我正在使用带有 sqlite 数据库的 recyclerview。现在我想添加搜索视图功能。
我想直接用光标过滤recylerview。我看到这个网站的很多帖子,但人们使用数组。
我读到了它,更好的解决方案是从游标读取数据,然后使用 cursorAdapter 然后更新屏幕。 (不从光标读取数据,然后将其写入数组,然后使用数组适配器并将其打印在屏幕上)。
如果我理解正确的话。 Searchview 使用光标然后填充一个数组,然后在屏幕上打印结果。
所以不使用数组也可以使用searchview?
我应该在 Mainactivity 中使用 filterable 扩展我的适配器还是使用 textwatcher?
有人能给我解释一下吗?
编辑
我的代码:
Edit_delete_product
:
public class Edit_Delete_Product extends AppCompatActivity implements DataBase_helper_interface {
private RecyclerView recyclerView;
private Recycler_Adapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
DataBase_Helper myDatabase;
SQLiteDatabase db;
public Cursor cursor3;
long cursor_pos;
Intent next_activity;
SearchView searchView;
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit__delete__product);
myDatabase = new DataBase_Helper(this);
db = myDatabase.getWritableDatabase();
build_RecyclerView();
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
// Some solutions I tried
// 1
mAdapter = new Recycler_Adapter(getApplicationContext(),cursor1);
mAdapter.notifyDataSetChanged();
//2
mAdapter.swapCursor(searchdata(newText));
mAdapter.notifyDataSetChanged();
// searchdata(newText);
Log.i("Tag2", String.valueOf(searchdata(newText)));
//3
mAdapter.getFilter().filter(newText);
//return false;
//4
mAdapter.filter(newText);
return true;
}
});
mAdapter.setOnItemClickListener(new Recycler_Adapter.ClickListener() {
@Override
public void onItemClick(View itemview) {
cursor_pos = (long) itemview.getTag();
next_activity = new Intent(itemview.getContext(), Product_specific_detail.class);
next_activity.putExtra("key", cursor_pos);
startActivity(next_activity);
}
});
}
@Override
protected void onResume(){
super.onResume();
mAdapter.swapCursor(getAllItems());
}
public void build_RecyclerView(){
recyclerView = findViewById(R.id.recycler_edit_del_product);
recyclerView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
mAdapter = new Recycler_Adapter(this, getAllItems());
recyclerView.setAdapter(mAdapter);
searchView = findViewById(R.id.search_view_edit_delete_product);
}
private Cursor getAllItems() {
return db.query(Table_Name,null,null,null,null,null,null);
}
private Cursor searchdata(String text) {
//1 solution
/* return db.query(Table_Name, null, NAME_PRODUCT, new String[]{text}, null, null, null);
}*/
//2
cursor1 = db.query( Table_Name, new String[] { NAME_PRODUCT}, NAME_PRODUCT + " LIKE ?",
new String[] { text }, null, null, null,
null);
if(cursor1 != null){
cursor1.moveToFirst();
}
return cursor1;
}
}
适配器:
public class Recycler_Adapter extends RecyclerView.Adapter<Recycler_Adapter.recyclerViewHolder> implements DataBase_helper_interface, Filterable {
private Context context;
private Cursor cursor;
private ClickListener clickListener;
ArrayList<Cursor> awad = new ArrayList<>();
String product_name;
long id;
public interface ClickListener {
void onItemClick(View itemview);
}
public void setOnItemClickListener(ClickListener mclickListener) {
clickListener = mclickListener;
}
public static class recyclerViewHolder extends RecyclerView.ViewHolder {
public ImageView mImageView1;
public TextView mTextView1;
public recyclerViewHolder(final View itemView, final ClickListener listener) {
super(itemView);
mImageView1 = itemView.findViewById(R.id.rec_image);
mTextView1 = itemView.findViewById(R.id.rec_text_1);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listener != null) {
int position = getLayoutPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onItemClick(itemView);
}
}
}
});
}
}
public Recycler_Adapter(Context mConext, Cursor mCursor) {
context = mConext;
cursor = mCursor;
}
@NonNull
@Override
public recyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_template, parent, false);
recyclerViewHolder recViewHold = new recyclerViewHolder(v, clickListener);
return recViewHold;
}
@Override
public void onBindViewHolder(@NonNull recyclerViewHolder holder, int position) {
if (!cursor.moveToPosition(position)) {
return;
}
product_name = cursor.getString(cursor.getColumnIndex(NAME_PRODUCT));
holder.mTextView1.setText(product_name);
id = cursor.getLong(cursor.getColumnIndex(_ID));
holder.itemView.setTag(id);
}
@Override
public int getItemCount() {
return cursor.getCount();
}
public void swapCursor(Cursor newCursor) {
if (cursor != null) {
cursor.close();
}
cursor = newCursor;
if (newCursor != null) {
notifyDataSetChanged();
}
}
public void filter(String text) {
// unfortunately delete content from here. Maybe here I should have filter method without implementing filterable?
}
@Override
public Filter getFilter() {
return simpleFilter;
}
private Filter simpleFilter = new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
if (product_name.toLowerCase().trim().contains(constraint)) {
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
awad.add(cursor);
//I thought about adding "matching" cursors to array and show this array in recycclerview or if
// it is empty show all data like at the beginning.
}
}
FilterResults results = new FilterResults();
results.values = awad;
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
awad.clear();
awad.addAll((ArrayList) results.values);
Log.i("TAG", product_name);
notifyDataSetChanged();
}
};
}
}
数据库助手:
public class DataBase_Helper extends SQLiteOpenHelper implements DataBase_helper_interface {
SQLiteDatabase db;
DataBase_Helper myDatabase;
Cursor cursor;
public DataBase_Helper(Context context) {
super(context, Data_Base_Name, null, Data_Base_Version);
db = this.getWritableDatabase();
}
@Override
public void onCreate(SQLiteDatabase db) {
String query = "CREATE TABLE " + Table_Name + " (" + _ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + DataBase_helper_interface.NAME_PRODUCT + " TEXT);";
db.execSQL(query);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + Table_Name);
onCreate(db);
}
}
界面:
public interface DataBase_helper_interface extends BaseColumns {
public static final String Data_Base_Name = "database_name";
public static final int Data_Base_Version = 1;
public static final String Table_Name = "table";
public static final String NAME_PRODUCT = "name_product";
}
简短的 xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Edit_Delete_Product"
android:orientation="vertical"
android:weightSum="10"
>
<SearchView
android:id="@+id/search_view_edit_delete_product"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
/>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="9"
android:background="@android:color/holo_green_dark"
>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_edit_del_product"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/holo_orange_dark"
android:paddingStart="4dp"
android:paddingEnd="4dp"
android:scrollbars="vertical"
android:paddingBottom="55dp"
/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</androidx.appcompat.widget.LinearLayoutCompat>
清单的简短版本:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.things">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<provider
android:name="br.com.mauker.materialsearchview.db.HistoryProvider"
android:authorities="br.com.mauker.materialsearchview.searchhistorydatabase"
android:exported="false"
android:protectionLevel="signature"
android:syncable="true" />
<activity
android:name=".Edit_Delete_Product"
android:label="@string/toolbar_edit_del_pr" />
<activity
android:name=".Add_Product"
android:label="@string/action_bar_name_add" />
<activity
android:name=".MainActivity"
android:label="@string/action_bar_name_main"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
在 SearchView 上设置一个 OnQueryTextListener。
每次用户在 SearchView 中输入一个字符时都会调用 onQueryTextChange
在那里您可以过滤从数据库中获得的列表,并将过滤后的列表提交给您的 recyclerView 适配器。
像这样。示例在 Kotlin 中。
searchView.setOnQueryTextListener(object: SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
return false
}
override fun onQueryTextChange(newText: String?): Boolean {
//perform your filtering here
return false
}
})
我在各种项目中集成了以下搜索视图。你需要的都在那里。
https://github.com/Mauker1/MaterialSearchView
我的项目之一:
https://bitbucket.org/codesteam/news_template/src/master/
让我们先了解它是如何工作的,然后您可以通过下载源代码或仅使用 Gradle 依赖项以自己的方式编写。
从我给定的项目中,我首先下载了源代码并将所有文件放在路径中:
/app/src/main/java/com/materialsearchview
让我们从 SearchViewManager 开始它是一个包含 MaterialSearchView 实例的文件,因此通过从任何活动创建 SearchViewManager 实例,我可以实例化搜索视图并访问它的公共成员,这样我就可以做我需要做的事情。例如,我在我的 MainActivity 中使用它,要使 SearchViewManager 发挥作用,下面的代码行是必要的
MainActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
searchViewManager = SearchViewManager.getInstance(this);
searchViewManager.create();
searchViewManager.addParrent((ViewGroup) findViewById(R.id.searchViewContainer));
}
protected void onResume() {
super.onResume();
searchViewManager.addParrent(searchViewContainer);
searchViewManager.setSearchItemClickListner(this);
searchViewManager.getSearchView().activityResumed();
}
@Override
protected void onPause() {
searchViewManager.removeParrent();
}
@Override
protected void onDestroy() {
searchViewManager.getSearchView().clearSuggestions();
}
@Override
public void onBackPressed() {
if (searchViewManager.getSearchView().isOpen()) {
// Close the search on the back button press.
searchViewManager.getSearchView().closeSearch();
} else {
super.onBackPressed();
}
}
@Override
public void onClick(SearchItem searchItem) {
if (searchItem != null){
}
}
现在在 activity_main.xml 中,我在下面的容器中注入了使用 SearchViewManager 创建的搜索视图
<LinearLayout
android:id="@+id/searchViewContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
</LinearLayout>
再次,我在活动的 onCreate 函数中创建了一个 SearchViewManager 实例,然后调用 searchViewManager.create();创建 MaterialSearchView 然后我调用 searchViewManager.addParrent((ViewGroup) findViewById(R.id.searchViewContainer));并将容器传递到将显示创建的搜索视图的位置。和我的活动的 onResume 功能我附加了 searchViewManager.setSearchItemClickListner(this);因此,如果用户使用搜索视图进行搜索并单击某个项目,我的活动将触发一个事件,因为我实施了 OnSearchItemClick
public class MainActivity extends AppCompatActivity implements OnSearchItemClick {
}
现在在清单文件中,我使用 appId 对内容提供者进行身份验证,因此它使搜索视图管理器可移植,如果用户安装了多个包含相同搜索视图代码的应用程序,它将具有不同的签名。
// in mainifest file
<provider
android:name="com.materialsearchview.db.HistoryProvider"
android:authorities="${applicationId}.searchhistorydatabase"
android:exported="false"
android:protectionLevel="signature"
android:syncable="true"/>
// in HistoryContract.java
private static String initAuthority() {
String authority = BuildConfig.APPLICATION_ID+".searchhistorydatabase";
return authority;
}
或者您可以编写文档如何创建 MsvAuthority.java 并对 auth 字符串进行硬编码并在需要的地方使用它并在清单文件中使用相同的字符串,只需按照文档的说明进行操作。
那样的话,就变成这样了
public class MsvAuthority {
public static final String CONTENT_AUTHORITY = "com.myapp.searchhistorydatabase";
}
public class HistoryContract {
public static final String CONTENT_AUTHORITY = MsvAuthority.CONTENT_AUTHORITY;
}
<provider
android:name="com.materialsearchview.db.HistoryProvider"
android:authorities="com.myapp.searchhistorydatabase.searchhistorydatabase"
android:exported="false"
android:protectionLevel="signature"
android:syncable="true"/>
现在,给你的建议:我在为整个项目编码时编写并更新了这个搜索视图代码,所以首先要清楚地了解他们在说什么(gitHub readme.md)然后理解我的概念我是如何实现它的我自己的需求,然后开始编写一个小项目,您将在其中使用最少的代码成功实现搜索视图。
如果你喜欢搜索视图管理器的概念然后开始以你自己的方式实现它,你可以通过查看我的代码来获得帮助。
如果您有任何问题,请随时问我,我会协助您,直到您成功完成搜索视图:D