RecyclerView -- 給你一個(gè)不卡的滑動(dòng)列表


看完此文章 你就會(huì)學(xué)到什么...

  • RecyclerView添加頭部,尾部,或list列表中某位置添加view
  • RecyclerView+SwipeRefreshLayout 實(shí)現(xiàn)上下拉刷新效果
  • 分頁加載數(shù)據(jù)
  • 列表優(yōu)化方案
  • 利用Glide加載圖片擂送,滑動(dòng)的時(shí)候按back鍵啊胶,App會(huì)crash蹦掉處理炮捧。

添加依賴

    //recyclerview
    compile 'com.android.support:recyclerview-v7:25.1.1'
    //glide
    compile 'com.github.bumptech.glide:glide:3.7.0'

    //butterknife 注意需要在三個(gè)第三添加代碼
    //1 module gradle里面底部添加
    compile 'com.jakewharton:butterknife:8.5.1'
    annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1'
    //2 module gradle 里面頂部添加
    apply plugin: 'com.jakewharton.butterknife'
    //3 在project gradle里面添加
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.3'
        classpath 'com.jakewharton:butterknife-gradle-plugin:8.5.1'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }

RecyclerView 任意位置添加view

RecyclerView中有以下三個(gè)函數(shù):

  1. getItemCount --得到列表中Item的總個(gè)數(shù)

  2. getItemViewType(int position)--決定布局使用哪一種類型,返回一個(gè)int型標(biāo)志position唬血,傳遞給onCreateViewHolder的第二個(gè)參數(shù)。
    通俗說:一個(gè)列表有很多個(gè)Item唤崭,每個(gè)Item都可以是自己的一個(gè)自定義的布局且每個(gè)都會(huì)有一個(gè)唯一的位置拷恨,可以通過Item中的位置position標(biāo)志,規(guī)定這個(gè)position將會(huì)返回的Item的布局類型谢肾。例如:

@Override
    public int getItemViewType(int position) {
        if (position == 0) {
            return TYPE_HEAD;
        } else if (position + 1 == getItemCount()) {
            return TYPE_FOOTER;
        } else {
            return TYPE_ITEM;
        }
    }

3.onCreateViewHolder(ViewGroup parent, int viewType) 依據(jù)getItemViewType返回的每個(gè)position位置所返回的布局類型腕侄,去渲染具體的ViewHolder 。例如:

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == TYPE_HEAD) {   
            View view = LayoutInflater.from(context).inflate(R.layout.recycler_view_discover_head, parent, false);
            return new HeadViewHolder(view);
        } else if (viewType == TYPE_ITEM) {
            View view = LayoutInflater.from(context).inflate(R.layout.recycler_view_discover_base, parent, false);
            return new ItemViewHolder(view);
        } else if (viewType == TYPE_FOOTER) {
            View view = LayoutInflater.from(context).inflate(R.layout.recycler_view_discover_foot, parent, false);
            return new FootViewHolder(view);
        }
        return null;
    } 

RecyclerView+SwipeRefreshLayout 實(shí)現(xiàn)上下拉刷新效果

xml如下布局

    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/swipeRefreshLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/discover_recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scrollbars="vertical" />
    </android.support.v4.widget.SwipeRefreshLayout>

用法

 //進(jìn)入界面時(shí)候顯示動(dòng)畫
 swipeRefreshLayout.post(new Runnable() {
            @Override
            public void run() {
                swipeRefreshLayout.setRefreshing(false); 
            }
        });

//每次下拉刷新時(shí)候加載刷新數(shù)據(jù)
        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                if (!isLoading) {
                    isLoading = true;
                    data.clear();
                    getData();
                }
            }
        });

利用了SwipeRefreshLayout實(shí)現(xiàn)了下拉數(shù)據(jù)刷新功能芦疏,而上拉加載數(shù)據(jù)是利用RecyclerView的

    public abstract static class OnScrollListener {
       //newState 參數(shù)有:
       //  SCROLL_STATE_TOUCH_SCROLL(1) 正在滾動(dòng)      
       // SCROLL_STATE_FLING(2) 手指做了拋的動(dòng)作(手指離開屏幕前冕杠,用力滑了一下)      
       // SCROLL_STATE_IDLE(0) 停止?jié)L動(dòng)     
        public void onScrollStateChanged(RecyclerView recyclerView, int newState){}

       //滾動(dòng)時(shí)一直回調(diào),直到停止?jié)L動(dòng)時(shí)才停止回調(diào)酸茴。單擊時(shí)回調(diào)一次
        public void onScrolled(RecyclerView recyclerView, int dx, int dy){}
    }

分頁加載數(shù)據(jù)&&列表優(yōu)化方案(思想編程)

分頁加載:
實(shí)際就是每次上拉分预,然后將數(shù)據(jù)加進(jìn)list集合里面,而獲取特定數(shù)據(jù)的控制薪捍,就是從頁碼來笼痹,每次上拉都將page頁碼加一放到請求參數(shù)里面配喳,而每次下拉,將list集合的數(shù)據(jù)清除凳干,將page還原成原來的1晴裹,請求到的數(shù)據(jù)放進(jìn)list里面。

列表優(yōu)化方案:
1.布局方面纺座,盡量少點(diǎn)組件嵌套息拜,盡量多用LinearLayout,少用RelativeLayout之類的净响,因?yàn)镽elativeLayout渲染時(shí)候需要需要資源較多少欺。
2.圖片優(yōu)化,建議使用現(xiàn)有的圖片框架馋贤,例如 Glide赞别,Picasso,F(xiàn)resco配乓,ImageLoader 等的開源框架仿滔,因?yàn)槔锩婧芎玫姆庋b了圖片緩存機(jī)制,以及沒用時(shí)候犹芹,或者用頻率少的時(shí)候崎页,那圖片緩存會(huì)優(yōu)先被回收。
3.圖片加載. 當(dāng)列表滑動(dòng)時(shí)候腰埂,將圖片用占位圖片顯示飒焦,或則圖片完全不顯示來處理,等滑動(dòng)停止后屿笼,再加載牺荠。本demo用Glide,結(jié)合RecyclerView.OnScrollListener 來處理圖片加載的驴一。具體看demo源碼休雌。
4.每次分頁加載數(shù)據(jù),數(shù)據(jù)添加進(jìn)List的時(shí)間(也可以說是網(wǎng)絡(luò)請求數(shù)據(jù)的時(shí)間最好在什么時(shí)候)肝断,經(jīng)過本人研究了bilibili安卓App和其它App列表滑動(dòng)流暢度的對(duì)比杈曲,bilibili是滑動(dòng)最不卡最流暢的,為什么這樣呢胸懈?實(shí)際上是因?yàn)榉猪摃r(shí)網(wǎng)絡(luò)請求數(shù)據(jù)的開始時(shí)間決定的鱼蝉。在RecyclerView.OnScrollListener 的onScrolled滑動(dòng)事件中處理。
下面代碼中有個(gè) 5 箫荡,它就是代碼的滑動(dòng)流暢的關(guān)鍵魁亦,也可以不一定是5,按實(shí)際需要寫羔挡。

@Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                int lastVisibleItemPosition = linearLayoutManager.findLastVisibleItemPosition();
                if (lastVisibleItemPosition + 5 >= adapter.getItemCount()) {
                    boolean isRefreshing = swipeRefreshLayout.isRefreshing();
                    if (isRefreshing) {
                        adapter.notifyItemRemoved(adapter.getItemCount());
                        return;
                    }
                    if (!isLoading) {        
                        isLoading = true;
                        getData();
                    }
                }
            }

這樣的優(yōu)化優(yōu)點(diǎn):滑動(dòng)特別流暢  缺點(diǎn):可能因?yàn)槠聊坏拇笮〔灰欢虞d開始時(shí)間不同洁奈,還有的就是你體驗(yàn)不到上拉加載數(shù)據(jù)的動(dòng)畫感(上拉加載更多.. 這樣的字你就難看到了间唉,不過網(wǎng)絡(luò)慢的時(shí)候,還是可以看到的)~利术。

利用Glide加載圖片呈野,滑動(dòng)的時(shí)候按back鍵,App會(huì)crash蹦掉處理印叁。

剛所說的列表滑動(dòng)優(yōu)化處理被冒,而我自己就隨便用了個(gè)Glide去加載圖片,可以看到轮蜕,在一瞬間滑動(dòng)昨悼,然后我按back鍵退出的時(shí)候,App會(huì)crash蹦掉跃洛,why率触?why?why汇竭?why葱蝗? due to “You cannot start a load for a destroyed activity”。


原因的出處是因?yàn)槲以诨瑒?dòng)那里做的圖片滑動(dòng)時(shí)停止加載细燎,停止時(shí)加載圖片導(dǎo)致的,“You cannot start a load for a destroyed activity”,說白了就是activity在你按back鍵時(shí)候已經(jīng)銷毀了两曼,而那個(gè)滾動(dòng)事件的Glide圖片處理事件還在執(zhí)行。

  mOnScrollListener = new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                switch (newState) {
                    case SCROLL_STATE_IDLE:
                        Glide.with(MainActivity.this).resumeRequests();
                        break;
                    case SCROLL_STATE_DRAGGING:
                    case SCROLL_STATE_SETTLING:
                        Glide.with(MainActivity.this).pauseRequests();
                        break;
                }
            }

解決問題:

  1. 嘗試在每個(gè)Glide使用前判斷玻驻,而且在activity的onDestory方法里寫上如下悼凑,解決問題失敗击狮! 博客鏈接:http://blog.csdn.net/a940659387/article/details/50555327
if(Util.isOnMainThread()) {
            Glide.with(this).pauseRequest();
        }
  1. 嘗試在每個(gè)Glide使用時(shí)候佛析,this改成getApplicationContext()益老,依然crash彪蓬! 博客鏈接:http://www.reibang.com/p/4a3177b57949
Glide.with(this).resumeRequests();  
  1. 我使用的推薦成功可以完美oknice的方法,不在Glide那里下手捺萌,在滾動(dòng)那里下手档冬。 Get something: 思維轉(zhuǎn)變,別一直糾纏Glide那里桃纯。
 @Override
    protected void onPause() {
        recyclerView.removeOnScrollListener(mOnScrollListener);
        super.onPause();
    }

僅供學(xué)習(xí)使用 提供思路酷誓,具體實(shí)現(xiàn)還是得按照自己業(yè)務(wù)邏輯處理

源碼地址
https://github.com/androidHRTZ/SuperRecyclerView.git

轉(zhuǎn)載請?jiān)陂_頭注明作者詳細(xì)信息和本文出處 謝謝

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市态坦,隨后出現(xiàn)的幾起案子盐数,更是在濱河造成了極大的恐慌,老刑警劉巖伞梯,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件玫氢,死亡現(xiàn)場離奇詭異帚屉,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)漾峡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門攻旦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人生逸,你說我怎么就攤上這事牢屋。” “怎么了槽袄?”我有些...
    開封第一講書人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵烙无,是天一觀的道長。 經(jīng)常有香客問我掰伸,道長皱炉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任狮鸭,我火速辦了婚禮合搅,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘歧蕉。我一直安慰自己灾部,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開白布惯退。 她就那樣靜靜地躺著赌髓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪催跪。 梳的紋絲不亂的頭發(fā)上锁蠕,一...
    開封第一講書人閱讀 51,763評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音懊蒸,去河邊找鬼荣倾。 笑死,一個(gè)胖子當(dāng)著我的面吹牛骑丸,可吹牛的內(nèi)容都是我干的舌仍。 我是一名探鬼主播,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼通危,長吁一口氣:“原來是場噩夢啊……” “哼铸豁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起菊碟,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤节芥,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后逆害,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體头镊,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡增炭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了拧晕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片隙姿。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖厂捞,靈堂內(nèi)的尸體忽然破棺而出输玷,到底是詐尸還是另有隱情,我是刑警寧澤靡馁,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布欲鹏,位于F島的核電站,受9級(jí)特大地震影響臭墨,放射性物質(zhì)發(fā)生泄漏赔嚎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一胧弛、第九天 我趴在偏房一處隱蔽的房頂上張望尤误。 院中可真熱鬧,春花似錦结缚、人聲如沸损晤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽尤勋。三九已至,卻和暖如春茵宪,著一層夾襖步出監(jiān)牢的瞬間最冰,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來泰國打工稀火, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留暖哨,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓憾股,卻偏偏與公主長得像鹿蜀,于是被迫代替她去往敵國和親箕慧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子服球,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,190評(píng)論 25 707
  • 內(nèi)容抽屜菜單ListViewWebViewSwitchButton按鈕點(diǎn)贊按鈕進(jìn)度條TabLayout圖標(biāo)下拉刷新...
    皇小弟閱讀 46,769評(píng)論 22 665
  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補(bǔ)...
    _Yfling閱讀 13,754評(píng)論 1 92
  • 抽屜菜單 MaterialDrawer★7337 - 安卓抽屜效果實(shí)現(xiàn)方案 Side-Menu.Android★3...
    彬哥狠逍遙閱讀 5,889評(píng)論 4 59
  • mybatis概念 概念:一個(gè)持久層框架 作用:ORM將sql語句映射成實(shí)體類 特點(diǎn):巧靈活半自動(dòng)化使用與中小型項(xiàng)...
    涼希涼兮閱讀 399評(píng)論 0 0