Android RecyclerView的卡頓問題

本文其實(shí)是上一篇Android本地app操作相關(guān)基礎(chǔ)的延伸,然而內(nèi)容基本沒什么聯(lián)系了(初學(xué)者身份瞬間暴露,打一槍換一個(gè)地方←_←),就不好意思再添個(gè)“續(xù)”或者“(2)”了~~
照舊先碼字!

RecyclerView為什么會(huì)卡

RecyclerView作為v7包的新控件,自從推出就廣受Android Developer們歡迎,實(shí)際上它已經(jīng)取代了ListView和GridView兩位老前輩的地位。然而不少親們想必也已經(jīng)發(fā)現(xiàn)了:沒有優(yōu)化過的Recycler性能很poor。上一篇博主使用的item也僅僅是一個(gè)圖兩串字而已,結(jié)果一滑動(dòng)就卡的要命,不能忍!
那么why?回想在用ListView和GridView的adapter時(shí),我們是用一種叫ViewHolder的自定義類(容器)來實(shí)現(xiàn)優(yōu)化的,而RecyclerView的特性之一就是強(qiáng)制你使用它的RecyclerView.ViewHolder。可是,RecyclerView.ViewHolder要比我們寫的那個(gè)單純的容器復(fù)雜多了(源碼里算上注釋有大約500行),與RecyclerView.Adapter的聯(lián)系也是千絲萬縷。


按stackoverflow上面比較通俗的解釋:RecyclerView.Adapter里面的onCreateViewHolder()方法和onBindViewHolder()方法對(duì)時(shí)間都非常敏感。類似I/O讀寫,Bitmap解碼一類的耗時(shí)操作,最好不要在它們里面進(jìn)行。


如何解決這個(gè)問題

  • 首先當(dāng)然得優(yōu)化你的item,合理運(yùn)用<include>,<merge>,<ViewStub>等標(biāo)簽,使布局層次盡量少——其實(shí)ListView和GridView里你也應(yīng)該這么做,應(yīng)該當(dāng)成是一種寫UI的習(xí)慣。
  • 其次就是靈活使用各種第三方庫,去完成各種耗時(shí)操作,比如通過Glide或者是Picasso加載圖片。優(yōu)秀的開源庫在性能上往往都考慮得很仔細(xì)。
  • 最后的問題來了,如果只想寫一個(gè)小demo,不愿大張旗鼓怎么辦?如果即便一般的第三方庫也不好解決問題,比如上一篇那個(gè)該死的loadIcon()方法返回的是一個(gè)Drawable對(duì)象,GlidePicasso都沒法直接處理,轉(zhuǎn)碼又等于添了個(gè)耗時(shí)任務(wù),那怎么辦?
真正的app管理應(yīng)用,應(yīng)該引入U(xiǎn)IL或者Picasso一類的加載庫進(jìn)行圖標(biāo)加載
(在此原諒博主沒仔細(xì)敲代碼,就信口開河了)

答案就是,想法在你setAdapter之前就把任務(wù)給完成

Demo

喲西,上代碼!本文代碼完全基于上一篇文,無須刪減重構(gòu)。
主要就是增添了一個(gè)實(shí)體bean對(duì)象,setAdapter()時(shí)要傳遞的數(shù)據(jù),全部通過它預(yù)先加載到內(nèi)存里!這樣那倆敏感方法里只需要簡單的get出來即可。

實(shí)體類AppBean.java

package com.example.jin.localapp;
import android.graphics.drawable.Drawable;

/**
 * Created by Jin on 2016/11/8.
 */
public class AppBean {
    private CharSequence name;
    private String packageName;
    private Drawable icon;
    //這類代碼可別逞英雄手動(dòng)寫哦,IDE(Android Studio和Eclipse都有的)里可以直接生成
    public CharSequence getName() {
        return name;
    }
    public void setName(CharSequence name) {
        this.name = name;
    }
    public String getPackageName() {
        return packageName;
    }
    public void setPackageName(String packageName) {
        this.packageName = packageName;
    }
    public Drawable getIcon() {
        return icon;
    }
    public void setIcon(Drawable icon) {
        this.icon = icon;
    }
}

主界面MainActivity.java

    private List<AppBean> mList;//mList的泛型換成AppBean
    private void initData() {//然后只需要改這個(gè)方法
        mList = new ArrayList<>();
        manager = getPackageManager();
        List<PackageInfo> list = manager.getInstalledPackages(0);//獲取已安裝的全部應(yīng)用
        for (PackageInfo info : list) {
            if ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
                AppBean bean = new AppBean();
                bean.setName(info.applicationInfo.loadLabel(manager));
                bean.setPackageName(info.packageName);
                bean.setIcon(info.applicationInfo.loadIcon(manager));
                mList.add(bean);
            }
        }
        //拿到數(shù)據(jù)再setAdapter
        mainRcv.setLayoutManager(new LinearLayoutManager(this));
        mainRcv.setHasFixedSize(true);
        mainRcv.setAdapter(new AppAdapter(this, mList));
    }

適配器AppAdapter.java

    private List<AppBean> appList;
    //同樣這邊的類型換過來
    public AppAdapter(Context context, List<AppBean> appList) {
        this.context = context;
        this.appList = appList;
        inflater = LayoutInflater.from(context);
        manager = context.getPackageManager();
    }
    //然后也只需要改這個(gè)方法
    @Override
    public void onBindViewHolder(AppHolder holder, final int position) {
        final AppBean bean = appList.get(position);
        holder.itemIconIv.setImageDrawable(bean.getIcon());//圖標(biāo)
        holder.itemNameTv.setText(bean.getName());//名稱
        holder.itemPackageTv.setText(bean.getPackageName());//包名

        holder.view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(manager.getLaunchIntentForPackage(bean.getPackageName()));//根據(jù)包名啟動(dòng)此應(yīng)用
                context.startActivity(intent);
            }
        });
    }

搞定!因?yàn)椴┲魇怯檬謾C(jī)直接錄像再轉(zhuǎn)gif,為了使點(diǎn)擊看上去有效果,于是給item增添了一個(gè)背景層,這需求實(shí)戰(zhàn)中也是很常見的哦~~

色彩資源文件colors.xml

這個(gè)粉紅色其實(shí)很難看,單純當(dāng)區(qū)別用。。。。。。
實(shí)戰(zhàn)開發(fā)如果沒有美工,一定要仔細(xì)斟酌選取,盡量讓自己審美好點(diǎn)!
推薦一個(gè)不錯(cuò)的配色方案網(wǎng)站Material Design調(diào)色板

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>
    <color name="colorWhite">#ffffff</color>
    <color name="colorPink">#f8bbd0</color>

</resources>

選擇器item_selector.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_selected="true" android:drawable="@color/colorWhite"  />  
    <item android:state_focused="true" android:drawable="@color/colorPink"  />  
    <item android:state_pressed="true" android:drawable="@color/colorPink"  />
    <item android:drawable="@color/colorWhite"/>

</selector>

條目布局item_app.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:background="@drawable/item_selector"
    android:layout_width="match_parent"
    android:layout_height="60dp">

<!-- 中間內(nèi)容無須修改,略-->

</RelativeLayout>

最終運(yùn)行效果

截圖已經(jīng)不太能感受到卡了,真機(jī)運(yùn)行更加流暢!

1.gif
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,325評(píng)論 25 708
  • afinalAfinal是一個(gè)android的ioc,orm框架 https://github.com/yangf...
    passiontim閱讀 15,556評(píng)論 2 45
  • 簡介: 提供一個(gè)讓有限的窗口變成一個(gè)大數(shù)據(jù)集的靈活視圖。 術(shù)語表: Adapter:RecyclerView的子類...
    酷泡泡閱讀 5,212評(píng)論 0 16
  • 天南地北其意是我在南,你在北,雖然望著同一片星空,記憶喚起無遐的漣漪,心里的訴聲卻如波浪無法控制,翻腔而來? 六月...
    咕嚕_fc3f閱讀 275評(píng)論 0 2
  • 已經(jīng)坐在位置上,思考自己今天該寫什么共80分鐘零六秒,手機(jī)也只剩余百分之二十的電量。希望一切都停止,除了自己的大腦...
    譽(yù)曉花香閱讀 418評(píng)論 0 0