zoukankan      html  css  js  c++  java
  • listView中多个listItem布局时,convertView缓存及使用

    转载请保留出处:http://www.eoeandroid.com/thread-72369-1-1.html

     
     
    最近有需求需要在listView中载入不同的listItem布局,开始没有使用convertView,加载了多个item后导致了内存泄露,所以回来研究convertView在多个listItem布局时的缓存及应用,并且和大家分享
    构造Adapter时,没有使用缓存的 convertView,导致内存泄露
    示例代码:
    1 public View getView(int position, View convertView, ViewGroup parent) {
    2    View view = new Xxx(...);
    3    ... ...
    4    return view;
    5  }

     描述:   以构造ListViewBaseAdapter为例,在BaseAdapter中提供了方法:

     public View getView(int position, View convertView, ViewGroup parent){ }
     
    来向ListView提供每一个item所需要的view对象。初始时ListView会从BaseAdapter中根据当前的屏幕布局实例化一定数量的view对象,同时ListView会将这些view对象缓存起来。当向上滚动ListView时,原先位于最上面的list itemview对象会被回收,然后被用来构造新出现的最下面的list item。这个构造过程就是由getView()方法完成的,getView()的第二个形参 View convertView就是被缓存起来的list itemview对象(初始化时缓存中没有view对象则convertViewnull)   由此可以看出,如果我们不去使用convertView,而是每次都在getView()中重新实例化一个View对象的话,即浪费资源也浪费时间,也会使得内存占用越来越大。
    修正示例代码:
     1 public View getView(int position, View convertView, ViewGroup parent) {
     2    View view = null;
     3    if (convertView != null) {
     4    view = convertView;
     5    ...
     6    } else {
     7    view = new Xxx(...);
     8    ...
     9    }
    10    return view;
    11  } 

    上述代码很好的解决了内存泄露的问题,使用convertView回收一些布局供下面重构是使用。

    但是如果出现如下图的需求,convertView就不太好用了,convertViewItem为单一的布局时,能够回收并重用,但是多个Item布局时,convertView的回收和重用会出现问题。

    Listview中有3Item布局,即使convertView缓存了一些布局,但是在重构时,根本不知道怎么样去让convertView返回你所需要的布局,这时你需要让adapter知道我当前有哪些布局,我重构Item时的布局选取规则,好让convertView能返回你需要的布局
    需要重写一下两个函数
    @Override
    public int getItemViewType(int position) {}

    官网解释如下,不解释了 Get the type of View that will be created by getView(int, android.view.View, android.view.ViewGroup)]getView(int, View, ViewGroup) for the specified item.
    Parameters

    position The position of the item within the adapter's data set whose view type we want.

    Returns

    • An integer representing the type of View. Two views should share the same type if one can be converted to the other in getView(int, android.view.View, android.view.ViewGroup)getView(int, View, ViewGroup). Note: Integers must be in the range 0 to getViewTypeCount() - 1. IGNORE_ITEM_VIEW_TYPE can also be returned.
    @Override
    public int getViewTypeCount() {}

    Get the type of View that will be created by getView(int, android.view.View, android.view.ViewGroup)getView(int, View, ViewGroup) for the specified item.
    Parameters

    position The position of the item within the adapter's data set whose view type we want.

    Returns

    • An integer representing the type of View. Two views should share the same type if one can be converted to the other in getView(int, android.view.View, android.view.ViewGroup)getView(int, View, ViewGroup). Note: Integers must be in the range 0 to getViewTypeCount() - 1. IGNORE_ITEM_VIEW_TYPE can also be returned.
    上述两个函数的作用这如它的名字,得到Item的样式,得到所有的样式数量
    下面直接上代码,就是上图的实现代码:
     
      1 package com.bestv.listViewTest;
      2 
      3 import java.util.ArrayList;
      4 
      5 import android.app.Activity;
      6 
      7 import android.content.Context;
      8 
      9 import android.os.Bundle;
     10 
     11 import android.util.Log;
     12 
     13 import android.view.LayoutInflater;
     14 
     15 import android.view.View;
     16 
     17 import android.view.ViewGroup;
     18 
     19 import android.widget.BaseAdapter;
     20 
     21 import android.widget.CheckBox;
     22 
     23 import android.widget.ImageView;
     24 
     25 import android.widget.LinearLayout;
     26 
     27 import android.widget.ListView;
     28 
     29 import android.widget.TextView;
     30 
     31 public class listViewTest extends Activity
     32 {
     33 
     34     /** Called when the activity is first created. */
     35 
     36     ListView listView;
     37 
     38     MyAdapter listAdapter;
     39 
     40     ArrayList<String> listString;
     41 
     42     @Override
     43     public void onCreate(Bundle savedInstanceState)
     44     {
     45 
     46         super.onCreate(savedInstanceState);
     47 
     48         setContentView(R.layout.main);
     49 
     50         listView = (ListView) this.findViewById(R.id.listview);
     51 
     52         listString = new ArrayList<String>();
     53 
     54         for (int i = 0; i < 100; i++)
     55 
     56         {
     57 
     58             listString.add(Integer.toString(i));
     59 
     60         }
     61 
     62         listAdapter = new MyAdapter(this);
     63 
     64         listView.setAdapter(listAdapter);
     65 
     66     }
     67 
     68     class MyAdapter extends BaseAdapter
     69     {
     70 
     71         Context mContext;
     72 
     73         LinearLayout linearLayout = null;
     74 
     75         LayoutInflater inflater;
     76 
     77         TextView tex;
     78 
     79         final int VIEW_TYPE = 3;
     80 
     81         final int TYPE_1 = 0;
     82 
     83         final int TYPE_2 = 1;
     84 
     85         final int TYPE_3 = 2;
     86 
     87         public MyAdapter(Context context)
     88         {
     89 
     90             // TODO Auto-generated constructor stub
     91 
     92             mContext = context;
     93 
     94             inflater = LayoutInflater.from(mContext);
     95 
     96         }
     97 
     98         @Override
     99         public int getCount()
    100         {
    101 
    102             // TODO Auto-generated method stub
    103 
    104             return listString.size();
    105 
    106         }
    107 
    108         //每个convert view都会调用此方法,获得当前所需要的view样式
    109 
    110         @Override
    111         public int getItemViewType(int position)
    112         {
    113 
    114             // TODO Auto-generated method stub
    115 
    116             int p = position % 6;
    117 
    118             if (p == 0)
    119 
    120                 return TYPE_1;
    121 
    122             else if (p < 3)
    123 
    124                 return TYPE_2;
    125 
    126             else if (p < 6)
    127 
    128                 return TYPE_3;
    129 
    130             else
    131 
    132                 return TYPE_1;
    133 
    134         }
    135 
    136         @Override
    137         public int getViewTypeCount()
    138         {
    139 
    140             // TODO Auto-generated method stub
    141 
    142             return 3;
    143 
    144         }
    145 
    146         @Override
    147         public Object getItem(int arg0)
    148         {
    149 
    150             // TODO Auto-generated method stub
    151 
    152             return listString.get(arg0);
    153 
    154         }
    155 
    156         @Override
    157         public long getItemId(int position)
    158         {
    159 
    160             // TODO Auto-generated method stub
    161 
    162             return position;
    163 
    164         }
    165 
    166         @Override
    167         public View getView(int position, View convertView, ViewGroup parent)
    168         {
    169 
    170             // TODO Auto-generated method stub
    171 
    172             viewHolder1 holder1 = null;
    173 
    174             viewHolder2 holder2 = null;
    175 
    176             viewHolder3 holder3 = null;
    177 
    178             int type = getItemViewType(position);
    179 
    180             //无convertView,需要new出各个控件
    181 
    182             if (convertView == null)
    183 
    184             {
    185                 Log.e("convertView = ", " NULL");
    186 
    187                 //按当前所需的样式,确定new的布局
    188 
    189                 switch (type)
    190 
    191                 {
    192 
    193                     case TYPE_1:
    194 
    195                         convertView = inflater.inflate(R.layout.listitem1, parent, false);
    196 
    197                         holder1 = new viewHolder1();
    198 
    199                         holder1.textView = (TextView) convertView.findViewById(R.id.textview1);
    200 
    201                         holder1.checkBox = (CheckBox) convertView.findViewById(R.id.checkbox);
    202 
    203                         Log.e("convertView = ", "NULL TYPE_1");
    204 
    205                         convertView.setTag(holder1);
    206 
    207                         break;
    208 
    209                     case TYPE_2:
    210 
    211                         convertView = inflater.inflate(R.layout.listitem2, parent, false);
    212 
    213                         holder2 = new viewHolder2();
    214 
    215                         holder2.textView = (TextView) convertView.findViewById(R.id.textview2);
    216 
    217                         Log.e("convertView = ", "NULL TYPE_2");
    218 
    219                         convertView.setTag(holder2);
    220 
    221                         break;
    222 
    223                     case TYPE_3:
    224 
    225                         convertView = inflater.inflate(R.layout.listitem3, parent, false);
    226 
    227                         holder3 = new viewHolder3();
    228 
    229                         holder3.textView = (TextView) convertView.findViewById(R.id.textview3);
    230 
    231                         holder3.imageView = (ImageView) convertView.findViewById(R.id.imageview);
    232 
    233                         Log.e("convertView = ", "NULL TYPE_3");
    234 
    235                         convertView.setTag(holder3);
    236 
    237                         break;
    238 
    239                 }
    240 
    241             }
    242 
    243             else
    244 
    245             {
    246 
    247                 //有convertView,按样式,取得不用的布局
    248 
    249                 switch (type)
    250 
    251                 {
    252 
    253                     case TYPE_1:
    254 
    255                         holder1 = (viewHolder1) convertView.getTag();
    256 
    257                         Log.e("convertView !!!!!!= ", "NULL TYPE_1");
    258 
    259                         break;
    260 
    261                     case TYPE_2:
    262 
    263                         holder2 = (viewHolder2) convertView.getTag();
    264 
    265                         Log.e("convertView !!!!!!= ", "NULL TYPE_2");
    266 
    267                         break;
    268 
    269                     case TYPE_3:
    270 
    271                         holder3 = (viewHolder3) convertView.getTag();
    272 
    273                         Log.e("convertView !!!!!!= ", "NULL TYPE_3");
    274 
    275                         break;
    276 
    277                 }
    278 
    279             }
    280 
    281             //设置资源
    282 
    283             switch (type)
    284 
    285             {
    286 
    287                 case TYPE_1:
    288 
    289                     holder1.textView.setText(Integer.toString(position));
    290 
    291                     holder1.checkBox.setChecked(true);
    292 
    293                     break;
    294 
    295                 case TYPE_2:
    296 
    297                     holder2.textView.setText(Integer.toString(position));
    298 
    299                     break;
    300 
    301                 case TYPE_3:
    302 
    303                     holder3.textView.setText(Integer.toString(position));
    304 
    305                     holder3.imageView.setBackgroundResource(R.drawable.icon);
    306 
    307                     break;
    308 
    309             }
    310 
    311             return convertView;
    312 
    313         }
    314 
    315     }
    316 
    317     //各个布局的控件资源
    318 
    319     class viewHolder1
    320     {
    321 
    322         CheckBox checkBox;
    323 
    324         TextView textView;
    325 
    326     }
    327 
    328     class viewHolder2
    329     {
    330 
    331         TextView textView;
    332 
    333     }
    334 
    335     class viewHolder3
    336     {
    337 
    338         ImageView imageView;
    339 
    340         TextView textView;
    341 
    342     }
    343 
    344 }

     在getView()中需要将不同布局进行缓存和适配,系统在判断是否有convertView时,会自动去调用getItemViewType (int position) ,查看是否已经有缓存的该类型的布局,从而进入if(convertView == null)和else{}的判断。期间需要做的是convertView.setTag(holder3),以便在convertView重用时可以直接拿到该布局的控件,holder3 = (viewHolder3) convertView.getTag()。到这一步,convertView的回收和重用就已经写好了,接下来只需要对你的不同的控件进行设置就行了。

  • 相关阅读:
    tornado 异步
    tornado websocket
    tornado cookie和session
    13 python学习笔记-面向对象编程2
    12 python学习笔记-面向对象编程1
    11 python学习笔记-网络编程(使用urlib或request模块请求接口)
    10 python学习笔记-操作数据库
    09 python学习笔记-操作excel
    08 python学习笔记-随机生成大乐透号码
    07 python学习笔记-写一个清理日志的小程序
  • 原文地址:https://www.cnblogs.com/androidxiaoyang/p/2879510.html
Copyright © 2011-2022 走看看