Как использовать SearchView в панели инструментов из всех фрагментов - PullRequest
0 голосов
/ 13 апреля 2020

Мое приложение имеет панель навигации, а также панель инструментов с 2 пунктами меню. Одним из элементов является метод SearchView ...

public boolean onCreateOptionsMenu(Menu menu)

, помещенный в MainActivity, и панель инструментов, видимо, видна из всех фрагментов моего приложения. Чтобы сделать SearchView пригодным для использования из всех фрагментов, которые я использовал, этот прекрасный метод:

public void onPrepareOptionsMenu(@NonNull Menu menu)

Этот метод в основном присутствует в каждом отдельном фрагменте моего приложения, и все логи поиска c повторяются во всех фрагменты, и это выглядит так:

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 из фрагменты ... Итак, через некоторое время я решил сделать это таким образом. Но как-то для меня это кажется плохой практикой ... Что ты думаешь? Как я могу сделать это по-другому, чтобы у меня не было много повторяющихся строк кода и чтобы сделать его более эффективным?

Ответы [ 2 ]

0 голосов
/ 14 апреля 2020

После реализации это мой класс Fragment, который наследует класс BasaFragment

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 (), я не знаю почему, но в этой строке для списка (NewModel newModel: list) возвращался нуль ...

0 голосов
/ 14 апреля 2020
/***
 * 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


}
...