2020-04-25-Android-滑動列表卡頓問題

View的刷新

前面學(xué)習(xí)過,view的刷新過程分為三步,measure,layout和draw。


7.Android View的刷新.jpg

所以一般的卡頓問題都可以從這三個(gè)過程分析,通過systrace查看哪一個(gè)流程比較耗時(shí)。
下面逐個(gè)看看:
1.measure
measure方法是為了測量view的大?。▽捄透撸?。
這里耗時(shí)的原因大概率跟布局有關(guān),不同類型的布局測量view大小的次數(shù)差別會比較大。比如RelativeLayout需要給每一個(gè)view的水平和豎直方向都測量一次,或者是嵌套較多的布局,也會需要多次測量大小。
舉個(gè)例子,我們應(yīng)該盡量少在每個(gè)子view分別設(shè)置padding和margin。
可以簡單理解說padding為內(nèi)邊距;margin為外邊距。
下面給了一張圖可以明顯看出兩者差異:

temp.PNG

在measure的時(shí)候,對于margin和padding都是需要單獨(dú)計(jì)算的。
2.layout
layout方法主要是為了確定view的位置。
layout方法需要確定子view相對于父容器在上下左右四個(gè)方向的距離。而且layout方法還需要從頂層view一級一級逐層確定子view的位置,所以嵌套過多的布局就很容易耗時(shí)。
3.draw
draw方法用于繪制每個(gè)view自己的內(nèi)容,同時(shí)也是從頂層view逐級向下繪制的。
這里的經(jīng)驗(yàn)是,不要在UI線程進(jìn)行太復(fù)雜的邏輯運(yùn)算,而是通過異步的方式,數(shù)據(jù)加載完成后通過postInvalidate通知UI線程刷新。

ListView

比較常見的卡頓還有列表滑動卡頓,也就是obtainView耗時(shí)。
這里很推薦一個(gè)做法,就是用RecyclerView代替ListView?;蛘呤菍etView中某些耗時(shí)操作通過異步實(shí)現(xiàn)。
比如下面的代碼邏輯,需要在getView中加載應(yīng)用圖標(biāo),這是一個(gè)比較耗時(shí)操作。

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if (convertView == null) {
                convertView = new PowerProtectInfoView(PowerUsageModelActivity.this);
            }
            PowerProtectInfoView infoView = (PowerProtectInfoView) convertView;

            if (!infoView.isDividerVisible()) {
                convertView = new PowerProtectInfoView(PowerUsageModelActivity.this);
                infoView = (PowerProtectInfoView) convertView;
            }

            if ((mAppList != null) && (mAppList.size() > 0)) {
                AppInfoWrapper appWrapper = mAppList.get(position);
                LoadTask loadTask = new LoadTask();
                loadTask.setInfoView(infoView);
                loadTask.execute(appWrapper);
                infoView.setTitle(appWrapper.label);
                infoView.setTitleColor(getResources().getColor(R.color.color_preference_title_color_normal));
                infoView.setDotVisible(appWrapper.hasDot);
            }

            return convertView;
        }

就可以通過AsyncTask實(shí)現(xiàn)一個(gè)異步操作。

    private class LoadTask extends AsyncTask<AppInfoWrapper, Integer, Drawable> {

        private PowerProtectInfoView mInfoView;

        public void setInfoView(PowerProtectInfoView infoView) {
            mInfoView = infoView;
        }

        @Override
        protected Drawable doInBackground(AppInfoWrapper... wrappers) {
            Log.d(TAG, "doInBackground");
            AppInfoWrapper appWrapper = wrappers[0];
            ApplicationInfo applicationInfo = appWrapper.appInfo;
            //Drawable icon = applicationInfo.loadIcon(getPackageManager());
            OppoPackageManager mOpm = new OppoPackageManager(PowerUsageModelActivity.this);
            Drawable icon = mOpm.getApplicationIconCache(applicationInfo);
            if (null == icon) {
                icon = getResources().getDrawable(R.drawable.pm_power_usage_system);
            }
            if (icon != null) {
                icon = OppoIconUtils.getDrawableForListUse(PowerUsageModelActivity.this, icon);
            }
            return icon;
        }

        @Override
        protected void onPostExecute(Drawable icon) {
            mInfoView.setIcon(icon);
            Log.d(TAG, "onPostExecute");
        }
    }

參考

Android 不同布局類型measure、layout、draw耗時(shí)對比
android listview 滑動卡頓問題解決
Android 中的卡頓丟幀原因概述 - 應(yīng)用篇
ListView和GridView列表滑動卡頓問題的優(yōu)化方法匯總
深入探索Android卡頓優(yōu)化(上)
Android 中的卡頓丟幀原因概述 - 系統(tǒng)篇
Android性能優(yōu)化之繪制優(yōu)化
android:padding和android:margin的區(qū)別 詳解
從 View 繪制談性能優(yōu)化

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容