ListView中滚动时速度很慢(使用ViewHolder /再循环) [英] ListView very slow when scrolling (using ViewHolder/recycling)

查看:199
本文介绍了ListView中滚动时速度很慢(使用ViewHolder /再循环)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新2011-08-29 如果我删除图像中的NodePickup,11:43就没了。

现在的问题是 - 为什么

----

我回来在尝试一些Android开发了。我有一个老的HTC Hero手机躺在附近,所以我启动一个了,做了一些更新,现在n个再次运行Eclipse和休息。

我的Andr​​oid 2.1运行在设备上。

我做了一个非常简单的测试应用程序,没有做任何事情,除了显示一些活动和这样的。即使没有数据库连接,从任一网络获取任何数据的应用程序是非常缓慢的。速度很慢。

例如,我有一些自定义布局项目一个ListView。如果只增加6-7项(让我得到的滚动)是滚动时出奇的慢。另外,我有一些按钮,改变了活动,也这是非常非常慢的:

  mButtonListenerUPP =新OnClickListener(){
    @覆盖
    公共无效的onClick(视图v)
    {
        意图myIntent =新的意图(BaseActivity.this,ActivityMain.class);
        BaseActivity.this.startActivity(myIntent);
    }
};
 

我想不通为什么,所以我只是张贴了code在这里,希望有人有一些提示,我=)

THX!

的适配器,NodeRowAdapter

 进口的java.util.ArrayList;
进口的java.util.List;

进口android.app.Activity;
进口android.content.Context;
进口android.view *。
进口android.widget.ArrayAdapter;

进口android.widget.TextView;

公共类NodeRowAdapter扩展ArrayAdapter
{
    私人活动范围内;
    私人的ArrayList<节点> mList;
    私人LayoutInflater充气;

    NodeRowAdapter(活动背景下,ArrayList的<节点>对象)
    {
        超(背景下,R.layout.nodepickup,对象);
        this.context =背景;
        mList =物体;
        充气=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    类ViewHolder
    {
        TextView的名称;
        TextView的时间;
        TextView的道路;
        节点节点;
    }

    公共节点getNode(INT位置)
    {
        如果(mList = NULL和放大器;!&安培; mList.size()>的位置)
            返回mList.get(位置);
        其他
            返回null;
    }
    公共查看getView(INT位置,查看convertView,父母的ViewGroup)
    {
        查看查看= convertView;
        ViewHolder持有人;
        如果(查看== NULL)
        {
            鉴于= inflater.inflate(R.layout.nodepickup,父母,假);
            持有人=新ViewHolder();
            holder.name =(TextView中)view.findViewById(R.id.name);
            holder.time =(TextView中)view.findViewById(R.id.time);
            holder.road =(TextView中)view.findViewById(R.id.road);
            view.setTag(保持器);
        }
        其他
        {
            支架=(ViewHolder)convertView.getTag();
        }

        节点node = mList.get(位置);
        holder.name.setText(node.name);
        holder.time.setText(node.time);
        holder.road.setText(node.road);

        返回(视图);
    }
}
 

的主要活动,ActivityMain

 公共类ActivityMain扩展BaseActivity
{
    私人NodeRowAdapter _nodeRowAdapter;

    / **第一次创建活动时调用。 * /
    @覆盖
    公共无效的onCreate(包savedInstanceState)
    {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        super.onCreate(savedInstanceState);
        的setContentView(R.layout.main);

        SICApplication._myContext =这一点;
        SICApplication._myContext =这一点;

        _nodeRowAdapter =新NodeRowAdapter(这一点,SICApplication.dataHolder_activityMain._nodes);
        ListView控件ListView1的=(的ListView)findViewById(R.id.ListViewNodes);
        listView1.setOnItemClickListener(新OnItemClickListener()
        {
            公共无效onItemClick(适配器视图<>母公司视图中查看,INT位置,长ID)
            {
                节点node = _nodeRowAdapter.getNode(位置);
                Log.v(MyApp的,节点=+ node.name);
            }
        });
        listView1.setAdapter(_nodeRowAdapter);

    }

    / *处理项目选择* /
    公共布尔onOptionsItemSelected(菜单项项)
    {
        开关(item.getItemId())
        {
            案例R.id.add_item:
                addNodeItem();
                返回true;
        }
        返回false;
    }



    私人无效addNodeItem()
    {
        _nodeRowAdapter.add(新节点(测试,ASD ASD,14点00,1));

    }
}
 

自定义列表项,NodePickup

 公共类NodePickup扩展的LinearLayout
{
    公共NodePickup(上下文的背景下,AttributeSet中的AttributeSet)
    {
        超(背景下,AttributeSet中的);

        LayoutInflater充气=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.nodepickup,这一点);

        this.setOnClickListener(新OnClickListener()
        {
            @覆盖
            公共无效的onClick(视图v)
            {
                AlertDialog.Builder建设者=新AlertDialog.Builder(的getContext());
                builder.setMessage(Ajabaja!)
                .setCancelable(真)
                .setPositiveButton(JA!,新DialogInterface.OnClickListener()
                {
                   公共无效的onClick(DialogInterface对话框,INT ID)
                   {
                       dialog.cancel();
                   }
                });
                builder.show();
            }

        });
    }
}
 

最后,在NodePickup XML布局

 <的LinearLayout
    机器人:ID =@ + ID / LinearLayout01
    机器人:layout_width =FILL_PARENT
    机器人:layout_height =64dip
    机器人:方向=横向
    机器人:背景=@可绘制/ stateful_background
    的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android>

    < ImageView的
        机器人:ID =@ + ID / ImageView01
        机器人:layout_width =40dip
        机器人:layout_height =40dip
        机器人:SRC =@可绘制/ arrow_up_green
        机器人:背景=@机器人:彩色/透明>
    < / ImageView的>

    <的LinearLayout
        机器人:ID =@ + ID / LinearLayout02
        机器人:背景=@机器人:彩色/透明
        机器人:layout_width =FILL_PARENT
        机器人:layout_height =WRAP_CONTENT
        机器人:方向=垂直
        的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android>

        <的TextView
            机器人:文本=14:46(15分钟)
            机器人:ID =@ + ID /时间
            机器人:TEXTSIZE =12dip
            机器人:文字颜色=#000000
            机器人:layout_width =FILL_PARENT
            机器人:layout_height =WRAP_CONTENT
            机器人:背景=@机器人:彩色/透明>
        < / TextView的>

        <的TextView
            机器人:文本=测试
            机器人:ID =@ + ID /路
            机器人:TEXTSIZE =12dip
            机器人:文字颜色=#000000
            机器人:layout_width =FILL_PARENT
            机器人:layout_height =WRAP_CONTENT
            机器人:背景=@机器人:彩色/透明>
        < / TextView的>

        <的TextView
            机器人:文本=考试考试
            机器人:ID =@ + ID /名称
            机器人:TEXTSIZE =12dip
            机器人:文字颜色=#000000
            机器人:layout_width =FILL_PARENT
            机器人:layout_height =WRAP_CONTENT
            机器人:背景=@机器人:彩色/透明>
        < / TextView的>
    < / LinearLayout中>
< / LinearLayout中>
 

解决方案
  

更新2011-08-29如果我删除图像中的NodePickup,11:43也没有​​了。

视图有一个很难搞清楚如何布局应呈现。您发布的XML没有多大帮助。如果您删除的ImageView那么LinearLayout02将母公司所有的宽度。但具有ImageView的与STANDAR dimentions和布局,将FILL_PARENT权混淆的观点很多。再次请求ImageView的大小,以推动利润率的权利(种)。以低于

看看我的建议

提示1

使用的LinearLayout属性权重。使ImageView的FILL_PARENT和的LinearLayout太(为宽度),并与配重​​特性发挥。 做到这一点也与TextViews垂直布局。最好解决方案对子级是把一个固定的大小来以为TextViews的高度。 另外还要考虑改变顶视图RelativeLayout的。请与STANDAR dimentions,AlignParentLeft图像,并把LinearLayout02 toRightOf ImageView的。你会救济的ViewGroup的onMeasure了很多。

提示2

好像当文字高度发生变化的全貌必须reinflated.A常见的工艺,以避免它,使列表项目固定的高度。因此,列表视图可以重复使用回收的看法,并没有reinflating。

提示3

给你LinearLayout02的64dp或FILL_PARENT一个固定的高度,因为你没有任何左侧的空间,但布局不知道,并尽量每次都重新安排它的自我,因为文字也是WRAP_CONTENT。

另外你说,如果你删除了ImageView的一切都是快了。如果上面没有任何影响能不能请你呢?既然你知道ImageView的大小是固定的。

扩展您的ImageView和覆盖requestLayout()方法。

 公共类MyImageView扩展ImageView的{

公共PImageView(上下文的背景下,ATTRS的AttributeSet,诠释defStyle){
    超(背景下,ATTRS,defStyle);

}

公共PImageView(上下文的背景下,ATTRS的AttributeSet){
    超(背景下,ATTRS);

}

公共PImageView(上下文的背景下){
    超(上下文);

}

@覆盖
    公共无效requestLayout(){
        / *
         *在这里做什么
         * /
    }
}
 

现在包括MyImageView小部件的XML之类的。

 < com.package_name.MyImageView
        机器人:ID =@ + ID / ImageView01
        机器人:layout_width =40dip
        机器人:layout_height =40dip
        机器人:SRC =@可绘制/ arrow_up_green
        机器人:背景=@机器人:彩色/透明>
 < /com.package_name.MyImageView>
 

UPDATE 2011-08-29 If I remove the image in the NodePickup, the lagginess is gone.

The question is - why?

----

I'm back at trying out some Android dev again. I have an "old" HTC Hero phone lying around, so I booted that one up, did some updates and are now up n running again with Eclipse and the rest.

I have Android 2.1 running on the device.

I have made a very simple test app that doesnt do anything at all except for showing some Activities and such. Even though there is no database connection, no data fetched from any network the app is very slow. VERY slow.

For example, I have a ListView with some custom layout items. When adding only 6-7 items (so that I get the scrolling) it is insanely slow when scrolling. Also, I have some buttons that changes the Activity and also that is very very slow:

mButtonListenerUPP = new OnClickListener() {
    @Override
    public void onClick(View v)
    {
        Intent myIntent = new Intent(BaseActivity.this, ActivityMain.class);
        BaseActivity.this.startActivity(myIntent);
    }
};

I cannot figure out why, so Im just posting the code here and hope that someone has some tip for me =)

Thx!

The Adapter, NodeRowAdapter

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.view.*;
import android.widget.ArrayAdapter;

import android.widget.TextView;

public class NodeRowAdapter extends ArrayAdapter 
{
    private Activity context;
    private ArrayList<Node> mList;
    private LayoutInflater inflater;

    NodeRowAdapter(Activity context, ArrayList<Node> objects) 
    {
        super(context, R.layout.nodepickup, objects);
        this.context=context;
        mList = objects;
        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    class ViewHolder 
    {
        TextView name;
        TextView time;
        TextView road;
        Node node;
    }

    public Node getNode(int position)
    {
        if (mList != null && mList.size() > position)
            return mList.get(position);
        else
            return null;
    }
    public View getView(int position, View convertView, ViewGroup parent) 
    {
        View view = convertView;
        ViewHolder holder;
        if (view == null)
        {
            view = inflater.inflate(R.layout.nodepickup, parent, false);
            holder = new ViewHolder();
            holder.name =(TextView)view.findViewById(R.id.name);
            holder.time =(TextView)view.findViewById(R.id.time);
            holder.road =(TextView)view.findViewById(R.id.road);
            view.setTag(holder);
        }
        else
        {
            holder = (ViewHolder) convertView.getTag();
        }

        Node node = mList.get(position);
        holder.name.setText(node.name);
        holder.time.setText(node.time);
        holder.road.setText(node.road);

        return(view);
    }
}

The main activity, ActivityMain

public class ActivityMain extends BaseActivity 
{
    private NodeRowAdapter _nodeRowAdapter;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        SICApplication._myContext = this;
        SICApplication._myContext = this;

        _nodeRowAdapter = new NodeRowAdapter(this, SICApplication.dataHolder_activityMain._nodes);
        ListView listView1 = (ListView) findViewById(R.id.ListViewNodes);
        listView1.setOnItemClickListener(new OnItemClickListener() 
        {
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) 
            {
                Node node = _nodeRowAdapter.getNode(position);
                Log.v("MyApp", "Node=" + node.name);
            } 
        });
        listView1.setAdapter(_nodeRowAdapter);  

    }

    /* Handles item selections */
    public boolean onOptionsItemSelected(MenuItem item) 
    {
        switch (item.getItemId()) 
        {
            case R.id.add_item:
                addNodeItem();
                return true;
        }
        return false;
    }



    private void addNodeItem()
    {
        _nodeRowAdapter.add(new Node("Test", "asd asd ", "14:00", 1));

    }
}

The custom list item, NodePickup

public class NodePickup extends LinearLayout
{
    public NodePickup(Context context, AttributeSet attributeSet)
    {
        super(context, attributeSet);

        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.nodepickup, this);

        this.setOnClickListener(new OnClickListener() 
        {
            @Override
            public void onClick(View v)
            {
                AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
                builder.setMessage("Ajabaja!")
                .setCancelable(true)
                .setPositiveButton("JA!", new DialogInterface.OnClickListener() 
                {
                   public void onClick(DialogInterface dialog, int id) 
                   {
                       dialog.cancel();
                   }
                });
                builder.show();
            }

        });
    }
}

And lastly, the NodePickup XML layout

<LinearLayout 
    android:id="@+id/LinearLayout01" 
    android:layout_width="fill_parent" 
    android:layout_height="64dip"
    android:orientation="horizontal" 
    android:background="@drawable/stateful_background"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <ImageView 
        android:id="@+id/ImageView01" 
        android:layout_width="40dip" 
        android:layout_height="40dip"
        android:src="@drawable/arrow_up_green"
        android:background="@android:color/transparent">
    </ImageView>

    <LinearLayout 
        android:id="@+id/LinearLayout02"
        android:background="@android:color/transparent"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:orientation="vertical"
        xmlns:android="http://schemas.android.com/apk/res/android">

        <TextView
            android:text="14:46 (15 min)"
            android:id="@+id/time"
            android:textSize="12dip"
            android:textColor = "#000000"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/transparent">
        </TextView>

        <TextView
            android:text="test"
            android:id="@+id/road"
            android:textSize="12dip"
            android:textColor = "#000000"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/transparent">
        </TextView>

        <TextView
            android:text="test test"
            android:id="@+id/name"
            android:textSize="12dip"
            android:textColor = "#000000"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/transparent">
        </TextView>
    </LinearLayout>
</LinearLayout>

解决方案

UPDATE 2011-08-29 If I remove the image in the NodePickup, the lagginess is gone.

The view has a hard time figuring how the layout should be rendered. The xml you posted don't help much. If you remove the ImageView then the LinearLayout02 will take all the width of the parent. But having the imageView with standar dimentions and the layout to the right will fill_parent confuses the view a lot. Requests the size of the imageView again to "push the margins to the right" (kind of). Take a look at my suggestions below

Tip1

use the LinearLayout property weight. Make the imageView fill_parent and the LinearLayout too (for the width) and play with the weight properties. Do that also for the vertical layout with the TextViews. The best Solution whould be to put a fixed size to the height of the TextViews thought. Also consider to change the top view to RelativeLayout. Make the image with standar dimentions , AlignParentLeft and put the LinearLayout02 toRightOf imageView. You will relief the onMeasure of the ViewGroup a lot.

Tip2

It seems like when the text changes height the whole view need to be reinflated.A common technic to avoid that it to make list Item fixed in height. So the listview can reuse the recycled views without reinflating.

Tip3

Give your LinearLayout02 a fixed height of 64dp or Fill_Parent since you don't have any left space, but the Layout don't know that and try to rearrange it self every time since the text is also Wrap_content.

Also you said that if you remove the ImageView everything is fast again.If the above don't have any effect can you please try this? Since you know that imageView size is fixed.

Extend your imageView and override requestLayout() method.

public class MyImageView extends ImageView {

public PImageView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);

}

public PImageView(Context context, AttributeSet attrs) {
    super(context, attrs);

}

public PImageView(Context context) {
    super(context);

}

@Override
    public void requestLayout() {
        /*
         * Do nothing here
         */
    }
}

Now include the MyImageView widget to your XML like that.

<com.package_name.MyImageView 
        android:id="@+id/ImageView01" 
        android:layout_width="40dip" 
        android:layout_height="40dip"
        android:src="@drawable/arrow_up_green"
        android:background="@android:color/transparent">
 </com.package_name.MyImageView >

这篇关于ListView中滚动时速度很慢(使用ViewHolder /再循环)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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