• 连接AdapterView视图和数据源的桥梁:Adapter适配器(3)


    BaseAdapter是一种使用频率较高的适配器,因为它可以通过自定义最大程度扩展满足各种情景下的使用。我们不仅需要知道适配器的使用,进一步我们也需要了解适配器的原理。

    问题是最好的学习方式,下面主要讨论这么几个问题:

    Q1.ListView中每个Item的创建

    Q2.ListView中Item的复用

    Q3.ListView中屏幕显示的Item与复用生成Item之间的关系

      首先写一个简单的demo.

     1 package com.aellenlei.baseadapterdemo;
     2 
     3 import android.support.v7.app.AppCompatActivity;
     4 import android.os.Bundle;
     5 import android.widget.ListView;
     6 
     7 import java.util.ArrayList;
     8 import java.util.List;
     9 
    10 public class MainActivity extends AppCompatActivity {
    11 
    12     @Override
    13     protected void onCreate(Bundle savedInstanceState) {
    14         super.onCreate(savedInstanceState);
    15         setContentView(R.layout.activity_main);
    16 
    17         //1.findViewById
    18         ListView listView = (ListView) findViewById(R.id.listView);
    19 
    20         //2.初始化数据源
    21         List<ItemBean> list = new ArrayList<>();
    22         for (int i = 0; i < 5; i++) {
    23             ItemBean itemBean = new ItemBean();
    24             itemBean.postion = i;
    25             itemBean.title = "title " + i;
    26             itemBean.content = "content " + i;
    27             list.add(itemBean);
    28         }
    29 
    30         //3.初始化适配器
    31         ItemBeanAdapter itemBeanAdapter = new ItemBeanAdapter(list, getApplicationContext());
    32 
    33         //4.ListView绑定适配器
    34         listView.setAdapter(itemBeanAdapter);
    35     }
    36 }
    MainActivity.java
     1 package com.aellenlei.baseadapterdemo;
     2 
     3 import android.content.Context;
     4 import android.util.Log;
     5 import android.view.LayoutInflater;
     6 import android.view.View;
     7 import android.view.ViewGroup;
     8 import android.widget.BaseAdapter;
     9 import android.widget.CheckBox;
    10 import android.widget.ImageView;
    11 import android.widget.TextView;
    12 
    13 import java.util.List;
    14 
    15 /**
    16  * User AellenLei
    17  * NAME ItemBeanAdapter
    18  * DATE 2016/3/7
    19  */
    20 public class ItemBeanAdapter extends BaseAdapter {
    21 
    22     private List<ItemBean> mData;
    23     private Context mContext;
    24 
    25     public ItemBeanAdapter(List<ItemBean> mData, Context mContext) {
    26         this.mData = mData;
    27         this.mContext = mContext;
    28     }
    29 
    30     @Override
    31     public int getCount() {
    32         return mData == null ? 0 : mData.size();
    33     }
    34 
    35     @Override
    36     public ItemBean getItem(int position) {
    37         return mData.get(position);
    38     }
    39 
    40     @Override
    41     public long getItemId(int position) {
    42         return position;
    43     }
    44 
    45     @Override
    46     public View getView(int position, View convertView, ViewGroup parent) {
    47 
    48         Log.d("msg", position + "," + getItem(position).postion + "," + getItem(position).title + ".  "
    49                 + ((convertView == null) ? ("covertView = null") :
    50                 (((TextView) convertView.findViewById(R.id.item_title)).getText().toString()))
    51         );
    52 
    53 
    54         View ret;
    55 
    56         if (convertView != null) {
    57             ret = convertView;
    58         } else {
    59             ret = LayoutInflater.from(mContext).inflate(R.layout.item, null);
    60             ViewHolder holder = new ViewHolder();
    61             holder.itemIcon = (ImageView) ret.findViewById(R.id.item_icon);
    62             holder.itemTitle = (TextView) ret.findViewById(R.id.item_title);
    63             holder.itemContent = (TextView) ret.findViewById(R.id.item_content);
    64             holder.itemDate = (TextView) ret.findViewById(R.id.item_date);
    65             holder.itemChecked = (CheckBox) ret.findViewById(R.id.item_check);
    66             ret.setTag(holder);
    67         }
    68 
    69         ViewHolder viewHolder = (ViewHolder) ret.getTag();
    70 
    71         ItemBean itemBean = getItem(position);
    72 
    73         viewHolder.itemIcon.setImageResource(R.mipmap.ic_launcher);
    74         viewHolder.itemTitle.setText(itemBean.title);
    75         viewHolder.itemContent.setText(itemBean.content);
    76         viewHolder.itemDate.setText("yyyy-MM-dd");
    77         viewHolder.itemChecked.setChecked(itemBean.check);
    78 
    79         return ret;
    80     }
    81 
    82     private static class ViewHolder {
    83         private ImageView itemIcon;
    84         private TextView itemTitle;
    85         private TextView itemContent;
    86         private TextView itemDate;
    87         private CheckBox itemChecked;
    88     }
    89 }
    ItemBeanAdapter
     1 package com.aellenlei.baseadapterdemo;
     2 
     3 /**
     4  * User AellenLei
     5  * NAME ItemBean
     6  * DATE 2016/3/7
     7  */
     8 public class ItemBean {
     9     public int postion;
    10     public String url;
    11     public String title;
    12     public String content;
    13     public String date;
    14     public boolean check;
    15 }
    ItemBean
     1 <?xml version="1.0" encoding="utf-8"?>
     2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     3     xmlns:tools="http://schemas.android.com/tools"
     4     android:layout_width="match_parent"
     5     android:layout_height="match_parent"
     6     android:paddingBottom="@dimen/activity_vertical_margin"
     7     android:paddingLeft="@dimen/activity_horizontal_margin"
     8     android:paddingRight="@dimen/activity_horizontal_margin"
     9     android:paddingTop="@dimen/activity_vertical_margin"
    10     tools:context=".MainActivity">
    11 
    12     <ListView
    13         android:id="@+id/listView"
    14         android:layout_width="match_parent"
    15         android:layout_height="match_parent"/>
    16 </RelativeLayout>
    activity_main.xml
     1 <?xml version="1.0" encoding="utf-8"?>
     2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     3     android:layout_width="match_parent"
     4     android:layout_height="match_parent"
     5     android:padding="8dp">
     6 
     7     <ImageView
     8         android:id="@+id/item_icon"
     9         android:layout_width="wrap_content"
    10         android:layout_height="wrap_content"
    11         android:src="@mipmap/ic_launcher"
    12         android:padding="4dp"/>
    13 
    14     <TextView
    15         android:id="@+id/item_title"
    16         android:layout_width="wrap_content"
    17         android:layout_height="wrap_content"
    18         android:textSize="20sp"
    19         android:textStyle="bold"
    20         android:layout_toRightOf="@id/item_icon"
    21         android:layout_alignTop="@id/item_icon"/>
    22     <TextView
    23         android:id="@+id/item_content"
    24         android:layout_width="wrap_content"
    25         android:layout_height="wrap_content"
    26         android:textSize="16sp"
    27         android:layout_below="@id/item_title"
    28         android:layout_toRightOf="@id/item_icon"
    29         android:layout_alignBottom="@id/item_icon"/>
    30 
    31     <TextView
    32         android:id="@+id/item_date"
    33         android:layout_width="wrap_content"
    34         android:layout_height="wrap_content"
    35         android:layout_toRightOf="@id/item_title"
    36         android:layout_alignParentRight="true"
    37         android:gravity="right"/>
    38     <CheckBox
    39         android:id="@+id/item_check"
    40         android:layout_width="wrap_content"
    41         android:layout_height="wrap_content"
    42         android:text="@null"
    43         android:layout_below="@id/item_date"
    44         android:layout_alignParentRight="true"
    45         android:gravity="center"
    46         android:layout_alignBottom="@id/item_content"/>
    47 </RelativeLayout>
    item.xml

     由于该Demo比较简单,不需多讲相信都可以看懂。

     ItemBeanAdapter.java的getView方法中有这么一句:

      

      分别打印的是ListView中每一个Item在ListView中的位置(默认从0开始,下同),该Item显示的数据源中指定位置数据的poistion和title,convertView是否为空若不为空打印convertView之前显示的title.

     当数据源中的数据条数为5时,Logcat的日志:

      

      UI:

      

     当数据源中的数据条数为10是,Logcat的日志:

      

      UI:

      

      

      根据这两种情况的测试,可以大概回答第一个问题:

    Q1.ListView中每个Item的创建

    A1.Adapter第一次创建的Items的数量是由手机屏幕的大小(可测试)和数据源数据的条数来决定的,也就是屏幕实际显示多少个Item就创建几个item的,不多创建新的item也不少创建新的item,items数量是屏幕实际显示数目的取整。将下面的完整结合来看,第一次创建的Item是最基本的Item,它的数量是确定的,以后新的item无论是向上滑动出现还是向下滑动出现都是复用第一次创建的items中的某个item。

    Q2.ListView中Item的复用

    A2:最核心的代码就是Adapter中的getView方法,它返回的是一个已经绑定好数据的view,而系统仅仅只是将这个view在屏幕的指定位置绘制出来。

      

      代码不是固定死的,当然你可以有自己的写法,但是原理总是相同的:

        A2:当ListView第一次创建一屏幕的items时,covertView始终为null(代码测试很容易得出),所以当covertView为空时,就需要将第一次创建一屏幕的items的每个item“初始化”,这里的“初始化”是将covertView和ViewHolder绑定起来,注意不论是将covertView和ViewHolder绑定起来还是ret和ViewHolder绑定起来,它们的本质是一样的,最后返回值是已经与ViewHolder绑定的View视图,当掌握了covertView的复用写法,可以说是基本上item的复用的写法也掌握了。

        注意下面一种情况,当ListView向上滑动,且item0完全不见,item7和item8出现(下图item8已经出现,只是没有完全显示)的情况:

        

        此时Logcat打印的日志:

          

        根据之前的第一次创建items打印的日志比较:item7仍然是新创建的,但是item8却是复用的,item8复用的是item0(完全根据日志得出的)。(PS 可能此处有疑问,下面会分析)

        A2:当listView向上滑动或者是向下滑动的时候,此时可能会出现item复用的情况(注意此时可能会出现复用的情况,不一定或出现哦)。若covertView不为空,就可以之前在该covertView初始化或复用中通过getTag方法,取出与之绑定的ViewHolder,从而实现减少findViewById的时间,findViewById是需要耗费时间的,当listView显示大量的数据,此时的findViewByid可以极大的提高效率。

        最后分析总结前面的,可以回答第三个问题:

    Q3.ListView中屏幕显示的Item与复用生成Item之间的关系

    A3:ListView实际创建item的数量是由手机屏幕的大小和数据源的数据数量来决定的,准确的将这是不准确的或是错误的。

       ListView在整个复用过程中本质上实际创建item的数量(这里所指的全部是最原始最本质的item)是由手机屏幕的大小、数据源的数据数量和每个item实际的大小来决定的(当然这里不考虑其他更为负责的情况,而是假定每个item的大小相同)。

       用可以唯一衡量确定的话说是:本质上items的数量是当第一个item完全消失后,此时Adapter总共创建的items数量,从本质上来说,这就是ListView在整个复用过程中复用的item的数量。假如从0,1,...,n-1(n为最原始的item数量)来看,当ListView向上滑动时,复用tem的顺序是按顺序复用0,1,...,n-1,每次复用一个;当ListView向下滑动时,复用的顺序是按照逆序的,从n-1,n-2,..,0,也是一个一个复用的。

      当然还有更为复杂的情况或者说从更为本质也就是源码的角度分析,这里暂不考虑,而是从一种最为表象或者最最最基本最最简单来分析ListView与Adapter。

     

  • 相关阅读:
    JavaScript高级程序设计学习笔记事件(一)(事件流、事件处理程序/事件侦听器)
    JavaScript高级程序设计学习笔记事件(二)(事件对象DOM中的事件对象/IE中的事件对象/跨浏览器的事件对象)
    闭包学习小记
    JavaScript高级程序设计学习笔记DOM(一)(节点层次Node类型节点关系/操作节点)
    打印网页内容
    尝试写第一个js插件 图片轮播
    JavaScript高级程序设计学习笔记面向对象的程序设计(一) 创建对象 (工厂模式、构造函数模式、原型模式等)
    jQuery二维码插件 jquery.qrcode.js
    ajax请求地址后加随机数防止浏览器缓存
    location.href 和document.referrer、event.keyCode、setTimeout 与setInterval、前置与后置型递增递减操作符
  • 原文地址:https://www.cnblogs.com/enjoy-coding/p/5252452.html
Copyright © 2020-2023  润新知