大家肯定都知道Android中有许多布局,比如Linerlayout、RelativeLayout等,布局优化就是减少布局文件层级,层级减少了,那么程序绘制时就快了许多,所以可以提高性能。
在布局代码中,使用什么布局基本遵守以下规则:
3.使用
内存泄漏优化换句话说,就是什么情况可能会导致内存泄漏:
public class MainActivity extends AppCompatActivity {
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadData();
}
private void loadData(){
Message message = Message.obtain();
mHandler.sendMessage(message);
}
}
这样hanlder会持有Activity的引用,handler是运行在一个Looper线程中的,而Looper线程是轮询来处理消息队列中的消息的,假设我们处理的消息有10条,而当他执行到第6条的时候,用户退出销毁了当前的Activity,这个时候消息还没有处理完,handler还在持有Activity的引用,这个时候就会导致无法被GC回收,造成了内存泄漏。
众所周知,RecyclerView拥有四级缓存,它们分别是:
(1)如果是RecyclerView不滚动情况下缓存(比如删除item)、重新布局时。
mCachedViews
> RecycledViewPool
的优先级缓存到mCachedViews或者RecycledViewPool中。(2)如果是RecyclerView滚动情况下缓存(比如滑动列表),在滑动时填充布局。
当RecyclerView要拿一个复用的ViewHolder时:
重新绑定数据
。createViewHolder()
重新去创建一个。这里有几点需要注意:
onBindViewHolder()
重新绑定数据才能使用。如果想深入了解RecyclerView缓存机制的同学,可以参考《RecyclerView的回收复用缓存机制详解》 这篇文章。
根据上面我们对缓存机制的了解,我们可以简单得到以下几个大方向:
onBindViewHolder
方法,减少ViewHolder绑定的时间。由于ViewHolder可能会进行多次绑定,所以在onBindViewHolder()
尽量只做简单的工作。onCreateViewHolder
方法,减少ViewHolder创建的时间。1.多使用Scrap进行局部更新。
notifyItemChange
、notifyItemInserted
、notifyItemMoved
和notifyItemRemoved
等方法替代notifyDataSetChanged
方法。notifyItemChanged(int position, @Nullable Object payload)
方法,传入需要刷新的内容进行局部增量刷新。这个方法一般很少有人知道,具体做法如下:
RecyclerView.Adapter
的onBindViewHolder(@NonNull RecyclerViewHolder holder, int position, @NonNull List
方法 java 复制代码
@Override public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position, @NonNull List
详细使用方法可参考XUI中的RecyclerView局部增量刷新 中的代码。
DiffUtil
、SortedList
进行局部增量刷新,提高刷新效率。和上面讲的传入payload
原理一样,这两个是Android默认提供给我们使用的两个封装类。这里我以DiffUtil
举例说明该如何使用。
DiffUtil.Callback
的5个抽象方法,具体可参考DiffUtilCallback.javaDiffUtil.calculateDiff
方法返回比较的结果DiffUtil.DiffResult
。DiffUtil.DiffResult
的dispatchUpdatesTo
方法,传入RecyclerView.Adapter进行数据刷新。详细使用方法可参考XUI中的DiffUtil局部刷新 和 XUI中的SortedList自动数据排序刷新 中的代码。
2.合理设置RecyclerViewPool的大小。如果一屏的item较多,那么RecyclerViewPool的大小就不能再使用默认的5,可适度增大Pool池的大小。如果存在RecyclerView中嵌套RecyclerView的情况,可以考虑复用RecyclerViewPool缓存池,减少开销。
3.为RecyclerView设置setHasStableIds
为true,并同时重写RecyclerView.Adapter的getItemId
方法来给每个Item一个唯一的ID,提高缓存的复用率。
4.视情况使用setItemViewCacheSize(size)
来加大CacheView缓存数目,用空间换取时间提高流畅度。对于可能来回滑动的RecyclerView,把CacheViews的缓存数量设置大一些,可以省去ViewHolder绑定的时间,加快布局显示。
5.当两个数据源大部分相似时,使用swapAdapter
代替setAdapter
。这是因为setAdapter
会直接清空RecyclerView上的所有缓存,但是swapAdapter
会将RecyclerView上的ViewHolder保存到pool中,这样当数据源相似时,就可以提高缓存的复用率。
1.在onBindViewHolder方法中,去除冗余的setOnItemClick等事件。因为直接在onBindViewHolder方法中创建匿名内部类的方式来实现setOnItemClick,会导致在RecyclerView快速滑动时创建很多对象。应当把事件的绑定在ViewHolder创建的时候和对应的rootView进行绑定。
2.数据处理与视图绑定分离,去除onBindViewHolder方法里面的耗时操作,只做纯粹的数据绑定操作。当程序走到onBindViewHolder方法时,数据应当是准备完备的,禁止在onBindViewHolder方法里面进行数据获取的操作。
3.有大量图片时,滚动时停止加载图片,停止后再去加载图片。
4.对于固定尺寸的item,可以使用setHasFixedSize
避免requestLayout
。
1.降低item的布局层级,可以减少界面创建的渲染时间。
2.Prefetch预取。如果你使用的是嵌套的RecyclerView,或者你自己写LayoutManager,则需要自己实现Prefetch,重写collectAdjacentPrefetchPositions
方法。
作者:xuexiangjys
链接:https://juejin.cn/post/7164032795310817294
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
响应速度优化的核心思想是避免在主线程中做耗时操作,Android规定,Activity如果5秒钟之内无法响应屏幕触摸事件或者键盘输入事件就会出现ANR,而BroadcastReceiver如果10秒,Service时20s当然这是小概率事件,如果在相应时间内未得到反映就会出现ANR。当有耗时操作时,可以单独开启一个线程去操作。
listview优化相信大家也都比较熟悉了,也是比较经典的面试题,在这里就不详细赘述了,主要有复用view,首先判断view是否为空,如果不为空直接引用,为空再创建使用ViewHolder类,settag的方式保存布局的控件初始化信息,避免每次都去findviewbyid影响效率
其实思想也很简单,那就是采用BitmapFactory.Options来加载所需尺寸的图片。这里假设通过ImageView来显示图片,很多时候ImageView并没有图片的原始尺寸那么大,这个时候把整个图片加载进来后再设给imageView,这显然是没必要的,因为ImageView并没有办法显示原始的图片。通过BitmapFactory.Options就可以按一定的采样率来加载缩小后的图片,将缩小后的图片在ImageView中显示,这样就会降低内存占用从而在一定程度上避免OOM,提高了Bitmap加载时的性能。
线程优化的思想是采用线程池,避免程序中存在大量的Thread。线程池可以重用内部的线程,从而避免了线程的创建和销毁所带来的性能开销,同时线程池还能有效地控制线程池的最大并发数,避免大量的线程因互相抢占系统资源从而导致阻塞现象的发生。因此在实际开