美文网首页
【Android】我讨厌“Adapter”这个单词!!!(一)

【Android】我讨厌“Adapter”这个单词!!!(一)

作者: Xxxxx面 | 来源:发表于2015-11-15 21:42 被阅读274次

    在《第一行代码》第三章第5节,介绍了“最难用的控件”ListView,其中的ArrayAdapter尤其让我感觉头痛。我就是记不住到底怎么写这个鬼东西的代码,为了理清思绪,现在以这篇博文边记录边学习关于“Adapter”的一些事。

    为什么要有Adapter这样的东西啊?

    根据《第一行代码》所讲的,我们的ListView需要显示在手机的数据很多,而且可能是从网上下载的,可能是从数据库读取的。因此应该先把这么大量的数据准备好,再进行展示,这就需要数据和ListView之间有个“桥梁”,Adapter就是起到这个作用。

    官方原话是这样的:

    An Adapter object acts as a bridge between an AdapterView and the underlying data for that view. The Adapter provides access to the data items. The Adapter is also responsible for making a View for each item in the data set.

    按照我的烂英语理解,Adapter就是为"AdapterView的子类"和"需要显示的数据"充当桥梁,让"AdapterView的子类"能够拿到数据项的内容,并且它还负责给每个数据项目返回view视图。

    来,说说最简单的Adapter用法吧。

    按照《第一行代码》3.5.1节那样,只显示最简单的字符串ListView。截取核心的代码如下:

    public class MainActivity extends Activity {
    
        String[] s = {"AAA", "AAA", "AAA", "AAA", "AAA", "AAA", "AAA", "AAA"};
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            ListView listView = (ListView) findViewById(R.id.listView);
            ArrayAdapter adapter = new ArrayAdapter(MainActivity.this,android.R.layout.simple_expandable_list_item_1,s);
            listView.setAdapter(adapter);
        }
    
    }
    

    其中,最重要的就是那句:
    new ArrayAdapter(MainActivity.this,android.R.layout.simple_expandable_list_item_1,s)
    这里有三个参数,分别代表:
    1. 当前上下文 (The current context.)
    2. 子项布局的id (The resource ID for a layout file containing a TextView to use when instantiating views.)
    3. 要适配的数据 (The objects to represent in the ListView.)

    我自己记Adapter这个东西,就是"视图 - 桥梁 - 数据"这样记的。
    上面的代码已经有这样的雏形了,最难搞的就是new ArrayAdapter的那几个参数。

    那我暂时就这样记忆咯:
    我是图书馆其中一名管理员,现在要把某些书籍按要求放回书架。
    ListView就像图书馆的书架,我就是Adapter,那些书就是数据。
    我(这些书要放回哪个类别的区域,按照横或者竖的方式,放哪些书回去);
    我推着装满书的小车,把书按指定的方式放回了指定区域的书架上面。

    额……如果是复杂一点的情况呢?

    复杂一点,有图有文字,显示成下面这个样子呢?



    还是先截取核心的代码如下:

    public class FruitArrayAdapter extends ArrayAdapter {
    
        private int resourceId;
    
        public FruitArrayAdapter(Context context, int textViewResourceId, List<Fruit> objects) {
            super(context, textViewResourceId, objects);
            resourceId = textViewResourceId;
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            Fruit fruit = (Fruit) getItem(position);
            View view = LayoutInflater.from(getContext()).inflate(resourceId,null);
            ImageView fruitIamge = (ImageView) view.findViewById(R.id.fruitImage);
            TextView fruitText = (TextView) view.findViewById(R.id.fruitText);
            fruitIamge.setImageResource(fruit.getImageId());
            fruitText.setText(fruit.getName());
            return view;
        }
    }
    
    fruitArrayAdapter = new FruitArrayAdapter(MainActivity.this,R.layout.fruit_listview,fruitList);
    

    可以看到,因为要显示的内容复杂了,所以需要定义我自己的布局文件R.layout.fruit_listview
    并且我还要知道怎么放这些数据(定义自己的Adapter)。
    这其中最难记的就是那个FruitAdapter,记很多次我都会忘掉。
    为了解决这个问题,继续深入一下ArrayAdapter这个类。

    一些关于ArrayAdapter的事

    先来看一下官方描述:

    A concrete BaseAdapter that is backed by an array of arbitrary objects. By default this class expects that the provided resource id references a single TextView. If you want to use a more complex layout, use the constructors that also takes a field id. That field id should reference a TextView in the larger layout resource.

    However the TextView is referenced, it will be filled with the toString() of each object in the array. You can add lists or arrays of custom objects. Override the toString() method of your objects to determine what text will be displayed for the item in the list.

    To use something other than TextViews for the array display, for instance, ImageViews, or to have some of data besides toString() results fill the views, override getView(int, View, ViewGroup) to return the type of view you want.

    根据我的烂英语,这段话能够得到一下一些信息:

    1.ArrayAdapter是BaseAdapter的子类,用来支持一个放任意对象的数组。

    2.默认情况它就是让你传一个TextView的资源id而已,类似与那个系统提供的android.R.layout.simple_expandable_list_item_1

    3.如果想要稍微不一样的布局(还是只显示字符的),
    就把一个复杂一点点的layout文件的id传入ArrayAdapter的构造方法,
    注意这个layout文件就只有一个<TextView/>标签,样式你自己定吧。
    (这个可能我理解有误,但参考android.R.layout.simple_expandable_list_item_1的代码,
    确实是这样的情况。)

    <TextView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/tv_users"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    

    4.上面这些做法,会将对象的toString()方法中的输出作为显示内容。如果想要好看一点,就重写那个对象的toString()方法吧。

    5.如果要显示<TextView>以外的控件,像有个<ImageVIew>之类的,就要重写Adapter的getVIew(int,View,ViewGroup)方法来得到你想要的布局咯。

    那么重写ArrayAdapter要记住哪些东西呢?

    上面已经贴过代码了,而且还提到,要重写getVIew(int,View,ViewGroup)方法。
    《第一行代码》中的FruitAdapter,除了重写了getVIew(int,View,ViewGroup)
    还重写了FruitAdapter的构造方法,public FruitArrayAdapter(Context context, int textViewResourceId, List<Fruit> objects) {…… ,为什么呢?

    是为了得到第二个参数,textViewResourceId
    就是ListView子项布局的id,其实就是R.layout.fruit_item文件。
    注意这个文件定义的,是ListView一个item的布局,
    不是整个ListView的样子,不要思维混乱了。
    又回到"视图 - 桥梁 - 数据"这个关系,因为现在就在"桥梁"中,
    所以,是真正要我们自己来进行这个"视图 - 数据"的对接工作了。
    既然,已经得到了"一个item的布局",那就是"视图"有了,就差"数据"。

    怎么得到某一项item的数据呢?
    利用getVIew(int,View,ViewGroup)第一个参数position,
    getItem(position),也就是this.getItem(position)
    也就是在调用这个FruitAdaptergetItem(position)方法,
    也就是调用ArrayAdaptergetItem(position)方法。

    ArrayAdapter的getItem方法源码:

     public T getItem(int position) {
            return mObjects.get(position);
        }
    

    也就是通过ArrayAdapter里面那个List<T> mObjects对象,
    得到它某一项的内容,最后再通过LayoutInflater,把数据桥接起来。

    来聊一聊ArrayAdapter那些构造方法

    当时我照着《第一行代码》敲FruitAdapter的时候,
    我就想为什么要重写这个构造方法?这个构造方法参数代表什么?
    结果一看就晕了,ArrayAdapter居然有六个构造方法:

    不过,仔细观察,其实就只有四个参数互相组合:
    1.context : The current context.
    2.resource : The resource ID for a layout file containing a layout to use when instantiating views.
    3.textViewResourceId : The id of the TextView within the layout resource to be populated
    4.objects : The objects to represent in the ListView.

    还是我的烂英语:
    1.上下文
    2.你要用在这个ListView的layout文件的id,这里也就是R.layout.listview之类的
    3.在上面这个R.layout.listview里面的TextView的id
    4.你要显示的那些数据

    我上机弄来弄去,还是不知道第三个参数存在的意义,
    如果不止一个TextView,那怎么办呢?
    感觉只要记住《第一行代码》那种写法就行了。

    希望有看到这篇博文的朋友,告诉我一下吧……
    有点长了,下篇继续交流吧。

    参考资料

    1.Android杂谈--ListView之BaseAdapter的使用 by 花郎V
    2.官方ArrayAdapter解释
    3.关于ArrayAdapter两个构造函数的区别
    4.ArrayAdapter构造方法参数的问题,我脑袋要炸了。 ...

    相关文章

      网友评论

          本文标题:【Android】我讨厌“Adapter”这个单词!!!(一)

          本文链接:https://www.haomeiwen.com/subject/gajkhttx.html