简体   繁体   中英

SearchView with RecyclerView (App closes when back to fragment which contains the recyclerview)

I have fragment contains Recyclerview and Searchview (in cardview not appbar), Regarding the search process, the application works normally, but the problem is When to go from this fragment that contains the recyclerview and back to it, the app closes.

Logcat:

java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.Object[] java.util.Collection.toArray()' on a null object reference
            at java.util.ArrayList.addAll(ArrayList.java:588)
            at com.quiltur.blocks.BlockListAdapter$3.publishResults(BlockListAdapter.java:174)
            

The Adapter:

public class BlockListAdapter extends RecyclerView.Adapter<BlockListAdapter.BlockViewHolder> implements Filterable {



    private FirebaseFirestore firebaseFirestore;
    private FirebaseAuth firebaseAuth;
    private String userId;
    public Context context;


    private List<BlockListModel> blockListModels;
    private List<BlockListModel> blockListModelsFull;
    private OnBlockListItemClicked onBlockListItemClicked;

    public BlockListAdapter(OnBlockListItemClicked onBlockListItemClicked) {
        this.onBlockListItemClicked = onBlockListItemClicked;
    }

    public void setBlockListModels(List<BlockListModel> blockListModels) {
        this.blockListModels = blockListModels;
        blockListModelsFull = new ArrayList<>(blockListModels);
    }

    @NonNull
    @Override
    public BlockViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.single_list_item, parent, false);
        context = parent.getContext();
        return new BlockViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull BlockViewHolder holder, int position) {
        holder.listTitle.setText(blockListModels.get(position).getName());
        String blockId = blockListModels.get(position).getBlock_id();
        String imageUrl = blockListModels.get(position).getImage();

        Shimmer shimmer = new Shimmer.ColorHighlightBuilder()
                .setDuration(1800) // how long the shimmering animation takes to do one full sweep
                .setBaseAlpha(0.9f) //the alpha of the underlying children
                .setHighlightAlpha(0.8f) // the shimmer alpha amount
                .setDirection(Shimmer.Direction.LEFT_TO_RIGHT)
                .setAutoStart(true)
                .setBaseColor(Color.WHITE)
                .build();

        ShimmerDrawable shimmerDrawable = new ShimmerDrawable();
        shimmerDrawable.setShimmer(shimmer);

        Glide   .with(holder.itemView.getContext())
                .load(imageUrl)
                .centerCrop()
                .placeholder(shimmerDrawable)
                .into(holder.listImage);


        firebaseFirestore = FirebaseFirestore.getInstance();
        firebaseAuth = FirebaseAuth.getInstance();
        userId = firebaseAuth.getCurrentUser().getUid();

        //Get Fav
        firebaseFirestore.collection("Users/" + userId + "/Favorites").document(blockId).addSnapshotListener(new EventListener<DocumentSnapshot>() {
            @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
            @Override
            public void onEvent(@Nullable DocumentSnapshot documentSnapshot, @Nullable FirebaseFirestoreException e) {

                if (documentSnapshot.exists()){
                    holder.listFav.setImageDrawable(context.getDrawable(R.drawable.fav_btn_full));
                }else {
                    holder.listFav.setImageDrawable(context.getDrawable(R.drawable.fav_btn_emp));
                }

            }
        });


        //Fav Feature
        holder.listFav.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                firebaseFirestore.collection("Users/" + userId + "/Favorites").document(blockId).get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
                    @Override
                    public void onComplete(@NonNull Task<DocumentSnapshot> task) {

                        if (!task.getResult().exists()){

                            Map<String,Object> favMap = new HashMap<>();
                            favMap.put("id", blockId);
                            firebaseFirestore.collection("Users/" + userId + "/Favorites").document(blockId).set(favMap);

                        }else {
                            firebaseFirestore.collection("Users/" + userId + "/Favorites").document(blockId).delete();
                        }
                    }
                });
            }
        });
    }

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

    @Override
    public Filter getFilter() {
        return blocksFilter;
    }

    private Filter blocksFilter = new Filter() {
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            List<BlockListModel> filteredList = new ArrayList<>();
            if (constraint == null || constraint.length() == 0) {
                filteredList.addAll(blockListModelsFull);
            }else {
                String filterPattern = constraint.toString().toLowerCase().trim();

                for (BlockListModel item : blockListModelsFull) {
                    if (item.getName().toLowerCase().contains(filterPattern)) {
                        filteredList.add(item);
                    }
                }
            }

            FilterResults results = new FilterResults();
            results.values = filteredList;
            results.count = filteredList.size();
            return results;
        }

        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
        blockListModels.clear();
        blockListModels.addAll((List) results.values);
        notifyDataSetChanged();
        }
    };

    public class BlockViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

        private ImageView listImage;
        private TextView listTitle;
        private ImageButton listFav;

        public BlockViewHolder(@NonNull View itemView) {
            super(itemView);

            listImage = itemView.findViewById(R.id.list_image);
            listTitle = itemView.findViewById(R.id.list_title);
            listFav = itemView.findViewById(R.id.favBtn);

            listTitle.setOnClickListener(this);
            listImage.setOnClickListener(this);

        }

        @Override
        public void onClick(View v) { onBlockListItemClicked.onItemClicked(getAdapterPosition());

        }
    }
        public interface OnBlockListItemClicked {
        void onItemClicked(int position);
    }
}

The search feature in the fragment:

searchView = view.findViewById(R.id.search_text);
        searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
        searchView.setQueryHint("Search");

        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {

                if(newText.length() > 0){
                    recoView.setVisibility(View.GONE);
                    recommended.setVisibility(View.GONE);

                }else {
                    recoView.setVisibility(View.VISIBLE);
                    recommended.setVisibility(View.VISIBLE);

                }
                adapter.getFilter().filter(newText);
                return false;
            }
        });

Note: I followed this lesson to add search to my app.

at java.util.ArrayList.addAll(ArrayList.java:588)
at com.quiltur.blocks.BlockListAdapter$3.publishResults(BlockListAdapter.java:174)

There is a problem in publishResults() that causes a NPE. I suspect that when you get back again from the fragment to the adapter the blockListModels gets a null value, not sure if there is something in the fragment getting it null; so as a start try to avoid calling methods on it before setting its value

I commented out the old code and added the new one.

    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {
       // blockListModels.clear();
       // blockListModels.addAll((List) results.values);

       blockListModels = (List<BlockListModel>) results.values;
       notifyDataSetChanged();
    }

UPDATE

When trying this code, the application does not closes, but two new problems arise. The first is when back to the fragment the recyclerview disappearance. and the second when searching, an imbalance occurs in the positions of recyclerview's items (In the old code this does not happen)

Now rollback the above mentioned trick to keep blockListModels not null, and set it intentionally inside the performFiltering

So the filter will be:

private Filter blocksFilter = new Filter() {
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            List<BlockListModel> filteredList = new ArrayList<>();
            if (constraint == null || constraint.length() == 0) {
                filteredList.addAll(blockListModelsFull);
            }else {
                String filterPattern = constraint.toString().toLowerCase().trim();

                for (BlockListModel item : blockListModelsFull) {
                    if (item.getName().toLowerCase().contains(filterPattern)) {
                        filteredList.add(item);
                    }
                }
        
            }

            // Setting the blockListModels
            blockListModels = filteredList; // <<< Here is the change 
        
            FilterResults results = new FilterResults();
            results.values = filteredList;
            results.count = filteredList.size();
            return results;
        }

        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            blockListModels.clear();
            blockListModels.addAll((List) results.values);
            notifyDataSetChanged();
        }
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM