• ListView 编程: Adapter 何方神圣?


    本文转自http://blog.csdn.net/androidbluetooth/article/details/6959017

    本来是想用一篇博客一口气写完:如何优化 ListView ,但是我发现这样做吃力不讨好,一方面,自己太累,另一方面给人的感觉是在记账,根本不是在交流。

    最后还是觉得分开写会好一点,每一篇突出一个重点比较好。欢迎交流。

    在这篇博客中,你可以了解到:

    1)Adapter(适配器)模式简介

    2)android Adapter 类简介

    3)android Adapter 与 ListView 之间的关系。

    4)如何自定义 Adapter 以及注意事项

     

    设计模式很抽象,熟练使用各种设计模式需要不断地实践和思考。Adapter,适配器,也是一种设计模式(适配器模式)。

    关于适配器模式,在这里可以打个比方:android 手机需要充电,但是你不可以直接使用 220v 的电压来给它充电除非你恨透了这个设备。那么,我们会使用标准的充电器来给该手机充电(它会进行电压电流的转换),那么这个充电器 就好比 Adapter(适配器)。

    GOF 关于 Adapter 模式是这样解释的:

    将一个类的接口转换成客户希望的另外一个接口。Adapter 模式使原本由于接口不兼容而不能一起工作的那些类可以一起工作。

    当然,这篇博客不是讲解 Adapter 模式的,关于该模式大家可以 GOOGLE 一下。

    android 中 Adapter 是一个接口,api 声明如下:

    该接口有很多间接或者直接的子接口、实现类。

    ListView 在 APP 开发中使用比较频繁,而 Adapter 是 ListView 与数据打交道的桥梁,当列表里的每一项显示到页面时,都会调用Adapter的getView方法返回一个View

    二者的关系可以使用下图简单描述:

    使用 ListView 的同时,一般会使用如 ArrayAdapter、CursorAdapter、SimpleAdapter 来为其添加显示数据。

    ArrayAdapter、CursorAdapter、SimpleAdapter 这三个类直接或者间接的继承了 BaseAdapter(该类是一个抽象类)类。

    BaseAdapter(该类是一个抽象类)类,api 声明如下:

    其中,ListAdapter、SpinnerAdapter 是 Adapter 的子接口。

    一般为了是 UI 更加的人性化更加的美观,设计人员会自己写一个类继承 BaseAdapter。

    那么举一个实例来看看如何实现这个子类,以及需要实现的方法的回调时机。

    Activity 代码

    package mark.zhang;
    
    import android.app.ListActivity;
    import android.os.Bundle;
    
    public class FileActivity extends ListActivity {
        
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            // 实例化自定义Adapter
            FileViewAdapter adapter = new FileViewAdapter(this);
            // 设置适配器
            setListAdapter(adapter);
        }
    }

    FileViewAdapter (自定义 Adapter )代码

    package mark.zhang;
    
    import android.content.Context;
    import android.util.Log;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseAdapter;
    import android.widget.ImageView;
    import android.widget.TextView;
    
    public class FileViewAdapter extends BaseAdapter {
        private LayoutInflater inflater = null;
        
        
        public FileViewAdapter(Context context) {
            inflater = LayoutInflater.from(context);
        }
    
        @Override
        public int getCount() {
            Log.d("mark", "getCount() is invoked!");
            return 10;
        }
    
        @Override
        public Object getItem(int position) {
            Log.d("mark", "getItem() is invoked!");
            return position;
        }
    
        @Override
        public long getItemId(int position) {
            Log.d("mark", "getItemId() is invoked!");
            Log.d("mark", "position = " + position);
            return position;
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            Log.d("mark", "getView() is invoked!");
            
            View v = inflater.inflate(R.layout.custom_fileview, null);
            ImageView image = (ImageView) v.findViewById(R.id.image_pic);
            TextView context = (TextView) v.findViewById(R.id.text_content);
            context.setText("fileName");
            image.setImageResource(R.drawable.file);
            
            return v;
        }
    }

    运行效果如图示:

    那么,重写的那四个方法(@Override),调用情况如下。

    运行该 App 之后,打印信息如下:

    getCount 方法返回需要显示的数据的个数,在 FileViewAdapter 代码中 getCount 方法返回数据为 10(这个数据可以根据实际情况修改)。

    从打印信息来看,getView 方法被调用了 10 次,这也正好说明 getCount 方法返回数据是多少,getView 方法就会被调用多少次。

    再做一个测试,首先退出该 APP,再次启动该 APP,打印信息如下:

    这次可以看出 getItemId 方法没有被调用。那么,何时会再次调用这个方法呢?点击列表中的任意一条数据,这里点击第一条数据,看看打印信息:

    可以看出,getItemId 方法被调用,并且可以看出 ListView 中数据是以 0 开始为索引值的,类似数组的索引。

    那么,思考一个问题,何时调用 getItem 方法呢,在 android 的 BaseAdapter 源码中没有发现直接调用 getItem 方法的代码(看小结吧)。

    更多关于 Adapter 的方法,可以参阅 SDK API 文档。

    小结:

    1. 四个方法的重写 

    FileViewAdapter 继承 BaseAdapter,重写以下四个方法:getCount、getItem、getItemId、getView。

    2. 绘制 ListView

    首先,系统在绘制 ListView 之前,将会先调用 getCount 方法来获取 Item 的个数。之后每绘制一个 Item 就会调用一次 getView 方法(getCount 方法返回几个数据,getView方法 就会被调用几次),getView 方法内就可以使用自定义好的 xml 来确定显示的效果并返回一个 View 对象作为一个 Item 显示出来。

    3. getView、getCount 方法

    在绘制L istView 过程中完成了适配器的主要转换功能,把数据和资源以开发者想要的效果显示出来。重复调用getView,使得 ListView 的使用更为简单和灵活。

    getView、getCount 两个方法是自定 ListView 显示效果中最为重要的,同时只要重写好了就两个方法,ListView 就能完全按开发者的要求显示。

    4. getItem、getItemId 方法

    而 getItem 和 getItemId 方法将会在调用 ListView 的响应方法的时候被调用到。

    在 ListView 的源码中可以看出,很多地方都调用了 getItemId 方法,但是没有直接看到调用 getItem 方法的。那么,我们还是往深层次看吧,从 ListView 源码追踪到 AdapterView 源码,可以看到:

    /**
         * Gets the data associated with the specified position in the list.
         *
         * @param position Which data to get
         * @return The data associated with the specified position in the list
         */
        public Object getItemAtPosition(int position) {
            T adapter = getAdapter();
            return (adapter == null || position < 0) ? null : adapter.getItem(position);
        }
    
        public long getItemIdAtPosition(int position) {
            T adapter = getAdapter();
            return (adapter == null || position < 0) ? INVALID_ROW_ID : adapter.getItemId(position);
        }

    可以看出这两个方法都是 public 的,当我们调用这两个方法时候,就会调用 getItem 或者 getItemId 方法。

    为了保证 ListView 的各个方法有效,这两个方法也得重写。

    附录 -- xml 文件 

    main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="fill_parent"
        android:layout_height="fill_parent">
        <ListView android:id="@android:id/list" android:layout_width="fill_parent"
            android:layout_height="fill_parent" />
    </LinearLayout>

    custom_fileview.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal" android:layout_width="fill_parent"
        android:layout_height="fill_parent">
    
        <ImageView android:id="@+id/image_pic" android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:layout_marginTop="5dip" />
    
        <TextView android:id="@+id/text_content" android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:layout_marginLeft="10dip"
            android:textSize="20sp" />
    
    </LinearLayout>

    在这篇博客中,可以看出 getView 方法反复的被调用,从而产生很多对象,当数据量很大的的时候上面的做法效率肯定高不了,那么,如何优化呢?且听下回分解!

     

     

     

     

  • 相关阅读:
    python基础_字典_列表_元组考试_day4
    基本数据类型-列表_元组_字典_day4
    python基础-基本数据类型总结_整型(int)_字符型(str)_day3
    python基础-range用法_python2.x和3.x的区别
    python基础--基本数据类型考试_day3
    批量创建文件和修改文件
    批量建立用户及密码
    打印九九乘法表
    Error Code : 1456 Recursive limit 0 (as set by the max_sp_recursion_depth variable) was exceeded for routine pro_app_rs_right_update···
    mysql 创建视图出现1349 View's SELECT contains a subquery in the FROM clause解决办法
  • 原文地址:https://www.cnblogs.com/sishuiliuyun/p/2738779.html
Copyright © 2020-2023  润新知