欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android性能优化教程之数据优化详解

程序员文章站 2022-05-16 09:49:49
android性能优化教程之数据优化详解 今天,继续android性能优化一 编码细节优化。 编码细节,对于程序的运行效率也是有很多的影响的。今天这篇主题由于技术能力有限,所以也不敢在深层去和大家分...

android性能优化教程之数据优化详解

今天,继续android性能优化一 编码细节优化。

编码细节,对于程序的运行效率也是有很多的影响的。今天这篇主题由于技术能力有限,所以也不敢在深层去和大家分享。我将这篇主题分为以下几个小节:

(1)缓存

(2)数据

(3)延迟加载和优先加载

1> 缓存

在android中缓存可以用在很多的地方:对象、io、网络、db等等。。对象缓存能减少内存分配,io缓存能对磁盘的读写访问,网络缓存能减少对网络的访问,db缓存能减少对的操作。

缓存针对的场景在android开发中也很明显:

(1)图片缓存

android中提供了lrucache缓存机制。我们可以使用lrucache来进行图片的缓存。对图片的缓存处理步骤一般是:

加载图片 -> 判断缓存中是否存在 ->存在,直接取出设置到imageview ->不存在,则请求网络下载图片 -> 图片下载成功,将图片缓存,设置到imageview

在android中有很多优秀的第三方开源库,所以我们也不必去重复造*。例如:fresco(facebook的产品)、picasso、glide、uil。

(2)不经常改变的数据

对于不需要经常改变的数据,例如app中的一些产品分类。我们就可以将其缓存起来。不用每次都去请求网络来加载数据。这个比较容易理解,不多说了。

(3)listview的缓存

listview item数据的缓存,相信大家都比较清楚。就是利用adapter类的getview方法中convertview复用原理,创建viewholder实现复用。material design 中也提供了recyclerview来替代listview。它会强制你在adapter中使用viewholder来复用view。

(4)消息缓存

此处消息是指handler中发送的message。为我们提供了obtainmessage()来复用一个message。我们来看下:

/**
 * return a new message instance from the global pool. allows us to
 * avoid allocating new objects in many cases.
 */
public static message obtain() {
 synchronized (spoolsync) {
  if (spool != null) {
message m = spool;
spool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
spoolsize--;
return m;
  }
 }
 return new message();
}
上述代码中,spool就是被缓存的一个message实例,首先判断如果不为null,直接拿来复用,否则创建新的message实例。

(5)io缓存

其实java中就为我们提供了一些具有缓存策略的io流:

bufferedreader、bufferedwriter。使用该类io流来代替 inputstream、reader 和outputstream、writer等等。

2> 数据

对于数据存储的优化可以从数据类型和结构来划分。

(1)使用stringbuilder或stringbuffer来拼接字符串,减少对象的临时分配。stringbuilder和stringbuffer的区别其实就一点:在并发操作下,stringbuffer是线程安全的。有利也有弊,线程安全的同时也导致了执行的速度下降。所以,如果不是在多线程操作的情况下,就使用stringbuilder。stringbuilder和stringbuffer的构造函数都允许你传入一个数量级来初始化它的空间大小。从而可以分配一定的空间大小,节省内存资源。

(2)使用weakreference。弱引用带来的好处想必大家都是清楚的。尤其是在android这种内存空间有限的设备中,对于内存的分配和释放是很重要的。weakreference使用很典型的一个场景就是handler。大家都清楚,在activity或fragment中使用handler一般都是作为内部类来实现的。这样就会引发一个问题。如果handler中的某个任务执行较长的时间,那么在activity或者fragment需要被释放的时候(ondestory),由于handler所关联的message还没有执行完成。这时handler就不能被释放,由于handler与activity或fragment所关联,那么就会导致activity或fragment不能被有效释放,最终导致其资源不能被释放,结果可想而知:oom。所以,解决该问题的办法就是使用weakreference或者将handler定义成static。下面来看使用weakreference的方式:

private final myhandler myhandler = new myhandler(this);
private static class myhandler extends handler {
private final weakreference m;
public myhandler(homefragment homefragment){
m = new weakreference(homefragment);
}
@override
public void handlemessage(message msg) {
homefragment homefragment = m.get();
if(homefragment != null) {
homefragment.vpbanner.setcurrentitem(msg.arg1);;
}
}
}

代码很简单,就是将fragment放在weakreference中。在handlemessage中直接取出来操作其中的view.

数据结构方面就比较多了,例如arraylist和linkedlist、linkedhashmap和hashset、weakhashmap。

(1)arraylist对于数据的查询速度比较快,linkedlist对于数据的插入和删除速度要比arraylist快。

(2)linkedhashmap可以记住数据存入的次序,hashset不允许有重复的元素存在。weakhashmap中的数据可以在适合的时候被系统gc自动回收,适合在内存吃紧的场景下。

(3)collections工具类中也提供了很多的适合多线程下操作的集合,并提高了性能,例如:Android性能优化教程之数据优化详解

(4)android中系统也提供了性能更优的数据类型,如:sparsearray,sparsebooleanarray,sparseintarray,pair。sparse的key为int类型。采用二分查找及简单数组存储。并且不需要泛型转换的开销,相对于map来说性能更优。

3>延迟加载

在android中延迟加载的用途也比较广泛,例如viewpager中fragment数据的延迟加载。因为viewpager默认是初始化两内容的。所以我们需要来处理进行延迟加载。

同样,不在activity或fragment对时间敏感的函数中进行耗时操作。避免出现anr的异常发生。

java中提供了scheduledxecutorservice作为延迟加载,其实timer定时器的延时是有bug存在的。所以不推荐使用timer。鸿洋博客有讲该timer的缺陷:timer 缺陷

android中可以使用handler的一些方法来延迟操作:

(1)postdelayed

(2)postattime

(3)sendmessagedelayed

以及view的postdelayed,alarmmanager定时等。