异步布局填充RecyclerView

7

我正在单个屏幕上使用两个RecyclerView(适用于Android TV)。每个RecyclerView都有复杂的布局项。加载需要一些时间。我在活动中使用了asynclayoutinflator。

    AsyncLayoutInflater inflater = new AsyncLayoutInflater(this);
    inflater.inflate(R.layout.main, null, callback);

我想知道是否有任何方法可以用RecyclerView实现相同的功能。

我遇到的问题是,onBindViewHolder在异步膨胀完成之前就被调用了。

3个回答

3
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.widget.FrameLayout
import androidx.asynclayoutinflater.view.AsyncLayoutInflater

class AsyncFrameLayout @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0,
    defStyleRes: Int = 0
) : FrameLayout(
    context,
    attrs,
    defStyleAttr,
    defStyleRes
) {
    init {
        layoutParams = LayoutParams(MATCH_PARENT, MATCH_PARENT)
    }

    private var isInflated = false
    private var pendingActions: MutableList<AsyncFrameLayout.() -> Unit> = ArrayList()

    fun inflateAsync(layoutResId: Int) {
        AsyncLayoutInflater(context).inflate(layoutResId, this) { view, _, _ ->
            addView(view)
            isInflated = true
            pendingActions.forEach { action -> action() }
            pendingActions.clear()
        }
    }

    fun invokeWhenInflated(action: AsyncFrameLayout.() -> Unit) {
        if (isInflated) {
            action()
        } else {
            pendingActions.add(action)
        }
    }
}

使用方法:

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
    val itemView = AsyncFrameLayout(parent.context)
    itemView.inflateAsync(R.layout.my_layout)
    return MyViewHolder(itemView)
}

override fun onBindViewHolder(viewHolder: MyViewHolder, position: Int) {
    viewHolder.itemView.invokeWhenInflated {

    }
}

2
如果您能解释一下代码的逻辑,那会更好。 - Tanuj Yadav

1

不知道这是否正是您要寻找的,但我正在考虑在充气机完成工作后设置您的回收器适配器中的项目。 这样,在inflate(...)方法之前,您的适配器getCount()将返回0,并且不再调用onBindViewHolder。


1
是的,这就是我面临的问题。有没有办法在后台膨胀我的RecyclerView项布局? - yadunath.narayanan
1
@yadunath.narayanan 你可以在onCreateViewHolder中返回一个带有空FrameLayout的视图持有者,同时在回调函数中使用frameLayout.addView(asyncInflatedView)启动异步膨胀。我可以想象如果视图在膨胀完成之前被回收可能会出现一些潜在的竞争问题(仅供参考)。 - Arturs Vancans

0

实际上,在使用Java中的RecyclerView中,AsyncLayoutInflator几乎没有什么资源可用。我实际上不得不使用少量可用于internet上的Kotlin资源,编写了自己版本的@Artem答案的Java代码。

首先,我们为recyclerview使用一个简单的虚拟视图,以便recycleview快速加载,并在后台使用asyncLayoutInflator将其余复杂的视图添加到simpleview中。

onBindExecutes之所以执行迅速且无法访问复杂布局的原因是onCreate方法仅创建了虚拟视图,因此当您尝试访问复杂视图时,它会返回空异常,因为复杂视图尚未生成。为了克服这一点,我们将列表传递给正在生成复杂视图的类,并相应地更新视图。

以下是如何实施它的程序。我的代码可能有点凌乱,因为我仍在学习,并且可以进一步改进。

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;
        }
    }

}

异步布局


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);

        }
    }
}


我想总结说,AsyncLayoutInflator 应该只在有限的情况下使用,因为其不正确的实现可能会导致意外的 UI 行为。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接