无条件布局膨胀:应该使用 View Holder 模式 [英] Unconditional layout inflation: Should use View Holder pattern

查看:34
本文介绍了无条件布局膨胀:应该使用 View Holder 模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是一个新手,我试图扩大项目行,但它在滚动时减慢了应用程序.在下面的代码中,它说我需要使用 View Holder.

 row = inflater.inflate(mLayoutResourceId, parent, false);

我该如何解决这个问题?

package com.example.android.ontrack.adapters;导入 android.content.Context;导入 android.view.LayoutInflater;导入 android.view.View;导入 android.view.ViewGroup;导入 android.widget.ArrayAdapter;导入 android.widget.TextView;导入 com.example.android.ontrack.R;导入 com.example.android.ontrack.models.Order;公共类 OrdersList 扩展了 ArrayAdapter{上下文 mContext;int mLayoutResourceId;订单 mData[] = null;公共订单列表(上下文上下文,整数资源,订单 [] 数据){超级(上下文,资源,数据);this.mContext = 上下文;this.mLayoutResourceId = 资源;this.mData = 数据;}@覆盖公共订单 getItem(int position) {返回 super.getItem(position);}@覆盖public View getView(int position, View convertView, ViewGroup parent) {查看行;LayoutInflater inflater = LayoutInflater.from(mContext);row = inflater.inflate(mLayoutResourceId, parent, false);TextView nameOfSchool = row.findViewById(R.id.school_name_orders);TextView nameOfAgent = row.findViewById(R.id.agent_name);TextView orderId = row.findViewById(R.id.order_id);TextView netRevenue = row.findViewById(R.id.net_revenue);TextView orderQuantity = row.findViewById(R.id.total_quantity);TextView date = row.findViewById(R.id.date);订单orders = mData[位置];nameOfSchool.setText(orders.nameOfSchool);nameOfAgent.setText(String.valueOf(orders.nameOfAgent));orderId.setText(String.valueOf(orders.orderId));netRevenue.setText(String.valueOf(orders.netRevenue));orderQuantity.setText(String.valueOf(orders.totalQuantity));date.setText(String.valueOf(orders.date));返回行;}}

解决方案

你的问题出在这段代码中:

<块引用>

@Overridepublic View getView(int position, View convertView, ViewGroup parent) {查看行;LayoutInflater inflater = LayoutInflater.from(mContext);row = inflater.inflate(mLayoutResourceId, parent, false);...返回行;}

警告消息是说,无论系统传递给 getView() 什么,你总是调用 inflater.inflate() 来生成你的.

首先要了解的是,传递给 getView()convertView 参数有时为 null,有时为 null.当它不为空时,它是一个旧"(回收")视图,之前从 getView() 返回.换句话说,它与您自己膨胀的类型完全相同,只是其中包含旧数据.

因此,您可以通过将上面的代码更改为以下代码来解决该问题:

@Overridepublic View getView(int position, View convertView, ViewGroup parent) {查看行;if (convertView == null) {LayoutInflater inflater = LayoutInflater.from(mContext);row = inflater.inflate(mLayoutResourceId, parent, false);} 别的 {行 = 转换视图;}...返回行;}

要理解的第二件事是 findViewById() 很慢.不像慢几秒,但足够慢,如果你必须运行它数百次,它会导致你的 UI 滞后.因此,视图持有者模式"是一种让您避免每次都必须查找这些视图的方法.

您要做的第一件事是创建一个类,该类包含您行中每个视图的字段.根据您发布的内容,这看起来像这样:

私有静态类ViewHolder {私人最终 TextView nameOfSchool;私人最终 TextView nameOfAgent;私人最终 TextView orderId;私人最终 TextView 净收入;私人最终 TextView orderQuantity;私人最终 TextView 日期;私有 ViewHolder(查看行){nameOfSchool = row.findViewById(R.id.school_name_orders);nameOfAgent = row.findViewById(R.id.agent_name);orderId = row.findViewById(R.id.order_id);netRevenue = row.findViewById(R.id.net_revenue);orderQuantity = row.findViewById(R.id.total_quantity);日期 = row.findViewById(R.id.date);}}

现在您必须将其插入到您的 getView() 代码中.每次对视图进行膨胀时(即当 convertView 为空时),您都需要创建一个新的 ViewHolder,并且您需要重新使用现有的 ViewHolder 否则.为此,我们使用视图的标记.

放在一起,看起来像这样:

@Overridepublic View getView(int position, View convertView, ViewGroup parent) {查看行;ViewHolder 支架;if (convertView == null) {LayoutInflater inflater = LayoutInflater.from(mContext);row = inflater.inflate(mLayoutResourceId, parent, false);持有人=新的ViewHolder(行);row.setTag(holder);} 别的 {行 = 转换视图;持有人 = (ViewHolder) row.getTag();}订单orders = mData[位置];holder.nameOfSchool.setText(orders.nameOfSchool);holder.nameOfAgent.setText(String.valueOf(orders.nameOfAgent));holder.orderId.setText(String.valueOf(orders.orderId));holder.netRevenue.setText(String.valueOf(orders.netRevenue));holder.orderQuantity.setText(String.valueOf(orders.totalQuantity));holder.date.setText(String.valueOf(orders.date));返回行;}

I'm a newbie, I tried to inflate the item row but it slows the application upon scrolling. In the code below, it says I need to use View Holder.

        row = inflater.inflate(mLayoutResourceId, parent, false);

How can I fix this?

package com.example.android.ontrack.adapters;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

import com.example.android.ontrack.R;
import com.example.android.ontrack.models.Order;

public class OrdersList extends ArrayAdapter<Order> {

    Context mContext;
    int mLayoutResourceId;
    Order mData[] = null;

    public OrdersList(Context context, int resource, Order[] data) {
        super(context, resource, data);
        this.mContext = context;
        this.mLayoutResourceId = resource;
        this.mData = data;
    }


    @Override
    public Order getItem(int position) {
        return super.getItem(position);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View row;

        LayoutInflater inflater = LayoutInflater.from(mContext);
        row = inflater.inflate(mLayoutResourceId, parent, false);

            TextView nameOfSchool = row.findViewById(R.id.school_name_orders);
        TextView nameOfAgent = row.findViewById(R.id.agent_name);
        TextView orderId = row.findViewById(R.id.order_id);
        TextView netRevenue = row.findViewById(R.id.net_revenue);
        TextView orderQuantity = row.findViewById(R.id.total_quantity);
        TextView date = row.findViewById(R.id.date);

        Order orders = mData[position];

        nameOfSchool.setText(orders.nameOfSchool);
        nameOfAgent.setText(String.valueOf(orders.nameOfAgent));
        orderId.setText(String.valueOf(orders.orderId));
        netRevenue.setText(String.valueOf(orders.netRevenue));
        orderQuantity.setText(String.valueOf(orders.totalQuantity));
        date.setText(String.valueOf(orders.date));

        return row;
    }
}

解决方案

Your problem is in this bit of code:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View row;

    LayoutInflater inflater = LayoutInflater.from(mContext);
    row = inflater.inflate(mLayoutResourceId, parent, false);

    ...
    return row;
}

The warning message is saying that, no matter what gets passed by the system to getView(), you're always calling inflater.inflate() to generate your row.

The first thing to understand is that the convertView param passed to getView() is sometimes null, and sometimes not. When it is not null, it is an "old" ("recycled") view that was previously returned from getView(). In other words, it's the exact same type of view that you'd inflate yourself, it just has old data in it.

So, you can fix that problem by changing the above code to this instead:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View row;

    if (convertView == null) {
        LayoutInflater inflater = LayoutInflater.from(mContext);
        row = inflater.inflate(mLayoutResourceId, parent, false);
    } else {
        row = convertView;
    }

    ...
    return row;
}

The second thing to understand is that findViewById() is slow. Not like multiple seconds slow, but slow enough that if you have to run it hundreds of times it will cause your UI to lag. So the "view holder pattern" is a way for you to avoid having to look up these views every time.

The first thing you do is create a class that has fields for each view in your row. Given what you posted, that would look something like this:

private static class ViewHolder {

    private final TextView nameOfSchool;
    private final TextView nameOfAgent;
    private final TextView orderId;
    private final TextView netRevenue;
    private final TextView orderQuantity;
    private final TextView date;

    private ViewHolder(View row) {
        nameOfSchool = row.findViewById(R.id.school_name_orders);
        nameOfAgent = row.findViewById(R.id.agent_name);
        orderId = row.findViewById(R.id.order_id);
        netRevenue = row.findViewById(R.id.net_revenue);
        orderQuantity = row.findViewById(R.id.total_quantity);
        date = row.findViewById(R.id.date);
    }
}

Now you have to plug it in to your getView() code. You will want to create a new ViewHolder every time you inflate a view (i.e. when convertView is null), and you'll want to re-use an existing ViewHolder otherwise. We use the view's tag for this.

All together, it looks like this:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View row;
    ViewHolder holder;

    if (convertView == null) {
        LayoutInflater inflater = LayoutInflater.from(mContext);
        row = inflater.inflate(mLayoutResourceId, parent, false);
        holder = new ViewHolder(row);
        row.setTag(holder);       
    } else {
        row = convertView;
        holder = (ViewHolder) row.getTag();
    }

    Order orders = mData[position];

    holder.nameOfSchool.setText(orders.nameOfSchool);
    holder.nameOfAgent.setText(String.valueOf(orders.nameOfAgent));
    holder.orderId.setText(String.valueOf(orders.orderId));
    holder.netRevenue.setText(String.valueOf(orders.netRevenue));
    holder.orderQuantity.setText(String.valueOf(orders.totalQuantity));
    holder.date.setText(String.valueOf(orders.date));

    return row;
}

这篇关于无条件布局膨胀:应该使用 View Holder 模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆