There is actually little to none resource for AsyncLayoutInflator in RecyclerView using Java, i actually had to write my own version of @Artem's answer in Java using few Kotlin resources available over the internet.
First we use a simple dummy view for recyclerview so that the recycleview loads quickly, and add the rest of the complicated view to the simpleview afterwards in background using asyncLayoutInflator.
The reason onBindExecutes executes quickly and you are unable to access the complicated layout is that the onCreate method creates only the dummy view, so when you try to access the complicated view it retunes a null exception as complicated views are yet to be generated. To overcome this, we pass the list to the class where the complicated views are being generated and update the view accordingly.
Below is the program on how its being implemented. My code maybe a little messy as im still learning, and can be improved further upon.
MyListData.Java
public class MyListData{
private String description;
private int imgId;
public MyListData(String description, int imgId) {
this.description = description;
this.imgId = imgId;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public int getImgId() {
return imgId;
}
public void setImgId(int imgId) {
this.imgId = imgId;
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyListData[] myListData = new MyListData[] {
new MyListData("Email", android.R.drawable.ic_dialog_email),
new MyListData("Info", android.R.drawable.ic_dialog_info),
new MyListData("Delete", android.R.drawable.ic_delete),
new MyListData("Dialer", android.R.drawable.ic_dialog_dialer),
new MyListData("Alert", android.R.drawable.ic_dialog_alert),
new MyListData("Map", android.R.drawable.ic_dialog_map),
new MyListData("Email", android.R.drawable.ic_dialog_email),
new MyListData("Info", android.R.drawable.ic_dialog_info),
new MyListData("Delete", android.R.drawable.ic_delete),
new MyListData("Dialer", android.R.drawable.ic_dialog_dialer),
new MyListData("Alert", android.R.drawable.ic_dialog_alert),
new MyListData("Map", android.R.drawable.ic_dialog_map),
};
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
MyListAdapter adapter = new MyListAdapter(myListData);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);
}
}
MyListAdapter
public class MyListAdapter extends ListAdapter<RecyclerView.ViewHolder> {
private MyListData[] listdata;
// RecyclerView recyclerView;
public MyListAdapter(MyListData[] listdata) {
this.listdata = listdata;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
DummyView dummyView= new DummyView(parent.getContext());
dummyView.inflate();
return new viewHolder(dummyView);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
setupDummyView(holder, position);
}
}
private void setupDummyView(RecyclerView.ViewHolder holder, int position) {
DummyView items = (DummyView) holder.itemView;
items.bindWhenInflated(items.textView, listdata[position]); - - - -> bindWhenInflated is a method in DummyViewClass which extends AsyncLayoutClass
}
@Override
public int getItemCount() {
return return listdata.length;
}
static class ListViewHolder extends RecyclerView.ViewHolder {
public ListViewHolder(ViewGroup view) {
super(view);
}
}
private static final class DummyView extends AsyncLayout {
public Context context;
MaterialTextView textView;
private final int layoutId = R.layout.datacolumn;
public DummyView(@NonNull Context context) {
super(context);
this.context = context;
}
public int getLayoutId() {
return this.layoutId;
}
@Override
public View getView(View view) {
textView = view.findViewById(R.id.dataText);
return super.getView(view);
}
public MaterialTextView getTextView() {
return textView;
}
}
}
AsyncLayout
public class AsyncLayout extends FrameLayout {
private final int layoutId;
private boolean isInflated = false;
private Context context;
private final List<MyListData>bindingfunction;
public AsyncLayout(Context context) {
super(context);
this.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
this.context = context;
layoutId = -1;
bindingfunction = new ArrayList<>();
}
public int getLayoutId() {
return layoutId;
}
public final void inflate() {
AsyncLayoutInflater asyncInflator = new AsyncLayoutInflater(context);
asyncInflator.inflate(this.getLayoutId(),this, (view, resid, parent) -> {
isInflated = true;
assert parent != null;
parent.addView(getView(view));
});
}
public View getView(View view) {
MaterialTextView textView = view.findViewById(R.id.listText);
for (MyListData data :bindingfunction
) {
textView.setText(data.getDescription());
}
return view;
}
public void bindWhenInflated(MaterialTextView textView, MyListData listData) {
if(isInflated){
textView.setText(listdata.getDescription());
}else{
bindingfunction.add(listData);
}
}
}
I like to conclude saying AsyncLayoutInflator should be used in limited circumstances as its improper implementation might result in unexpected UI behaviour.