6

Problem

I have a list of items that are displayed in android through a FirebaseRecyclerAdapter. I create this adapter with a database reference on all the list of items (let's say "posts"). The post displays also the category and if the user click on the category, I would like to update the list to display only items on that category.

Solution I tried that doesn't work I put a click listener on the "category" textview and when the user click on it I tried to instantiate a new adapter with the new database query but it doesn't work.

Other ideas: Do it outside the adpater: create a new Intent to relaunch the fragment and create a new adapter with the new query

Question Did someone deal with the same situation where on a user click you want to filter the original list of items retrieved by the adpater? What is the best solution?

Details

protected void populateViewHolder(final PostViewHolder viewHolder, final Post post, final int position) {


    /* Set the post text, author and category */
    viewHolder.postText.setText(post.getText());
    viewHolder.postAuthor.setText(post.getAuthor());
    viewHolder.postCategory.setText(post.getCategory());

    /* Set a listener on category so that 
      I refresh data with only that category */
    viewHolder.quoteCategory.setOnClickListener(new View.OnClickListener() {

        Post selectedPost = getItem(position);

        @Override
        public void onClick(View v) {

            String category = selectedPost.getCategory();

            // !!!! NOW I HAVE TO CHANGE DATA SET !!! ///

I think now I can create a new Fragment with a new adapter with correct Db reference... but is this the best way? Is there a way to use the same Adapater inside the populate view passing another query?

DavideN
  • 253
  • 2
  • 11

5 Answers5

2

You can use updateOptions(options) after building options with the new query.

updateOptions(newOptions)

A sample

fun changeQuery() {
        val newQuery = mBaseQuery
            .orderByChild("timestamp")
            .limitToLast(100)

        // Make new options
        val newOptions = FirebaseRecyclerOptions.Builder<Post>()
            .setQuery(newQuery, Post::class.java)
            .build()

        // Change options of adapter.
        mAdapter.updateOptions(newOptions)
    }

Reference

Arush Kharbanda
  • 141
  • 3
  • 11
1

Try calling .notifyDatasetChanged() on your adapter when the click occurs. After you have changed the dataset with the fresh firebase data.

Josef Korbel
  • 1,168
  • 1
  • 9
  • 32
  • Thank you for the answer, but the problem is not to notify a change in data set... the problem is how to change dataset once the adpater has already been created. "after you have changed the dataset" ... how can I do it? – DavideN Aug 05 '16 at 08:39
1

You do not change the query, you create a new adapter and query, replace the adapter in the recycler view, and clean up the old one.

Here is an example, "changing the query" based on a selection in a spinner:

   locationSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(final AdapterView<?> adapterView, final View view,
         final int i, final long l) {
            if (locationSpinner.getSelectedItem() != null) {
                final Location location = locationSpinner.getSelectedItem();
                final String indexString = String.format("open/%s/", location.getId());
                final Query query = FirebaseDatabase.getInstance()
                        .getReference("availabilities")
                        .orderByChild("statusLocationDateKey")
                        .startAt(indexString + "0") // simplified for example
                        .endAt(indexString + "9"); // simplified for example
                adapter = new ListingAdapter(query);
                final FirebaseRecyclerAdapter oldAdapter = 
                        (FirebaseRecyclerAdapter) listing.getAdapter();
                listing.setAdapter(adapter);
                if (oldAdapter != null) {
                    oldAdapter.cleanup();
                }
            }
        }

Note: ListingAdapter is a subclass of FirebaseRecyclerAdapter and listing is a RecyclerView.

Also be sure to include a null check in the on destroy for the activity or fragment, since with the code above, there is no guarantee that the adapter was ever initialized, for example:

@Override
public void onDestroyView() {
    if (adapter != null) {
        adapter.cleanup();
    }
    super.onDestroyView();
}
Tony BenBrahim
  • 7,040
  • 2
  • 36
  • 49
1

If you want to change database query after creation you need to stopListening to the adapter and then create new adapter with new query and startListening to adapter

Sample Code is below

FirebaseRecyclerAdapter fireBaseAdapter;
RecyclerView recyclerView;

 @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.your_layout, container, false);


locationSpinner.setOnItemSelectedListener(this);
Query query = databaseReference.child("yourChild").orderByChild("keyName");

    getDataFireBase(query);

    return view;
}

public void getDataFireBase(final Query query) {
    if (fireBaseAdapter!= null)
        fireBaseAdapter.stopListening();       


    FirebaseRecyclerOptions<YourModelClass> options = new FirebaseRecyclerOptions.Builder<YourModelClass>()
            .setQuery(query,YourModelClass.class)
            .build();

    fireBaseAdapter= new FirebaseRecyclerAdapter(options);
    recyclerView.setAdapter(fireBaseAdapter);
    fireBaseAdapter.startListening();
}



 @Override
    public void onItemSelected(final AdapterView<?> adapterView, final View view, final int i, final long l) {



Query query = databaseReference.child("yourChild").orderByChild("keyName"); // your new query

    getDataFireBase(query);




        }

 @Override
public void onStart() {
    super.onStart();
    fireBaseAdapter.startListening();
}

@Override
public void onStop() {
    super.onStop();
    fireBaseAdapter.stopListening();
}
Akshay n.s
  • 23
  • 5
0

Here is the code for update the firebase data. Here I update two parameters, that passed to function as title and body.

private void writeNewPost(String userId, String username, String title, String body) {

        String key = mDatabase.child("posts").push().getKey();
        Post post = new Post(userId, username, title, body);
        Map<String, Object> postValues = post.toMap();

        Map<String, Object> childUpdates = new HashMap<>();
        childUpdates.put("/posts/" + key, postValues);
        childUpdates.put("/user-posts/" + userId + "/" + key, postValues);

        mDatabase.updateChildren(childUpdates);
    }

I think this will helps you.

Shanto George
  • 994
  • 13
  • 26
  • thanks for the answer by I don't want to update/change data... I want to filter them differently in the UI. The solution I've found it's to create a new fragment and call it with a new firebaseadapter where I put as argument another firebase query in the constructor – DavideN Aug 05 '16 at 10:14