美文网首页
2020-04-25-Android-滑动列表卡顿问题

2020-04-25-Android-滑动列表卡顿问题

作者: 耿望 | 来源:发表于2020-04-26 19:38 被阅读0次

View的刷新

前面学习过,view的刷新过程分为三步,measure,layout和draw。


7.Android View的刷新.jpg

所以一般的卡顿问题都可以从这三个过程分析,通过systrace查看哪一个流程比较耗时。
下面逐个看看:
1.measure
measure方法是为了测量view的大小(宽和高)。
这里耗时的原因大概率跟布局有关,不同类型的布局测量view大小的次数差别会比较大。比如RelativeLayout需要给每一个view的水平和竖直方向都测量一次,或者是嵌套较多的布局,也会需要多次测量大小。
举个例子,我们应该尽量少在每个子view分别设置padding和margin。
可以简单理解说padding为内边距;margin为外边距。
下面给了一张图可以明显看出两者差异:

temp.PNG

在measure的时候,对于margin和padding都是需要单独计算的。
2.layout
layout方法主要是为了确定view的位置。
layout方法需要确定子view相对于父容器在上下左右四个方向的距离。而且layout方法还需要从顶层view一级一级逐层确定子view的位置,所以嵌套过多的布局就很容易耗时。
3.draw
draw方法用于绘制每个view自己的内容,同时也是从顶层view逐级向下绘制的。
这里的经验是,不要在UI线程进行太复杂的逻辑运算,而是通过异步的方式,数据加载完成后通过postInvalidate通知UI线程刷新。

ListView

比较常见的卡顿还有列表滑动卡顿,也就是obtainView耗时。
这里很推荐一个做法,就是用RecyclerView代替ListView。或者是将getView中某些耗时操作通过异步实现。
比如下面的代码逻辑,需要在getView中加载应用图标,这是一个比较耗时操作。

        @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实现一个异步操作。

    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耗时对比
android listview 滑动卡顿问题解决
Android 中的卡顿丢帧原因概述 - 应用篇
ListView和GridView列表滑动卡顿问题的优化方法汇总
深入探索Android卡顿优化(上)
Android 中的卡顿丢帧原因概述 - 系统篇
Android性能优化之绘制优化
android:padding和android:margin的区别 详解
从 View 绘制谈性能优化

相关文章

网友评论

      本文标题:2020-04-25-Android-滑动列表卡顿问题

      本文链接:https://www.haomeiwen.com/subject/ppehwhtx.html