androidandroid-fragmentsandroid-recyclerviewsearchview

SearchView on RecylerView in a Fragment


I've been working on a SearchView and I have failed miserably. When I type something on it, nothing happens and it does not filter the list. I have provided my fragment and my adapter below. Please help! Thanks!

Additional Question: After I type something in the searchview, and if I tap the back button, I want the keyboard to hide and to return the title of my fragment. How should i do this?

Fragment

public class RecentNewsFragment extends Fragment implements ConnectivityReceiver.ConnectivityReceiverListener, SearchView.OnQueryTextListener {

    public RecentNewsFragment() {

    }

    final String TAG = "MainPageActivity";
    ArrayList<News> newsList;
    public RecyclerView rvNewsArticle;
    public NewsArticleAdapter adapter;
    public SwipeRefreshLayout swipeRefreshLayout;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        View view =  inflater.inflate(R.layout.fragment_recent_news, container, false);

        checkConnection();

        rvNewsArticle = (RecyclerView) view.findViewById(R.id.rvNewsArticle);
        rvNewsArticle.setHasFixedSize(true);
        final LinearLayoutManager manager = new LinearLayoutManager(getActivity());
        rvNewsArticle.setLayoutManager(manager);

        swipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipeRefresh);
        swipeRefreshLayout.setColorSchemeResources(R.color.primaryColor, R.color.primaryTextColor, R.color.secondaryColor);
        swipeRefreshLayout.setSize(SwipeRefreshLayout.LARGE);
        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        loadNews();
                    }
                }, 1000);
            }
        });

        return view;
    }

    private void loadNews() {
        String ip = IPAddress.ipaddress;
        String url = "http://" + ip + "/theflare/app/news.php";
        StringRequest stringRequest = new StringRequest(Request.Method.GET,
                url,
                new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                        Log.d(TAG, response);

                        newsList = new JsonConverter<News>()
                                .toArrayList(response, News.class);
                        adapter = new NewsArticleAdapter(getActivity(), newsList);
                        rvNewsArticle.setAdapter(adapter);

                        swipeRefreshLayout.setRefreshing(false);

                        FileCacher<ArrayList<News>> newsCacher = new FileCacher<>(getActivity(), "theflarenewscache.txt");
                        try {
                            newsCacher.appendOrWriteCache(newsList);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        if (error != null) {
                            Snackbar snackbar = Snackbar
                                    .make(getActivity().findViewById(android.R.id.content), "Something went wrong.", Snackbar.LENGTH_INDEFINITE)
                                    .setAction("Retry", new View.OnClickListener() {
                                        @Override
                                        public void onClick(View view) {
                                            loadNews();
                                        }
                                    });
                            View sbView = snackbar.getView();
                            sbView.setBackgroundColor(ContextCompat.getColor(getActivity(), R.color.maroon));
                            snackbar.show();
                        }
                    }
                }
        );

        MySingleton.getInstance(getActivity()).addToRequestQueue(stringRequest);
    }

    private void loadCachedNews() {
        FileCacher<ArrayList<News>> newsCacher = new FileCacher<>(getActivity(), "theflarenewscache.txt");
            if(newsCacher.hasCache()){
                try {
                    ArrayList<News> cachedNewsList = newsCacher.readCache();
                    final NewsArticleAdapter adapter = new NewsArticleAdapter(getActivity(), cachedNewsList);
                    //rvNewsArticle.setAdapter(adapter);
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (ClassCastException e){
                    e.printStackTrace();
                }
            }
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        // Inflate the menu; this adds items to the action bar if it is present.
        inflater.inflate(R.menu.main_page, menu);
        // Associate searchable configuration with the SearchView
        final MenuItem searchItem = menu.findItem(R.id.action_search);
        final SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
        searchView.setOnQueryTextListener(this);

        MenuItemCompat.setOnActionExpandListener(searchItem, new MenuItemCompat.OnActionExpandListener() {
                    @Override
                    public boolean onMenuItemActionCollapse(MenuItem item) {
                    // Do something when collapsed
                        adapter.setFilter(newsList);
                        return true; // Return true to collapse action view
                    }

                    @Override
                    public boolean onMenuItemActionExpand(MenuItem item) {
                        // Do something when expanded
                        return true; // Return true to expand action view
                    }
                });

        super.onCreateOptionsMenu(menu, inflater);
    }

    @Override
    public boolean onQueryTextSubmit(String query) {
        if (adapter != null) {

            query = String.valueOf(query.equals(""));
        }
        return true;
    }

    @Override
    public boolean onQueryTextChange(String newText) {
        newText = newText.toLowerCase();
        final ArrayList<News> filteredNewsList = new ArrayList<>();
        for (News model : newsList) {
            final String title = model.getTitle().toLowerCase();
            final String author = model.getAuthor().toLowerCase();
            final String category = model.getCategory().toLowerCase();
            final String content = model.getContent().toLowerCase();
            if ((title.contains(newText)) || (author.contains(newText)) || (category.contains(newText)) || (content.contains(newText))) {
                filteredNewsList.add(model);
            }
        }
        adapter.setFilter(filteredNewsList);
        return true;
    }

    // Method to manually check connection status
    private void checkConnection() {
        boolean isConnected = isConnected();
        snackInternet(isConnected);
    }

    private void snackInternet(boolean isConnected) {
      if (isConnected) {
          Snackbar snackbar = Snackbar.make(getActivity().findViewById(android.R.id.content), "Connected to the Internet!", Snackbar.LENGTH_SHORT);
          View sbView = snackbar.getView();
          sbView.setBackgroundColor(ContextCompat.getColor(getActivity(), R.color.primaryDarkColor));
          snackbar.show();
          loadNews();
      }
      else {
          Snackbar snackbar = Snackbar
                  .make(getActivity().findViewById(android.R.id.content), "You seem to be offline.", Snackbar.LENGTH_INDEFINITE)
                  .setAction("Retry", new View.OnClickListener() {
                      @Override
                      public void onClick(View view) {
                          loadNews();
                      }
                  });
          View sbView = snackbar.getView();
          sbView.setBackgroundColor(ContextCompat.getColor(getActivity(), R.color.maroon));
          snackbar.show();
          loadCachedNews();
      }
    }

    @Override
    public void onResume() {
        super.onResume();

        // register connection status listener
        TheFlare.getInstance().setConnectivityListener(this);
    }

    /**
     * Callback will be triggered when there is change in
     * network connection
     */
    @Override
    public void onNetworkConnectionChanged(boolean isConnected) {
        snackInternet(isConnected);
    }

}

Adapter

public class NewsArticleAdapter extends RecyclerView.Adapter<NewsArticleAdapter.NewsViewHolder> {

    private Context context;
    private ArrayList<News> newsList;

    public NewsArticleAdapter(Context context, ArrayList<News> newsList){
        this.context = context;
        this.newsList = newsList;
    }

    @Override
    public NewsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        View view = inflater.from(parent.getContext())
                .inflate(R.layout.news_cardview_layout, parent, false);

        NewsViewHolder newsViewHolder = new NewsViewHolder(view);
        return newsViewHolder;
    }

    @Override
    public void onBindViewHolder(NewsViewHolder holder, int position) {
        final News selectedNews = newsList.get(position);
        holder.tvId.setText(String.valueOf(selectedNews.id));
        holder.tvTitle.setText(selectedNews.title);
        holder.tvPubDate.setText("" + selectedNews.publicationDate);

        String ip = IPAddress.ipaddress;
        String fullUrl = "http://" + ip + "/theflare/admin/img/newsbanner/" + selectedNews.imgBanner;

        Picasso.with(context)
                .load(fullUrl)
                .placeholder(R.drawable.bannerplaceholder)
                .error(android.R.drawable.stat_notify_error)
                .into(holder.ivImage);

        holder.ivImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick (View view) {
                Intent intent = new Intent(context, NewsDetailActivity.class);
                intent.putExtra("newsList", selectedNews);
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                context.startActivity(intent);
            }
        });

    }

    @Override
    public int getItemCount() {
        if(newsList != null){
            return newsList.size();
        }
        return 0;
    }

    public void setFilter(ArrayList<News> newsArrayList) {
        newsList.clear();
        newsList.addAll(newsArrayList);
        notifyDataSetChanged();
    }

    //ViewHolder class
    public static class NewsViewHolder extends RecyclerView.ViewHolder{

        public CardView cvNews;
        public TextView tvId;
        public ImageView ivImage;
        public TextView tvTitle;
        public TextView tvPubDate;

        public NewsViewHolder(View itemView) {
            super(itemView);
            cvNews = (CardView)itemView.findViewById(R.id.cvNews);
            tvId = (TextView) itemView.findViewById(R.id.tvId);
            ivImage = (ImageView)itemView.findViewById(R.id.ivImageUrl);
            tvTitle = (TextView)itemView.findViewById(R.id.tvTitle);
            tvPubDate = (TextView)itemView.findViewById(R.id.tvPubDate);

        }
    }
}

Solution

  • Solved it! Had to insert some codes and it finally worked! Here is what I have done:

    In my MainActivity, I had to change my onCreateOptions method to this:

    @Override
        public boolean onCreateOptionsMenu(Menu menu) {
    
            return true;
        }
    

    Then in my fragment's onCreateView method:

    setHasOptionsMenu(true);
    

    I also had to implement the listeners for searchview and menuitem:

    public class RecentNewsFragment extends Fragment implements SearchView.OnQueryTextListener, MenuItem.OnActionExpandListener
    

    Afterwards, I implement these methods:

        @Override
        public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
            // Inflate the menu; this adds items to the action bar if it is present.
            inflater.inflate(R.menu.search_menu, menu);
            // Associate searchable configuration with the SearchView
            final MenuItem searchItem = menu.findItem(R.id.action_search);
            MenuItemCompat.setShowAsAction(searchItem, MenuItemCompat.SHOW_AS_ACTION_ALWAYS | MenuItemCompat.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
            final SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
            searchView.setOnQueryTextListener(this);
    
            super.onCreateOptionsMenu(menu, inflater);
        }
    
        @Override
        public boolean onQueryTextSubmit(String query) {
            return true;
        }
    
        @Override
        public boolean onQueryTextChange(String newText) {
            if (newText == null || newText.trim().isEmpty()) {
                adapter.setFilter(newsList);
                return false;
            }
            newText = newText.toLowerCase();
            final ArrayList<News> filteredNewsList = new ArrayList<>();
            for (News model : newsList) {
                final String title = model.getTitle().toLowerCase();
                final String author = model.getAuthor().toLowerCase();
                final String category = model.getCategory().toLowerCase();
                final String content = model.getContent().toLowerCase();
                if ((title.contains(newText)) || (author.contains(newText)) || (category.contains(newText)) || (content.contains(newText))) {
                    filteredNewsList.add(model);
                }
            }
            adapter.setFilter(filteredNewsList);
            return true;
        }
    
    @Override
        public boolean onMenuItemActionExpand(MenuItem item) {
            return true;
        }
    
        @Override
        public boolean onMenuItemActionCollapse(MenuItem item) {
            adapter.setFilter(newsList);
            return true;
        }
    

    Finally, in my adapter:

    public void setFilter(ArrayList<News> newsArrayList) {
            news.clear();
            news.addAll(newsArrayList);
            notifyDataSetChanged();
        }