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

所以一般的卡頓問題都可以從這三個(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為外邊距。
下面給了一張圖可以明顯看出兩者差異:
在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)化