我正在将recyclerview与sqlite数据库一起使用。现在我想添加搜索视图功能。
我想直接用光标过滤recylerview。我看到这个网站的很多帖子,但人们使用数组。
我读过它,更好的解决方案是从游标读取数据,然后使用cursorAdapter,然后更新屏幕。(不从游标读取数据,然后将其写入数组,然后使用数组适配器并将其打印在屏幕上(。
如果我理解得当的话。Searchview使用光标填充一个数组,然后在屏幕上打印结果。
那么,在不使用数组的情况下使用searchview是可能的吗?
我应该用filterable扩展我的适配器,还是在Mainactivity中使用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。
在onQueryTextChange中,每次用户在SearchView 中输入字符时都会调用
在那里,您可以过滤从数据库中获得的列表,并将过滤后的列表提交给您的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在以下代码行中发挥作用,是必要的
主要活动.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((;并将创建的搜索视图显示在其中的容器传递出去。在我的活动的Resume功能上,我附加了searchViewManager.setSearchItemClickListner(this(;因此,如果用户使用搜索视图进行搜索并点击项目,我的活动将触发事件,因为我实现了OnSearchItemClick
public class MainActivity extends AppCompatActivity implements OnSearchItemClick {
}
现在在清单文件中,我使用appId作为内容提供商的身份验证,因此它使searchview管理器具有可移植性,并且如果用户安装了多个包含相同搜索视图代码的应用程序,它将具有不同的签名。
// 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;
}
或者,您可以编写doc如何创建MsvAuthority.java,并对auth字符串进行硬编码,然后在需要的地方使用它,并在清单文件中使用相同的字符串,只需遵循doc的说明即可。
在这种情况下,它将像这个
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