Search code examples
androidandroid-recyclerviewretrofitretrofit2android-threading

How to use Two NotifyDataSetChanged() Atomically


To summarize my problem:

I have a list of items and a button that I click to query an API

When I click the button, two methods are called. The first method displays a progress bar, clears the list, and uses notifyDataSetChanged()

public void methodOne(){
      mProgressBar.setVisibility(View.VISIBLE);
      mList.clear;
      mAdapter.notifyDataSetChanged();
}

The second method uses retrofit to make a query, and in the callback method, I hide the progress bar, add to the list and call notifyDataSetChanged();

public void methodTwo(){
      RetrofitInterfaces.SearchForPosts service = RetrofitClientInstance.getRetrofitInstance()
                .create(RetrofitInterfaces.SearchForPosts.class);
        Call<Feed> call = service.listRepos(url);
        call.enqueue(new Callback<Feed>() {
            @Override
            public void onResponse(@NonNull Call<Feed> call, @NonNull Response<Feed> response) {
               
                try{

                   mProgressBar.setVisibility(View.INVISIBLE);
                   mList.addAll(response.body().getData()); 
                   mAdapter.notifyDataSetChanged();

                } catch(Exception e){
                   Log.e(TAG, "Error: " + e);
                }
                
            }

            @Override
            public void onFailure(@NonNull Call<Feed> call, @NonNull Throwable t) {
                Log.e(TAG, "onFailure: " + t);
     
            }
        });
    }

}

My problem is when I call these two ones after another:

methodOne();
methodTwo();

The second method with the retrofit call sometimes returns an IndexOutOfBounds exception because methodOne() calls mList.clear() and mAdapter.notifyDataSetChanged(); while I am making edits to mList.

My question is how can I make the two happen atomically so that they don't interfere with each other? (I want methodOne() to do everything even before the query happens in methodTwo)


Solution

  • You can use AsyncTask that will execute methodTwo() when methodOne() finished executing

    private class MethodsTask extends AsyncTask<Void, Void, Void> {
        @Override
        protected Void doInBackground(Void... voids) {
            methodOne();
            return null;
        }
    
        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
            methodTwo();
        }
    }
    

    So instead of calling the two methods

    methodOne();
    methodTwo();
    

    Use this

    MethodsTask task = new MethodsTask();
    task.execute();