Android 卡片浏览量和 XML 加载图像导致应用延迟

Android Cardviews and XML Loading Images Make App Lag

我在 XML 中使用了 4 个卡片视图,它们每个只加载一张图片和一个文本视图。不使用 RecyclerView 或任何动态的东西。 我的导航抽屉打开时有很多滞后,整个应用程序在添加卡片视图后滞后。有没有更好的方法来实现这些卡片视图? 这些只是嵌套在线性布局中。

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:showIn="@layout/app_bar_main"
android:orientation="vertical"
tools:context="com.example.jesse.apbiologystudyappv2.MainActivity">

<android.support.v7.widget.CardView
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/card_view_1_natural_selection"
    android:layout_gravity="center"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="16dp"
    card_view:cardCornerRadius="8dp">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <ImageView
            android:layout_width="match_parent"
            android:layout_height="96dp"
            android:scaleType="centerCrop"
            android:src="@drawable/apple_tree" />
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Natural Selection and Evolution"
            android:typeface="normal"
            android:layout_centerInParent="true"
            android:textAlignment="center"
            android:textColor="@color/colorTextIcons"
            android:textSize="24dp"/>
    </RelativeLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/card_view_2_descent_and_ancestry"
    android:layout_gravity="center"
    android:layout_marginBottom="16dp"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    card_view:cardCornerRadius="8dp">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <ImageView
            android:layout_width="match_parent"
            android:layout_height="96dp"
            android:scaleType="centerCrop"
            android:src="@drawable/gravestones" />
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Descent and Ancestry"
            android:typeface="normal"
            android:layout_centerInParent="true"
            android:textAlignment="center"
            android:textColor="@color/colorTextIcons"
            android:textSize="24dp"/>
    </RelativeLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/card_view_3_speciation"
    android:layout_gravity="center"
    android:layout_width="match_parent"
    android:layout_marginBottom="16dp"
    android:layout_height="wrap_content"
    card_view:cardCornerRadius="8dp">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <ImageView
            android:layout_width="match_parent"
            android:layout_height="96dp"
            android:scaleType="centerCrop"
            android:src="@drawable/dinosaur" />
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Speciation and Extinction"
            android:typeface="normal"
            android:layout_centerInParent="true"
            android:textAlignment="center"
            android:textColor="@color/colorTextIcons"
            android:textSize="24dp"/>
    </RelativeLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/card_view_4_origin_of_life"
    android:layout_gravity="center"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="16dp"
    card_view:cardCornerRadius="8dp">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <ImageView
            android:layout_width="match_parent"
            android:layout_height="96dp"
            android:scaleType="centerCrop"
            android:src="@drawable/bacteria" />
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Origin of Life"
            android:typeface="normal"
            android:layout_centerInParent="true"
            android:textAlignment="center"
            android:textColor="@color/colorTextIcons"
            android:textSize="24dp"/>
    </RelativeLayout>
</android.support.v7.widget.CardView>


</LinearLayout>

您也应该使用 RecyclerView 来管理内存。为此,您只需要一个 CardView。

activity_main.xml :

 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:paddingLeft="@dimen/activity_horizontal_margin"
     android:paddingRight="@dimen/activity_horizontal_margin"
     android:paddingTop="@dimen/activity_vertical_margin"
     android:paddingBottom="@dimen/activity_vertical_margin"
     app:layout_behavior="@string/appbar_scrolling_view_behavior"
     tools:showIn="@layout/app_bar_main"
     android:orientation="vertical"
     tools:context="com.example.jesse.apbiologystudyappv2.MainActivity">

      <android.support.v7.widget.RecyclerView
        android:id="@+id/lstActions"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_margin="1dp"
        android:padding="0dp"/>
</LinearLayout>

cardview_item.xml:

<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/card_view_1_natural_selection"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
card_view:cardCornerRadius="8dp">
<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
        android:layout_width="match_parent"
        android:layout_height="96dp"
        android:scaleType="centerCrop"
        android:id="@+id/imgActoun" />
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/txtActoun"
        android:typeface="normal"
        android:layout_centerInParent="true"
        android:textAlignment="center"
        android:textColor="@color/colorTextIcons"
        android:textSize="24dp"/>
</RelativeLayout>

创建一个 class ActionItem.java 像这样:

public class ActionItem
{
private final int mTitleResID;
private final int mIconResID;

public ActionItem(int titleResID, int iconResID)
{
    this.mTitleResID = titleResID;
    this.mIconResID = iconResID;
}

public int getTitleResID()
{
    return mTitleResID;
}

public int getIconResID()
{
    return mIconResID;
}
}

MainActivity 中的 onCreateView 必须是这样的:

public View onCreateView(String name, Context context, AttributeSet attrs)
{
    List<ActionItem> actionItems = new ArrayList<>();
    actionItems.add(new ActionItem(R.string.NaturalSelectionAndEvolution, R.drawable.apple_tree));
    actionItems.add(new ActionItem(R.string.DescentAndAncestry, R.drawable.gravestones));
    RecyclerView lstActions = (RecyclerView) findViewById(R.id.lstActions);
    ActionAdapter actionAdapter = new ActionAdapter(actionItems);
    lstActions.setAdapter(actionAdapter);

    return super.onCreateView(name, context, attrs);
}

像这样添加 ActionAdapter:

public class ActionAdapter extends RecyclerView.Adapter<ActionAdapter.ActionHolder>
{
private final List<ActionItem> mActionItems;

public ActionAdapter(List<ActionItem> actionItems)
{
    this.mActionItems = actionItems;
}

@Override
public ActionHolder onCreateViewHolder(ViewGroup viewGroup, int i)
{
    LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
    View itemView = inflater.inflate(R.layout.cardview_item, viewGroup, false);

    return new ActionHolder(itemView);
}

@Override
public void onBindViewHolder(ActionHolder actionHolder, int position)
{
    ActionItem actionItem = mActionItems.get(position);
    actionHolder.mTxtTitle.setText(actionItem.getTitleResID());
    actionHolder.mImgIcon.setImageResource(actionItem.getIconResID());
}

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

public class ActionHolder extends RecyclerView.ViewHolder implements View.OnClickListener
{
    protected final TextView mTxtTitle;
    protected final ImageView mImgIcon;

    public ActionHolder(View view)
    {
        super(view);
        mImgIcon = (ImageView) view.findViewById(R.id.imgAction);
        mTxtTitle = (TextView) view.findViewById(R.id.txtAction);
    }
 }
}

我对 Fred 的回答做了一些改动。而不是把这个

public View onCreateView(String name, Context context, AttributeSet attrs){
    List<ActionItem> actionItems = new ArrayList<>();
    actionItems.add(new ActionItem(R.string.NaturalSelectionAndEvolution, R.drawable.apple_tree));
    actionItems.add(new ActionItem(R.string.DescentAndAncestry, R.drawable.gravestones));
    RecyclerView lstActions = (RecyclerView) findViewById(R.id.lstActions);
    ActionAdapter actionAdapter = new ActionAdapter(actionItems);
    lstActions.setAdapter(actionAdapter);

    return super.onCreateView(name, context, attrs);
}

在 onCreateView 中,我在 MainActivity 的 onCreate 中实现了它,并在 class:

的顶部放置了一些 declerations
private RecyclerView.LayoutManager mLayoutManager;
private List<ActionItem> actionItems = new ArrayList<>();
private RecyclerView listOfCards;
private ActionAdapter actionAdapter;

然而,我仍然遇到很多延迟,这是由于 XML 加载图像造成的。因此,我改用 Github 上可用的 Glide 依赖项。在ActionAdapter中,我添加了一个上下文需求,然后更改了onBindViewHolder。上下文要求是为了满足需要上下文的 Glide 方法。

public class ActionAdapter extends RecyclerView.Adapter<ActionAdapter.ActionHolder> {
private final List<ActionItem> mActionItems;
private Context mContext;

public ActionAdapter(List<ActionItem> actionItems, Context context) {
    this.mActionItems = actionItems;
    this.mContext = context;
}

@Override
public ActionHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
    LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
    View itemView = inflater.inflate(R.layout.cardview_item, viewGroup, false);

    return new ActionHolder(itemView);
}

@Override
public void onBindViewHolder(ActionHolder actionHolder, int position) {
    ActionItem actionItem = mActionItems.get(position);
    actionHolder.mTxtTitle.setText(actionItem.getTitleResID());
    Glide.with(mContext).load(actionItem.getIconResID()).into(actionHolder.mImgIcon);
}

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

public class ActionHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
    protected final TextView mTxtTitle;
    protected final ImageView mImgIcon;

    public ActionHolder(View view) {
        super(view);
        mImgIcon = (ImageView) view.findViewById(R.id.imgAction);
        mTxtTitle = (TextView) view.findViewById(R.id.txtAction);
    }

    @Override
    public void onClick(View v) {
        //do something
    }
}

}

如您所见,我从 onBindViewHolder 中删除了 actionHolder.mImgIcon .setText.... 并将其替换为 Glide 命令。这使得应用程序在启动时不会跳过任何帧,并且在打开导航抽屉时不会再产生延迟。原来延迟是由冗余 RelativeLayouts、XML 插入图片(而不是更有效的滑动)和不使用 RecyclerView 的组合产生的。