Android编程权威指南(第二版)学习笔记(九)—— 第9章 使用 RecyclerView 显示列表

本章主要讲述了 RecyclerView 的基础使用,单例设计模式以及通过抽象的统一的 activity 来托管 fragment(以减少重复代码量)。

GitHub 地址:
完成第九章

1. 单例(SingleInstance)

单例是特殊的 JAVA 类,在创建实例的时候,一个单例类仅允许创建一个实例。应用能在内存里多久,单例就能存在多久,因此将对象列表保存在单例里的话,就能随时获取到数据,而不用管 activity 和 fragment 的生命周期怎么变化。不过当应用被从内存里移除的时候,单例对象就不复存在了。

要创建单例,需要创建一个带有私有构造方法及 get() 方法的类,如果实例已经存在了,get() 方法就直接返回它,如果还不存在,就需要调用构造方法创建它。书上的代码是这样的:

public class CrimeLab {
    //下面这个静态对象只会创建一次
    private static CrimeLab sCrimeLab;
    
    private List<Crime> mCrimes;
    
    //程序的其他部分需要使用时,调用下列方法,当第一次使用的时候创建这个对象,如果不是第一次使用的时候就直接返回静态对象。
    public static CrimeLab get(Context context) {
        if (sCrimeLab == null) {
            sCrimeLab = new CrimeLab(context);
        }
        return sCrimeLab;
    }

    //私有的构造方法,只在 get 方法中使用
    private CrimeLab(Context context) {
        mCrimes = new ArrayList<>();
        //初始化数据的语句
        ………………
    }

    //由于对象只创建了一次,故而数据只有一份
    public List<Crime> getCrimes() {
        return mCrimes;
    }

    public Crime getCrime(UUID id) {
        for (Crime crime : mCrimes) {
            if (crime.getId().equals(id)) {
                return crime;
            }
        }
        return null;
    }
}

单例能方便地控制模型层对象,由一个单例类来控制数据,所有的修改都由它处理,会使数据的一致性控制更加简便。

但是万事总有缺点,

  • 首先,单例无法做到持久的存储,应用的内存被回收时,单例就不复存在了。
  • 其次,单例还不利于单元测试。
  • 最后,单例还容易被滥用,需要注意的是有充足的理由时才使用单例模式存储共享数据。

2. 使用抽象 activity 托管 fragment

由于书中大部分 FragmentActivity 的是类似的,所以可以直接创建一个抽象的类用于被继承,简化代码。

回忆一下使用 fragment 的步骤:

  1. 在托管的 activity 的 onCreate() 方法中新建一个 FragmentManager 对象(getSupportFragmentManager() 方法或者 getFragmentManager() 方法)。
  2. 使用该对象的 findFragmentById() 方法找到放置 fragment 的位置。
  3. 如果 fragment 没有建立,就新建一个 fragment 对象,并使用 FragmentManager 对象的 beginTransaction().add().commit() 的连续方法将 fragment 事务提交到队列中

在这其中,只有新建 fragment 对象是与具体 fragment 有关的,那么我们可以将其写成一个抽象的函数:

protected abstract Fragment createFragment();

3. RecyclerView, Adapter 和 ViewHolder

对于一个列表,之前有 ListView,网格有 GridView,但要实现更加复杂的布局和功能,比如瀑布流的时候,就有些力不从心了。RecyclerView 是 Google 推出 Android 5.0 时一并推出的控件,其具有强大的功能和高度的解耦,有助于开发者实现更加多变具有拓展能力的布局。

3.1 RecyclerView 简介及工作原理

要使用 RecyclerView 显示视图,需要三样东西,即RecyclerView,Adapter, ViewHolder,它们的任务各不相同:

  • RecyclerView 是视图层对象,负责回收和定位屏幕上的 ViewHolder
  • ViewHolder 只负责容纳 View 视图
  • Adapter 是控制器对象,负责创建必要的 ViewHolder,从模型层获取数据并与 ViewHolder 绑定,然后提供给 RecyclerView 显示

RecyclerView 需要显示视图对象时,就会去找它的 Adapter,然后会有如下调用。

  1. 首先,调用 Adapter 的 getItemCount() 方法,RecyclerView 询问数组列表中包含多少个对象。
  2. 接着,调用 Adapter 的 createViewHolder(ViewGroup, int) 方法创建 ViewHolder 以及 ViewHolder 要显示的视图。
  3. 最后,RecyclerView 会传入 ViewHolder 及其位置,调用 onBindViewHolder(ViewHolder, int) 方法。Adapter 会找到目标位置的数据并用数据填充到 ViewHolder 的视图上。

过程图示如下:


这里写图片描述

需要注意的是,相对于 onBindViewHolder(ViewHolder, int) 方法,createViewHolder(ViewGroup, int) 方法的调用并不频繁。一旦创建了够用的 ViewHolder,RecyclerVIew 就会停止调用 createViewHolder() 方法,然后通过回收旧的 ViewHolder 来节约时间和内存。

3.2 使用 RecyclerView

介绍了 RecyclerView 的各种细节,我们来看看它具体怎么使用吧。

3.2.1 添加 RecyclerView 依赖库

在 File - Project Structure 菜单项,选择 app 模块,然后单击 Dependencies 选项页,单击加号,找到并添加 recyclerview-v7 支持库。

3.2.2 在布局文件中使用 RecyclerView 并在 JAVA 代码中声明

示例 JAVA 代码如下:

mCrimeRecyclerView = (RecyclerView) view.findViewById(R.id.crime_recycler_view);
mCrimeRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));

RecyclerView 视图创建完成后,就立即转交给了 LayoutManager 对象。LayoutManager 实际上负责定位列表项和定义屏幕滚动行为,因此如果没有 LayoutManger 的支持,不仅 RecyclerView 无法工作,还会导致应用崩溃。在示例中使用的 LinearLayoutManager 是以竖直列表的方式展示列表项,内置的还有GridLayoutManager ,还有很多第三方的库可以使用。

3.2.3 实现 Adapter 和 ViewHolder

ViewHolder 需要做的事情很简单,就是将自定义的 view 中的组件找出来并绑定在这个 ViewHolder 的成员变量上。

比如定义了一个有标题和图片的 item,那么这个 Holder 可以这么写:

class ItemHolder extends RecyclerView.ViewHolder {
    
    public TextView mTitle;
    public ImageView mImg;
    
    public ItemHolder(View itemView) {
        super(itemView);

        mTitle = (TextView) itemView.findViewById(R.id.tv_item_title);
        mImg = (ImageView) itemView.findViewById(R.id.iv_item_img);
    }
}

如果有监听器的话,也可以写在构造函数中

对于 Adapter 来说,要做的事就更多了,我来一一梳理:

  • 从模型层获取数据
    一般在 Adapter 内部声明一个数据模型的成员变量,在 Adapter 的构造函数中进行初始化

  • 重写 ViewHolder 这个父类的三个方法

    • onCreateViewHolder(ViewGroup parent, int viewType)
      每当 RecyclerView 需要新的 View 视图来显示列表项的时候就会调用这个方法。在这其中,我们创建 View 视图,然后封装到 ViewHolder 中,此时并不需要向视图加载数据。
     //一个典型的 onCreateViewHolder 方法的内部
     LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
     View view = layoutInflater.inflate(R.layout.list_item, parent, false);
     return new ItemHolder(view);
    
  • onBindViewHolder(ItemHolder holder, int position)
    这个方法负责将 ViewHolder 的 View 视图和模型层的数据绑定起来。拿到 ViewHolder 和列表项在数据集中的索引位置后,我们通过索引位置找到要显示的数据进行绑定。绑定完毕后,刷新显示 View 视图。

//典型的 onBindViewHolder 方法内部
Data data = mDataList.get(position); 
// 注意上面的 mDataList 就是在 Adatper 的构造函数中初始化的 Adapter 的成员变量
holder.mTitle.setText(data.getTitle(position));
holder.mImg.setImageResource(data.getImgRes(position));
  • getItemCount()
    返回要展示的数据的数量,一般是数据集的 size

到此一个基本的 Adapter 就创建完了,在主程序中声明并初始化 Adapter,调用 RecyclerView 的 setAdapter 方法即可显示出列表了~


GitHub Page: kniost.github.io
简书:http://www.jianshu.com/u/723da691aa42

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容