首页 > 解决方案 > RecyclerView onBindViewHolder 方法增加启动时间?

问题描述

我是 android 应用程序开发的新手,我最近制作了我的第一个应用程序,其中包含一个基本的 tablayout,在我的 MainActivity 中有两个片段。

在我的第二个选项卡中,它仅包含一个 RecyclerView 作为根布局。我所做的是用我自己的数据模型的数组列表填充 RecyclerView。

我的 RecyclerView 有 13 个项目。这些项目的视图是来自https://github.com/florent37/ExpansionPanel的扩展布局,我完全按照他为 RecyclerView 所做的方式进行了操作,并且效果很好。

但是,我的应用程序的启动时间已显着增加到1s++。我发现我的 RecyclerViewAdapter 中的 onBindViewHolder 方法是罪魁祸首。我尝试注释掉onBindViewHolder方法的内容,启动时间减少了一半到600ms,这对我来说还可以。

所以我的问题是如何解决这个问题?我应该以不同的方式绑定我的数据吗?

我不想有一个缓慢的启动时间。我看到了一些关于使用数据绑定 API、在不同的线程和异步上运行的帖子,但我不知道该怎么做。

请帮忙~先谢谢了!

这是我的适配器:

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

private Context context;
private ArrayList<DataModel> list;
private final ExpansionLayoutCollection expansionsCollection = new ExpansionLayoutCollection();

MyAdapter(ArrayList<DataModel> list, Context context) {
    this.list = list;
    this.context = context;
    expansionsCollection.openOnlyOne(true);
}


@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
   View itemView == LayoutInflater.from(parent.getContext()).inflate(R.layout.expansion_panel, parent, false);
   return new ViewHolder(itemView);
}


@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {

    DataModel currentData = list.get(position);
    switch (currentData.getType()) {
        case DataModel.NO_FORMULA:
            holder.titleText.setText(currentData.getTitle());
            holder.contentText.setText(currentData.getContent());
            holder.formulaView.removeAllViews();
            expansionsCollection.add(holder.expansionLayout);
            break;

        case DataModel.WITH_FORMULA:
            View formulaLayout = ((Activity)context).getLayoutInflater().inflate(currentData.getFormulaLayoutId(),null);

            holder.titleText.setText(currentData.getTitle());
            holder.contentText.setText(currentData.getContent());
            holder.formulaView.removeAllViews();
            holder.formulaView.addView(formulaLayout);
            expansionsCollection.add(holder.expansionLayout);
            break;
    }
}


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

private static class ViewHolder extends RecyclerView.ViewHolder {

    TextView titleText, contentText;
    ExpansionLayout expansionLayout;
    FrameLayout formulaView;

    ViewHolder(View itemView) {
        super(itemView);
        this.titleText = itemView.findViewById(R.id.title_text);
        this.contentText = itemView.findViewById(R.id.content_text);
        this.expansionLayout = itemView.findViewById(R.id.expansionLayout);
        this.formulaView  = itemView.findViewById(R.id.formula_view);
    }

}

这是我的项目布局:

    <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    tools:ignore="ContentDescription,RtlHardcoded,HardcodedText">

    <com.github.florent37.expansionpanel.ExpansionHeader
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#fff"
        app:expansion_headerIndicator="@id/headerIndicator"
        app:expansion_layout="@id/expansionLayout"
        app:expansion_toggleOnClick="true">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="?android:attr/selectableItemBackground"
            android:minHeight="50dp"
            android:paddingLeft="16dp"
            android:paddingRight="16dp"
            android:theme="@style/RecyclerViewTheme">

            <TextView
                android:id="@+id/title_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_centerVertical="true"
                android:layout_toLeftOf="@id/headerIndicator"
                android:textColor="#000" />

            <android.support.v7.widget.AppCompatImageView
                android:id="@+id/headerIndicator"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true"
                android:layout_marginLeft="16dp"
                android:adjustViewBounds="true"
                app:srcCompat="@drawable/ic_expansion_header_indicator_grey_24dp" />

        </RelativeLayout>


    </com.github.florent37.expansionpanel.ExpansionHeader>

    <com.github.florent37.expansionpanel.ExpansionLayout
        android:id="@+id/expansionLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:expansion_expanded="false">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:background="#F5F5F5">

            <TextView
                android:id="@+id/content_text"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="16dp"
                android:textColor="#000" />

            <FrameLayout
                android:id="@+id/formula_view"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>

        </LinearLayout>

    </com.github.florent37.expansionpanel.ExpansionLayout>

    <View
        android:layout_width="match_parent"
        android:layout_height="0.7dp"
        android:background="?android:attr/listDivider" />

</LinearLayout>

这是我的数据模型:

public class DataModel {

public static final int WITH_FORMULA = 0;
public static final int NO_FORMULA = 1;

private String title, content;
private int type, formulaLayoutId;

DataModel(int type, String title, String content) {
    this.type = type;
    this.title = title;
    this.content = content;
}

DataModel(int type, String title, String content, int formulaLayoutId) {
    this.type = type;
    this.title = title;
    this.content = content;
    this.formulaLayoutId = formulaLayoutId;
}

public String getTitle() {
    return title;
}

public String getContent() {
    return content;
}

public int getFormulaLayoutId() {
    return formulaLayoutId;
}

public int getType() {
    return type;
}

*我创建了 13 个以长标题和长段落为内容的 DataModel 对象,并将它们放在一个数组列表中。当用户单击扩展面板的标题时,扩展布局将展开以显示其内容。

recyclerview 中的 13 个项目中只有 2 个是 WITH_FORMULA 的类型,它必须膨胀 formulaLayout。

标签: androidperformancedata-bindingandroid-recyclerviewapp-startup

解决方案


如果您确定问题的根源onBindViewHolder是通货膨胀,那么唯一的问题就是通货膨胀。

inflate是一个非常昂贵的操作,因为它解析 XML 然后创建视图层次结构。不要在onBindViewHolder. onCreateViewHolder而是将视图膨胀一次。如果您不想显示它NO_FORMULA以防万一,只需将其可见性设置为GONE和以防VISIBLE万一WITH_FORMULA。更改可见性是一种更简单的操作。


推荐阅读