如何从所有片段中使用工具栏中的 SearchView
Posted
技术标签:
【中文标题】如何从所有片段中使用工具栏中的 SearchView【英文标题】:How to use SearchView in Toolbar from all fragments 【发布时间】:2020-07-26 11:35:40 【问题描述】:我的应用程序有一个导航抽屉以及一个带有 2 个菜单项的工具栏。其中一项是 SearchView...
public boolean onCreateOptionsMenu(Menu menu)
方法放置在 MainActivity 中,并且从我的应用程序的所有片段中显然都可以看到 Toolbar。 为了让 SearchView 可以从所有片段中使用,我一直在使用这个可爱的方法:
public void onPrepareOptionsMenu(@NonNull Menu menu)
该方法基本上在我的应用程序的每个片段中,所有搜索逻辑在所有片段中重复,看起来像这样:
public class ChampagneFragment extends Fragment
private View champagneView;
private RecyclerView champagneList;
private ItemsAdapter itemsAdapter;
private List<NewModel> list;
private DatabaseOpenHelper databaseOpenHelper;
public ChampagneFragment()
// Required empty public constructor
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
setHasOptionsMenu(true);
// Inflate the layout for this fragment
champagneView = inflater.inflate(R.layout.fragment_champagne, container, false);
champagneList = champagneView.findViewById(R.id.champagneRVList);
champagneList.setLayoutManager(new LinearLayoutManager(getContext()));
return champagneView;
@Override
public void onStart()
super.onStart();
databaseOpenHelper = new DatabaseOpenHelper(getContext());
//Check exists database
File database = getContext().getDatabasePath(DatabaseOpenHelper.DBNAME);
if(false == database.exists())
databaseOpenHelper.getReadableDatabase();
//Copy db
if(copyDatabase(getContext()))
Toast.makeText(getContext(), "Copy database success", Toast.LENGTH_SHORT).show();
else
Toast.makeText(getContext(), "Copy data error", Toast.LENGTH_SHORT).show();
return;
//Get product list in db when db exists
list = databaseOpenHelper.getChampagne();
//Init adapter
itemsAdapter = new ItemsAdapter(getContext(), list);
//Set adapter for listview
champagneList.setAdapter(itemsAdapter);
// copy SQLite data
private boolean copyDatabase(Context context)
try
InputStream inputStream = context.getAssets().open(DatabaseOpenHelper.DBNAME);
String outFileName = DatabaseOpenHelper.DBLOCATION + DatabaseOpenHelper.DBNAME;
OutputStream outputStream = new FileOutputStream(outFileName);
byte[]buff = new byte[1024];
int length = 0;
while ((length = inputStream.read(buff)) > 0)
outputStream.write(buff, 0, length);
outputStream.flush();
outputStream.close();
Log.w("MainActivity","DB copied");
return true;
catch (Exception e)
e.printStackTrace();
return false;
//======================SEARCHING FUNCTIONALITY=========================
//fetching SearchView
@Override
public void onPrepareOptionsMenu(@NonNull Menu menu)
super.onPrepareOptionsMenu(menu);
MenuItem mSearchMenuItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) mSearchMenuItem.getActionView();
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener()
@Override
public boolean onQueryTextSubmit(String query)
return false;
@Override
public boolean onQueryTextChange(String newText)
// filtering data
if (newText != null && TextUtils.getTrimmedLength(newText) > 0)
newText = newText.toLowerCase();
List<NewModel> myList = new ArrayList<>();
for (NewModel newModel : list)
String title = newModel.getTitle().toLowerCase();
String description = newModel.getDescription().toLowerCase();
if (title.contains(newText) || description.contains(newText))
myList.add(newModel);
onSerach();
itemsAdapter.setFilter(myList);
else
list = databaseOpenHelper.getChampagne();
itemsAdapter = new ItemsAdapter(getContext(), list);
champagneList.setAdapter(itemsAdapter);
itemsAdapter.notifyDataSetChanged();
return true;
);
//getting data from search table in SQLite
public void onSerach()
databaseOpenHelper = new DatabaseOpenHelper(getContext());
//Check exists database
File database = getContext().getDatabasePath(DatabaseOpenHelper.DBNAME);
if(false == database.exists())
databaseOpenHelper.getReadableDatabase();
//Copy db
if(copyDatabase(getContext()))
Toast.makeText(getContext(), "Copy database success", Toast.LENGTH_SHORT).show();
else
Toast.makeText(getContext(), "Copy data error", Toast.LENGTH_SHORT).show();
return;
//Get product list in db when db exists
list = databaseOpenHelper.getSearch();
//Init adapter
itemsAdapter = new ItemsAdapter(getContext(), list);
//Set adapter for listview
champagneList.setAdapter(itemsAdapter);
首先我尝试过滤数据并将其显示在 MainActivty 的新列表中,但后来我无法使用片段中的 SearchView...所以过了一会儿,我决定这样做。但不知何故,对我来说,这似乎是一种不好的做法……你怎么看? 我怎么能以不同的方式做到这一点,这样我就没有很多重复的代码行并提高效率?
【问题讨论】:
几乎每次你在需要使用继承的类中有重复代码时 巴曼,谢谢!让我阅读有关继承的文档...老实说,对此一无所知!一开始我还是个初学者:) 但无论如何有用的信息,所以我知道要寻找什么! @Bahman,我正在阅读文档,我绝对理解使用继承的目的。但是,我仍然无法从基本片段中继承一些方法......在这种情况下,我想继承 onPrepareOptionsMenu() 和 onSearch() 方法......你有什么说明吗? @Bahman,非常感谢!你今天教会了我一些新东西!我已尽我所能尽可能有效地做到这一点。有时间就来看看吧! 【参考方案1】:/***
* Base class ChampagneBaseFragment extends Fragment
***/
public abstract class ChampagneBaseFragment extends Fragment
// here override any Fragment method that has same code in all childs
// here put variables used by methods of this class
// if you want to read or write to this variables in child class
// then you have to make them public or protected
public void onSerach()
// your onSearch code that is same in childs
@Override
public void onPrepareOptionsMenu(@NonNull Menu menu)
// your onPrepareOptionsMenu code that is same in childs
// other common functions...
/***
* Child class ChampagneFragment extends ChampagneBaseFragment
***/
public class ChampagneFragment extends ChampagneBaseFragment // extends ChampagneBaseFragment
// here you are using methods of ChampagneBaseFragment
// you can use them without changing them
// or you can override methods of ChampagneBaseFragment and call super to use them
// then add your code below super call
【讨论】:
【参考方案2】:实现后,这是我继承BasaFragment类的Fragment类
public class ChampagneFragment extends BaseFragment
private View champagneView;
private RecyclerView champagneList;
private ItemsAdapter itemsAdapter;
private List<NewModel> list;
private DatabaseOpenHelper databaseOpenHelper;
public ChampagneFragment()
// Required empty public constructor
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
setHasOptionsMenu(true);
// Inflate the layout for this fragment
champagneView = inflater.inflate(R.layout.fragment_champagne, container, false);
champagneList = champagneView.findViewById(R.id.champagneRVList);
champagneList.setLayoutManager(new LinearLayoutManager(getContext()));
databaseOpenHelper = new DatabaseOpenHelper(getContext());
//Get product list in db when db exists
list = databaseOpenHelper.getChampagne();
//Init adapter
itemsAdapter = new ItemsAdapter(getContext(), list);
//Set adapter for listview
champagneList.setAdapter(itemsAdapter);
return champagneView;
@Override
public void onPrepareOptionsMenu(@NonNull Menu menu)
super.onPrepareOptionsMenu(menu);
MenuItem mSearchMenuItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) mSearchMenuItem.getActionView();
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener()
@Override
public boolean onQueryTextSubmit(String query)
return false;
@Override
public boolean onQueryTextChange(String newText)
Toast.makeText(getContext(), "Hello", Toast.LENGTH_SHORT).show();
if (newText != null && TextUtils.getTrimmedLength(newText) > 0)
newText = newText.toLowerCase();
List<NewModel> myList = new ArrayList<>();
for (NewModel newModel : list)
String title = newModel.getTitle().toLowerCase();
String description = newModel.getDescription().toLowerCase();
if (title.contains(newText) || description.contains(newText))
myList.add(newModel);
onSerach();
itemsAdapter.setFilter(myList);
else
list = databaseOpenHelper.getChampagne();
itemsAdapter = new ItemsAdapter(getContext(), list);
champagneList.setAdapter(itemsAdapter);
itemsAdapter.notifyDataSetChanged();
return true;
);
@Override
public void onSerach()
super.onSerach();
list = databaseOpenHelper.getSearch();
itemsAdapter = new ItemsAdapter(getContext(), list);
champagneList.setAdapter(itemsAdapter);
还有继承自的类,BaseFragment 类
public abstract class BaseFragment extends Fragment
public DatabaseOpenHelper databaseOpenHelper;
public RecyclerView recyclerView;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
View view = inflater.inflate(R.layout.base_fragment, container, false);
databaseOpenHelper = new DatabaseOpenHelper(getContext());
//Check exists database
File database = getContext().getDatabasePath(DatabaseOpenHelper.DBNAME);
if(false == database.exists())
databaseOpenHelper.getReadableDatabase();
//Copy db
if(copyDatabase(getContext()))
Toast.makeText(getContext(), "Copy database succes", Toast.LENGTH_SHORT).show();
else
Toast.makeText(getContext(), "Copy data error", Toast.LENGTH_SHORT).show();
//return;
recyclerView = view.findViewById(R.id.baseFragmentRCV);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
return view;
public boolean copyDatabase(Context context)
try
InputStream inputStream = context.getAssets().open(DatabaseOpenHelper.DBNAME);
String outFileName = DatabaseOpenHelper.DBLOCATION + DatabaseOpenHelper.DBNAME;
OutputStream outputStream = new FileOutputStream(outFileName);
byte[]buff = new byte[1024];
int length = 0;
while ((length = inputStream.read(buff)) > 0)
outputStream.write(buff, 0, length);
outputStream.flush();
outputStream.close();
Log.w("MainActivity","DB copied");
return true;
catch (Exception e)
e.printStackTrace();
return false;
public void onSerach()
databaseOpenHelper = new DatabaseOpenHelper(getContext());
//Check exists database
File database = getContext().getDatabasePath(DatabaseOpenHelper.DBNAME);
if(false == database.exists())
databaseOpenHelper.getReadableDatabase();
//Copy db
if(copyDatabase(getContext()))
Toast.makeText(getContext(), "Copy database success", Toast.LENGTH_SHORT).show();
else
Toast.makeText(getContext(), "Copy data error", Toast.LENGTH_SHORT).show();
return;
所以我删除了 onStart() 方法并将这些代码行移到 onCreateView() 下面...检查数据是否存在的部分在 BaseFragment 类中,所以现在在我的片段中,我只是从数据库中获取产品列表因为每个片段都有自己的列表。对于 search() 方法,我也做了同样的事情。从 SQLite 数据库复制数据的方法已放在 BaseFragment 类中。我唯一无法完成的是 onPrepareOptionsMenu() 方法,我不知道为什么,但在这一行中 for (NewModel newModel : list) list 正在返回 null...
【讨论】:
以上是关于如何从所有片段中使用工具栏中的 SearchView的主要内容,如果未能解决你的问题,请参考以下文章
如何使用java将数据从片段传递到android中的另一个片段?