美文网首页
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