-1

Adapter Class

Currently trying to implement a search for my recycler view. When i try running the searching i get an error of "E/RecyclerView: No adapter attached; skipping layout". I have tried using notifyDatasetChanged() but still not working. When I print the filtered list I can see it contains the correct amount of items it should return however it is not being updated. Thanks

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> implements Filterable {

        Context context;
         ArrayList<New> fullList;
        ArrayList<New> list;

        public RecyclerViewAdapter(Context context, ArrayList<New> fullList) {
            this.fullList = fullList;
            this.list  = new ArrayList<>(fullList);
            this.context = context;
        }

        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.rows, parent, false);
            ViewHolder viewHolder = new ViewHolder(view);
            return viewHolder;
        }

        @Override
        public void onBindViewHolder(ViewHolder holder, int position) {

            New studentDetails = fullList.get(position);
            holder.setTitle(studentDetails.getType().toString());

        }
        @Override
        public int getItemCount() {

            return fullList.size();
        }

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

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

                    for(New item: fullList)
                    {
                        if(item.getType().toString().toLowerCase().contains(filterPattern))
                        {
                            filteredList.add(item);
                        }
                    }
                }
                FilterResults results= new FilterResults();
                results.values = filteredList;
                System.out.println("filtered " + filteredList.toString());
                return results;
            }

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {

                list.clear();
                list.addAll((List)results.values);
                notifyDataSetChanged();
            }
        };

Fragment

@Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        super.onCreateOptionsMenu(menu, inflater);
        // Do something that differs the Activity's menu here
        MenuItem searchItem = menu.findItem(R.id.search);
        SearchView searchView = (SearchView)searchItem.getActionView();
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                return false;
            }
            @Override
            public boolean onQueryTextChange(String newText) {
                System.out.println("before" + list);
                adapter.getFilter().filter(newText);
                System.out.println("after" + list);
                return false;
            }

        });

    }
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        mView= inflater.inflate(R.layout.fragment_shown,container,false);
        myRecycler=(RecyclerView)mView.findViewById(R.id.recycler);
        myRecycler.setHasFixedSize(true);
        myRecycler.setLayoutManager(new LinearLayoutManager(getContext()));
        mDatabase = FirebaseDatabase.getInstance().getReference().child("Student");

        mDatabase.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot snapshot) {
                for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
                    New studentDetails = dataSnapshot.getValue(New.class);
                    Map<String, String> map = (Map) dataSnapshot.getValue();
                    String message = map.get("name");
                    if(message.equals("studentname"))
                    {
                        list.add(studentDetails);
                    }

                }

                adapter = new RecyclerViewAdapter(getActivity(), list);
                myRecycler.setAdapter(adapter);
                adapter.notifyDataSetChanged();

            }

            @Override
            public void onCancelled(DatabaseError databaseError) {



            }
        });

        return mView;
    }
M4rkus123
  • 5
  • 2
  • don't worry. It's just a warning. Because when rendering your recyclerview in onViewCreated, your fragment need you to set adapter immediatly but you set it in a callback – Slim_user71169 Feb 22 '20 at 04:06

1 Answers1

0

The issue is that you aren't creating an adapter until you get an update from the database. You should set the adapter outside of the listener, and updated it as needed:

 public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    mView= inflater.inflate(R.layout.fragment_shown,container,false);
    myRecycler=(RecyclerView)mView.findViewById(R.id.recycler);
    myRecycler.setHasFixedSize(true);
    myRecycler.setLayoutManager(new LinearLayoutManager(getContext()));

 //set your adapter when you create the view
 adapter = new RecyclerViewAdapter(getActivity(), list);
                myRecycler.setAdapter(adapter);
    mDatabase = FirebaseDatabase.getInstance().getReference().child("Student");

    mDatabase.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot snapshot) {
            for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
                New studentDetails = dataSnapshot.getValue(New.class);
                Map<String, String> map = (Map) dataSnapshot.getValue();
                String message = map.get("name");
                if(message.equals("studentname"))
                {
                    list.add(studentDetails);
                }

            }


            adapter.notifyDataSetChanged();

        }

        @Override
        public void onCancelled(DatabaseError databaseError) {



        }
    });

    return mView;
}

You will also need to update your data set. You can do something like this in your adapter class:

public void updateData(List<New> myData){
     list = myData; 
     notifyDataSetChanged()
}

Then instead of calling adapter.notifyDataSetChanged()you call adapter.updateData(list).

BlackHatSamurai
  • 23,275
  • 22
  • 95
  • 156