1

My question is, is the initialization of a new RecyclerView adapter an asynchronous call?

I have an adapter that I am creating:

mRecyclerAdapter = new TestAdapter(mContext, mListImages);
mRecycler.setLayoutManager(mLayoutManager);
mRecycler.setAdapter(mRecyclerAdapter);

After initializing it, I can call .add() directly after these methods without calling .notifyDataSetChanged() and they would still be added to my adapter, and displayed.

mRecyclerAdapter = new TestAdapter(mContext, mListImages);
mRecycler.setLayoutManager(mLayoutManager);
mRecycler.setAdapter(mRecyclerAdapter);

mListImages.add( . . .);
mListImages.add( . . .);
mListImages.add( . . .);

Are RecyclerView adapters automatically initialized on a background thread?

Here is my adapter:

public class SelectBucketAdapter extends RecyclerView.Adapter<SelectBucketAdapter.ViewHolder> {

    private static final String TAG = "SelectBucketAdapter";

    private Context mContext;
    private ArrayList<String> mBucketList;

    public SelectBucketAdapter(Context mContext, ArrayList<String> mBucketList,
                               ) {
        this.mContext = mContext;
        this.mBucketList = mBucketList;

    }

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

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int i) {
        ... binding views
    }

    @Override
    public int getItemCount() {
        return mBucketList.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder{

        @BindView(R.id.vh_selectbucketmenu_name)
        TextView vhBucketName;


        int mPosition;
        public ViewHolder(@NonNull View itemView) {
            super(itemView);

        }


    }
}
azizbekian
  • 60,783
  • 13
  • 169
  • 249
DIRTY DAVE
  • 2,523
  • 2
  • 20
  • 83

2 Answers2

2

Are RecyclerView adapters automatically initialized on a background thread?

No, they are not.

Is the initialization of a new RecyclerView adapter an asynchronous call?

No, it is not.

The layout creation and attachment to window is async.

What this means?

Assume we have following code:

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  ...

  val adapter = MyAdapter()
  recyclerView.adapter = adapter

  adapter.list.add("1")
}

In this case we will see the "1" being displayed on the screen, because at the point when adapter.list.add("1") was executed RecyclerView hasn't yet passed through its measure-layout-draw cycle.

Now let's consider following code:

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  ...

  val adapter = MyAdapter()
  recyclerView.adapter = adapter

  Handler().postDelayed({ adapter.list.add("AAA") }, 2000)
}

In this case adapter.list.add("AAA") will be executed in roughly 2 seconds. As long as RecyclerView will already be laid out by that time, then mutating the adapter dataset won't make the RecyclerView show the item, because RecyclerView doesn't know if dataset has suffered a change.

Let's consider following case:

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  ...

  val adapter = MyAdapter()
  recyclerView.adapter = adapter

  recyclerView.doOnPreDraw { adapter.list.add("preDraw") }
  recyclerView.doOnLayout { adapter.list.add("layout") }
  adapter.list.add("onCreate")
}

In this case still only "onCreate" will be displayed on screen.

To sum up: as soon as RecyclerView has passed its measure step (i.e. View#onMeasure) then mutating adapter won't be reflected unless adapter explicitly notifies RecyclerView.

azizbekian
  • 60,783
  • 13
  • 169
  • 249
1

The term 'intiializing' is quite ambiguous. At what point do you consider the adapter 'intiialized'?. To me, an Adapter can be intiialized with 0 items. So you can't really measure whether the Adapter has been intiialized by looking at the contents of the RecyclerView.

Secondly, you're asking if 'intiializing is an asynchronous call'. The 'initialization' of a RecyclerView Adapter is a whole bunch of calls. What you've observed is that the result of these calls is not always immediately visible - which tells you that at least some of what is happening behind the scenes is asynchronous.

I think what you're trying to ask is 'at what point in the lifecycle of a RecyclerView are you required to notify the Adapter of changes'. And it sounds like the answer is 'once the RecyclerView has reached onMeasure() (based on @azizbekian's answer).

If you want to add items to the Adapter without having to call notifyDataSetChanged(), then I would suggest adding them before calling RecyclerView.setAdapter(). Once you've set the Adapter, any further changes you make to the Adapter's dataset should be followed with a notifyDataSetChanged() call (or preferably, one of the more specific notifyX() calls).

Tim Malseed
  • 6,003
  • 6
  • 48
  • 66