Search code examples
androidandroid-recyclerview

How do I update a RecyclerView on sorting the data?


My database (Firestore) stores Charts, created by Users.

On opening the app, the User is shown their own Charts, sorted by Chart Name (this is displayed in a Fragment called MyChartsFragment). They can click a button to change the sort field; this should retrieve the same list of Charts, but sorted by the selected field.

I'm able to pass the new sort field name into MyChartsFragment, but at that point the list of Charts goes blank. I assume I need to redraw it somehow.

The MyChartsFragment is as follows (I've removed most of the try-catch blocks, error checks etc, for clarity):

public class FragmentMyCharts extends FragmentChartsList {

    public FragmentMyCharts() {}

    public Query getQuery(FirebaseFirestore databaseReference, String orderBy) {
        // Specify the query which is used to retrieve this user's charts
        return databaseReference.collection("charts")
                .whereEqualTo("uid", getUid())
                .orderBy(orderBy);
    }
}

This extends FragmentChartsList, which contains:

public abstract class FragmentChartsList extends Fragment {

    private FirebaseFirestore mDatabaseRef;
    private FirestoreRecyclerAdapter<Chart, ChartViewHolder> mAdapter;
    private Query mChartsQuery;
    private RecyclerView mRecycler;
    private String mOrder = "name";

    FragmentManager mFragmentManager;
    ToolbarFragmentListCharts mFragmentTLC;

    public FragmentChartsList() {}

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);

        // Inflate layout, and find Recycler View to hold the list
        View rootView = inflater.inflate(
                R.layout.fragment_charts_list, container, false);

        mRecycler = rootView.findViewById(R.id.charts_list);
        mRecycler.setHasFixedSize(true);

        // Set up Layout Manager, and set Recycler View to use it
        LinearLayoutManager mManager = new LinearLayoutManager(getActivity());
        mManager.setReverseLayout(true);
        mManager.setStackFromEnd(true);
        mRecycler.setLayoutManager(mManager);

        // Connect to the database, and get the appropriate query
        mDatabaseRef = FirebaseFirestore.getInstance();
        mChartsQuery = getQuery(mDatabaseRef, mOrder);

        // Set up Recycler Adapter
        FirestoreRecyclerOptions<Chart> recyclerOptions = new FirestoreRecyclerOptions.Builder<Chart>()
                .setQuery(mChartsQuery, Chart.class)
                .build();

        mAdapter = new ChartListAdapter(recyclerOptions, this.getActivity());

        // Use Recycler Adapter in RecyclerView
        mRecycler.setAdapter(mAdapter);

        return rootView;
    }


    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        // Add listener to charts collection, and deal with any changes by re-showing the list
        mChartsQuery.addSnapshotListener(new EventListener<QuerySnapshot>() {
            @Override
            public void onEvent(@Nullable QuerySnapshot queryDocumentSnapshots,
                                @Nullable FirebaseFirestoreException e) {

                if (queryDocumentSnapshots != null && queryDocumentSnapshots.isEmpty()) {
                    ((MainActivity) Objects.requireNonNull(getActivity())).setPage(1);
                }

            }
        });
    }

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

    public void setOrderField(String order) {
        mOrder = order;
        mChartsQuery = getQuery(mDatabaseRef, mOrder);

        // Set up Recycler Adapter
        FirestoreRecyclerOptions<Chart> recyclerOptions = new FirestoreRecyclerOptions.Builder<Chart>()
                .setQuery(mChartsQuery, Chart.class)
                .build();

        mAdapter = new ChartListAdapter(recyclerOptions, this.getActivity());

        // Use Recycler Adapter in RecyclerView
        mRecycler.setAdapter(mAdapter);

    }

    public abstract Query getQuery(FirebaseFirestore databaseReference, String orderBy);

}

So, when the main activity is notified by the toolbar that the sort field has changed, it retrieves the MyChartsFragment (as a FragmentChartsList) and calls the setOrderField function:

public void setOrder(String order) {

        FragmentChartsList myCharts = (FragmentChartsList) mPagerAdapter.getItem(0);
        myCharts.setOrderField(order);

    }

This appears to update the value of mOrder correctly, but then it doesn't re-display the RecyclerView, so I just get a blank space.

What am I doing wrong?

EDITED TO ADD DETAIL:

My ChartListAdapter class is:

public class ChartListAdapter
        extends FirestoreRecyclerAdapter<Chart, ChartViewHolder> {

    private Activity mActivity;
    private FirestoreRecyclerOptions<Chart> recyclerOptions;

    public ChartListAdapter(FirestoreRecyclerOptions<Chart> recyclerOptions, Activity activity) {
        super(recyclerOptions);

        mActivity = activity;

    }

    @Override
    protected void onBindViewHolder(@NonNull ChartViewHolder holder, int position, @NonNull Chart model) {

        final String chartKey = this.getSnapshots().getSnapshot(position).getId();

        model.setKey(chartKey);

        // Set click listener for the chart
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(mActivity, ActivityViewChart.class);
                intent.putExtra("ChartKey", chartKey);
                mActivity.startActivity(intent);
            }
        });

        // Implement long-click menu
        mActivity.registerForContextMenu(holder.itemView);

        // Bind Chart to ViewHolder
        holder.bindToChart(model);
    }

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

        return new ChartViewHolder(view);
    }

    public void setRecyclerOptions(FirestoreRecyclerOptions<Chart> recyclerOptions) {
        this.recyclerOptions = recyclerOptions;
    }

}

Solution

  • Solved... in setOrderField I was declaring a new mAdapter, but not listening to it. Once I added

    mAdapter.startListening()

    it all worked fine!