Android編程權(quán)威指南(第二版)學(xué)習(xí)筆記(九)—— 第9章 使用 RecyclerView 顯示列表

本章主要講述了 RecyclerView 的基礎(chǔ)使用,單例設(shè)計(jì)模式以及通過抽象的統(tǒng)一的 activity 來托管 fragment(以減少重復(fù)代碼量)。

GitHub 地址:
完成第九章

1. 單例(SingleInstance)

單例是特殊的 JAVA 類,在創(chuàng)建實(shí)例的時(shí)候绊谭,一個(gè)單例類僅允許創(chuàng)建一個(gè)實(shí)例。應(yīng)用能在內(nèi)存里多久,單例就能存在多久程拭,因此將對象列表保存在單例里的話,就能隨時(shí)獲取到數(shù)據(jù)棍潘,而不用管 activity 和 fragment 的生命周期怎么變化恃鞋。不過當(dāng)應(yīng)用被從內(nèi)存里移除的時(shí)候,單例對象就不復(fù)存在了亦歉。

要?jiǎng)?chuàng)建單例恤浪,需要?jiǎng)?chuàng)建一個(gè)帶有私有構(gòu)造方法及 get() 方法的類,如果實(shí)例已經(jīng)存在了肴楷,get() 方法就直接返回它水由,如果還不存在,就需要調(diào)用構(gòu)造方法創(chuàng)建它赛蔫。書上的代碼是這樣的:

public class CrimeLab {
    //下面這個(gè)靜態(tài)對象只會創(chuàng)建一次
    private static CrimeLab sCrimeLab;
    
    private List<Crime> mCrimes;
    
    //程序的其他部分需要使用時(shí)砂客,調(diào)用下列方法,當(dāng)?shù)谝淮问褂玫臅r(shí)候創(chuàng)建這個(gè)對象呵恢,如果不是第一次使用的時(shí)候就直接返回靜態(tài)對象鞠值。
    public static CrimeLab get(Context context) {
        if (sCrimeLab == null) {
            sCrimeLab = new CrimeLab(context);
        }
        return sCrimeLab;
    }

    //私有的構(gòu)造方法,只在 get 方法中使用
    private CrimeLab(Context context) {
        mCrimes = new ArrayList<>();
        //初始化數(shù)據(jù)的語句
        ………………
    }

    //由于對象只創(chuàng)建了一次渗钉,故而數(shù)據(jù)只有一份
    public List<Crime> getCrimes() {
        return mCrimes;
    }

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

單例能方便地控制模型層對象齿诉,由一個(gè)單例類來控制數(shù)據(jù),所有的修改都由它處理,會使數(shù)據(jù)的一致性控制更加簡便粤剧。

但是萬事總有缺點(diǎn)歇竟,

  • 首先,單例無法做到持久的存儲抵恋,應(yīng)用的內(nèi)存被回收時(shí)焕议,單例就不復(fù)存在了。
  • 其次弧关,單例還不利于單元測試盅安。
  • 最后,單例還容易被濫用世囊,需要注意的是有充足的理由時(shí)才使用單例模式存儲共享數(shù)據(jù)别瞭。

2. 使用抽象 activity 托管 fragment

由于書中大部分 FragmentActivity 的是類似的,所以可以直接創(chuàng)建一個(gè)抽象的類用于被繼承株憾,簡化代碼蝙寨。

回憶一下使用 fragment 的步驟:

  1. 在托管的 activity 的 onCreate() 方法中新建一個(gè) FragmentManager 對象(getSupportFragmentManager() 方法或者 getFragmentManager() 方法)。
  2. 使用該對象的 findFragmentById() 方法找到放置 fragment 的位置嗤瞎。
  3. 如果 fragment 沒有建立墙歪,就新建一個(gè) fragment 對象,并使用 FragmentManager 對象的 beginTransaction().add().commit() 的連續(xù)方法將 fragment 事務(wù)提交到隊(duì)列中

在這其中贝奇,只有新建 fragment 對象是與具體 fragment 有關(guān)的虹菲,那么我們可以將其寫成一個(gè)抽象的函數(shù):

protected abstract Fragment createFragment();

3. RecyclerView, Adapter 和 ViewHolder

對于一個(gè)列表,之前有 ListView掉瞳,網(wǎng)格有 GridView毕源,但要實(shí)現(xiàn)更加復(fù)雜的布局和功能,比如瀑布流的時(shí)候陕习,就有些力不從心了脑豹。RecyclerView 是 Google 推出 Android 5.0 時(shí)一并推出的控件,其具有強(qiáng)大的功能和高度的解耦衡查,有助于開發(fā)者實(shí)現(xiàn)更加多變具有拓展能力的布局瘩欺。

3.1 RecyclerView 簡介及工作原理

要使用 RecyclerView 顯示視圖,需要三樣?xùn)|西拌牲,即RecyclerView俱饿,Adapter, ViewHolder塌忽,它們的任務(wù)各不相同:

  • RecyclerView 是視圖層對象拍埠,負(fù)責(zé)回收和定位屏幕上的 ViewHolder
  • ViewHolder 只負(fù)責(zé)容納 View 視圖
  • Adapter 是控制器對象,負(fù)責(zé)創(chuàng)建必要的 ViewHolder土居,從模型層獲取數(shù)據(jù)并與 ViewHolder 綁定枣购,然后提供給 RecyclerView 顯示

RecyclerView 需要顯示視圖對象時(shí)嬉探,就會去找它的 Adapter,然后會有如下調(diào)用棉圈。

  1. 首先涩堤,調(diào)用 Adapter 的 getItemCount() 方法,RecyclerView 詢問數(shù)組列表中包含多少個(gè)對象分瘾。
  2. 接著胎围,調(diào)用 Adapter 的 createViewHolder(ViewGroup, int) 方法創(chuàng)建 ViewHolder 以及 ViewHolder 要顯示的視圖。
  3. 最后德召,RecyclerView 會傳入 ViewHolder 及其位置白魂,調(diào)用 onBindViewHolder(ViewHolder, int) 方法。Adapter 會找到目標(biāo)位置的數(shù)據(jù)并用數(shù)據(jù)填充到 ViewHolder 的視圖上上岗。

過程圖示如下:


這里寫圖片描述

需要注意的是福荸,相對于 onBindViewHolder(ViewHolder, int) 方法,createViewHolder(ViewGroup, int) 方法的調(diào)用并不頻繁肴掷。一旦創(chuàng)建了夠用的 ViewHolder敬锐,RecyclerVIew 就會停止調(diào)用 createViewHolder() 方法,然后通過回收舊的 ViewHolder 來節(jié)約時(shí)間和內(nèi)存捆等。

3.2 使用 RecyclerView

介紹了 RecyclerView 的各種細(xì)節(jié),我們來看看它具體怎么使用吧续室。

3.2.1 添加 RecyclerView 依賴庫

在 File - Project Structure 菜單項(xiàng)栋烤,選擇 app 模塊,然后單擊 Dependencies 選項(xiàng)頁挺狰,單擊加號明郭,找到并添加 recyclerview-v7 支持庫。

3.2.2 在布局文件中使用 RecyclerView 并在 JAVA 代碼中聲明

示例 JAVA 代碼如下:

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

RecyclerView 視圖創(chuàng)建完成后丰泊,就立即轉(zhuǎn)交給了 LayoutManager 對象薯定。LayoutManager 實(shí)際上負(fù)責(zé)定位列表項(xiàng)和定義屏幕滾動行為,因此如果沒有 LayoutManger 的支持瞳购,不僅 RecyclerView 無法工作话侄,還會導(dǎo)致應(yīng)用崩潰。在示例中使用的 LinearLayoutManager 是以豎直列表的方式展示列表項(xiàng)学赛,內(nèi)置的還有GridLayoutManager 年堆,還有很多第三方的庫可以使用。

3.2.3 實(shí)現(xiàn) Adapter 和 ViewHolder

ViewHolder 需要做的事情很簡單盏浇,就是將自定義的 view 中的組件找出來并綁定在這個(gè) ViewHolder 的成員變量上变丧。

比如定義了一個(gè)有標(biāo)題和圖片的 item,那么這個(gè) 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);
    }
}

如果有監(jiān)聽器的話绢掰,也可以寫在構(gòu)造函數(shù)中

對于 Adapter 來說痒蓬,要做的事就更多了童擎,我來一一梳理:

  • 從模型層獲取數(shù)據(jù)
    一般在 Adapter 內(nèi)部聲明一個(gè)數(shù)據(jù)模型的成員變量,在 Adapter 的構(gòu)造函數(shù)中進(jìn)行初始化

  • 重寫 ViewHolder 這個(gè)父類的三個(gè)方法

    • onCreateViewHolder(ViewGroup parent, int viewType)
      每當(dāng) RecyclerView 需要新的 View 視圖來顯示列表項(xiàng)的時(shí)候就會調(diào)用這個(gè)方法攻晒。在這其中顾复,我們創(chuàng)建 View 視圖,然后封裝到 ViewHolder 中炎辨,此時(shí)并不需要向視圖加載數(shù)據(jù)捕透。
     //一個(gè)典型的 onCreateViewHolder 方法的內(nèi)部
     LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
     View view = layoutInflater.inflate(R.layout.list_item, parent, false);
     return new ItemHolder(view);
    
  • onBindViewHolder(ItemHolder holder, int position)
    這個(gè)方法負(fù)責(zé)將 ViewHolder 的 View 視圖和模型層的數(shù)據(jù)綁定起來。拿到 ViewHolder 和列表項(xiàng)在數(shù)據(jù)集中的索引位置后碴萧,我們通過索引位置找到要顯示的數(shù)據(jù)進(jìn)行綁定乙嘀。綁定完畢后,刷新顯示 View 視圖破喻。

//典型的 onBindViewHolder 方法內(nèi)部
Data data = mDataList.get(position); 
// 注意上面的 mDataList 就是在 Adatper 的構(gòu)造函數(shù)中初始化的 Adapter 的成員變量
holder.mTitle.setText(data.getTitle(position));
holder.mImg.setImageResource(data.getImgRes(position));
  • getItemCount()
    返回要展示的數(shù)據(jù)的數(shù)量虎谢,一般是數(shù)據(jù)集的 size

到此一個(gè)基本的 Adapter 就創(chuàng)建完了,在主程序中聲明并初始化 Adapter曹质,調(diào)用 RecyclerView 的 setAdapter 方法即可顯示出列表了~


GitHub Page: kniost.github.io
簡書:http://www.reibang.com/u/723da691aa42

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末婴噩,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子羽德,更是在濱河造成了極大的恐慌几莽,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宅静,死亡現(xiàn)場離奇詭異章蚣,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)姨夹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門纤垂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人磷账,你說我怎么就攤上這事峭沦。” “怎么了逃糟?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵吼鱼,是天一觀的道長。 經(jīng)常有香客問我绰咽,道長蛉抓,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任剃诅,我火速辦了婚禮巷送,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘矛辕。我一直安慰自己笑跛,他們只是感情好付魔,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著飞蹂,像睡著了一般几苍。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上陈哑,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天妻坝,我揣著相機(jī)與錄音,去河邊找鬼惊窖。 笑死刽宪,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的界酒。 我是一名探鬼主播圣拄,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼毁欣!你這毒婦竟也來了庇谆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤凭疮,失蹤者是張志新(化名)和其女友劉穎饭耳,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體执解,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡寞肖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了材鹦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片逝淹。...
    茶點(diǎn)故事閱讀 40,090評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡耕姊,死狀恐怖桶唐,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情茉兰,我是刑警寧澤尤泽,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站规脸,受9級特大地震影響坯约,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜莫鸭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一闹丐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧被因,春花似錦卿拴、人聲如沸衫仑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽文狱。三九已至,卻和暖如春缘挽,著一層夾襖步出監(jiān)牢的瞬間瞄崇,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工壕曼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留苏研,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓窝稿,卻偏偏與公主長得像楣富,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子伴榔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,166評論 25 707
  • 內(nèi)容抽屜菜單ListViewWebViewSwitchButton按鈕點(diǎn)贊按鈕進(jìn)度條TabLayout圖標(biāo)下拉刷新...
    皇小弟閱讀 46,766評論 22 665
  • 一周總結(jié) 1.快樂痛苦四原則:好消息要分開說纹蝴,壞消息要一起說,小好大壞分開說踪少,大好小壞一起說塘安。 2.五商派寫作心法...
    臨淄茂業(yè)DDM王春梅閱讀 91評論 0 0
  • 9月7日晚,陜西榆林官方公布產(chǎn)婦墜樓事件初步調(diào)查結(jié)果: 1 該產(chǎn)婦入院診斷明確援奢、產(chǎn)前告之手續(xù)完善兼犯、診療措施合理、搶...
    胡勇波閱讀 9,234評論 0 1
  • 對戲曲的愛來的有點(diǎn)莫名其妙。 那樣粉白的圍墻具篇,桃花從墻里邊伸出來纬霞,銀鐲碧玉一陣叮叮當(dāng)當(dāng)?shù)捻憽?剛起床梳洗完畢的女子...
    公子薛薛閱讀 249評論 0 2