【问题标题】:How to use SearchView in Toolbar from all fragments如何从所有片段中使用工具栏中的 SearchView
【发布时间】: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,非常感谢!你今天教会了我一些新东西!我已尽我所能尽可能有效地做到这一点。有时间就来看看吧!

标签: android sqlite android-fragments


【解决方案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...

    【讨论】:

      猜你喜欢
      • 2015-10-29
      • 1970-01-01
      • 2015-02-07
      • 1970-01-01
      • 2015-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多