android最佳性能实践

时间:2023-01-30 14:22:15

android最佳性能实践(一)-----合理管理内存

参考博客:(郭霖博客)http://blog.csdn.net/guolin_blog/article/details/42238627

        内存(RAM)对手机来说至关重要,是非常珍贵的资源。为了使垃圾回收器可以正常释放所占有的内存,在编写代码时一定要注意避免出现

内存泄漏的问题。内存泄漏通常是由于全局成员变量持有对象引用所导致的,如果一个对象的引用不再被其他对象所持有,那么系统就会将这个

对象所分配的内存进行回收。

     Android系统给我们提出了很多内存优化的建议技巧,只要按照这些技巧来编写程序,就可以让我们的程序在内存性能发面表现得相当不错,下面

我们就来一一学习一下这些技巧。

首先:知晓内存的开支情况:

    使用枚举通常会比使用静态常量消耗两倍以上的内存,在android开发中我们尽可能地少用枚举。

    任何一个类,包括内部类、匿名类,都要占用大概500字节的内存空间。

    任何一个类的实例要消耗12-16字节的内存开支,因此频繁创建实例也会在一定程度上影响内存。

    使用HashMap时,即使你只设置了一个基本数据类型的键,比如说int,但是也会按照对象的大小来分配内存,大概是32字节,而不是4字节。

因此最好的办法就是像上面所说的一样,使用优化过的数据集合。

优化方法:

方法一:节制地使用Service:

     我们知道Service分为显式和隐式的。但一定要注意只有当当前任务正在执行的时候才应该让Service运行起来,另外,当任务执行完后去停止

Service的时候,要小心Service停止失败导致内存泄漏的情况。

     当我们启动一个Service时,系统会倾向于将这个Service所依赖的进程进行保留,这样就会导致这个进程变得非常消耗内存。并且,系统可以在LRU cache当中缓存的进程数量也会减少,导致切换应用程序的时

候耗费更多性能。严重的话,甚至有可能会导致崩溃,因为系统在内存非常吃紧的时候可能已无法维护所有正在运行的Service所依赖的进程了。

     为了能够控制Service的生命周期,Android官方推荐的最佳解决方案就是使用IntentService,这种Service的最大特点就是当后台任务执行结束后会自动停

止,从而极大程度上避免了Service内存泄漏的可能性。

 

方法二:当界面不可见时释放内存:

     首先,如何判断我们的Activity当前是不是不可见的,当然你可以凭你自己对Activity生命周期的了解去判断;应用程序中的判断很简单;如下:

     只需要在Activity中重写onTrimMemory()方法,然后在这个方法中监听TRIM_MEMORY_UI_HIDDEN这个级别,一旦触发了之后就说明用户已经离开

了我们的程序,那么此时就可以进行资源释放操作了,如下所示:

     public void onTrimMemory(int level){

       super.onTrimMemory(level);

       switch(level){

        case TRIM_MEMORY_UI_HIDDEN:

              //进行资源释放操作

        break;

     }

    }

     这和onStop()方法还是有很大区别的,因为onStop()方法只是当一个Activity完全不可见的时候就会调用,比如说用户打开了我们程序中的另一个Activity。因此,我们可以在onStop()方法中去释放一些Activity相关的资源,比如说取消网络连接或者注销广播接收器等,但是像UI相关的资源应该一直要等到onTrimMemory(TRIM_MEMORY_UI_HIDDEN)这个回调之后才去释放,

这样可以保证如果用户只是从我们程序的一个Activity回到了另外一个Activity,界面相关的资源都不需要重新加载,从而提升响应速度。

 

方法三:避免在Bitmap上浪费内存

不要在手机上加载分辨率超高的图片,分辨率太高对手机来说视觉效果也不好。

 

方法四:使用优化过的数据集合:

     androidAPI中提供了一些优化过的数据集合工具类,如SpareArray,SpareBooleanArray等,使用HashMap工具类会相对比较低。

 

方法五:谨慎使用抽象编程:

     许多程序员都喜欢各种使用抽象来编程,认为这是一种很好的编程习惯。当然,这一点不可否认,因为的抽象的编程方法更加面向对象,而且在代码的维护和可扩展性方面都会有所提高。但是,在Android上使用抽象会带来额外的内存开支,因为抽象的编程方法需要编写额外的代码,虽然这些代码根本执行不到,但是却也要映射到内存当中,不仅占用了更多的内存,在执行效率方面也会有所降低。当然这里我并不是提倡大家

完全不使用抽象编程,而是谨慎使用抽象编程,不要认为这是一种很酷的编程方式而去肆意使用它,只在你认为有必要的情况下才去使用。

 

方法六:少用不必要的框架;

比如说像Guice或者RoboGuice等(简化findViewById的编程)

 

使用ProGuard简化代码

     ProGuard相信大家都不会陌生,很多人都会使用这个工具来混淆代码,但是除了混淆之外,它还具有压缩和优化代码的功能。ProGuard会对我们的代码进行检索,删除一些无用的代码,并且会对类、字段、方法等进行重命名,重命名之后的类、字段和方法名都会比原来简短很多,这样的话也就对内存的占用变得更少了。

 

方法七 使用多个进程:

     并不是建议使用,而是它确实会节省内存。

 

Android最佳性能实践(二)——分析内存的使用情况

博客参考地址:http://blog.csdn.net/guolin_blog/article/details/42238633

     前言:虽然说手机内存都已经比较大了,但是我们都知道,系统不是会把所有内存分配给我们的手机的。每个程序都会有使用的内存

上限,这被称为是堆大小(Heap Size)。不同的手机,堆大小是不同的。,堆大小也已经由Nexus One时的32MB,变成了Nexus 5时的192MB。

如果大家想要知道自己手机的堆大小是多少,可以调用如下代码:

ActivityManager manager =(ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);

int heapSize = manager.getMemoryClass();

也就是说我们在开发应用程序时不能超过这个大小限制,否则会出现:OutOfMemoryError错误。

 

android 的GC操作:也就是垃圾回收操作

      垃圾回收其实就是回收掉不用的对象,但那些是不用的对象,android是这么判断的。

触发GC操作后android会从一个叫做Roots的对象爱是检查,所有它可以访问到的对象就说明还在使用中,应该

进行保留,而其他的就是可以回收了的对象。

      那么下一个问题来了,什么时候会触发GC操作呢?这个通常由系统自己去决定,当然也可以认为区监听。

怎样监听系统的GC过程呢?很简单,系统每进行一次GC操作,就会在LogCat打印出一条日志:

格式如下:

 D/dalvikvm:<GC_Reason><Amount_freed>,<Heap_stats>,<Pause_time>

GC_Reason:是触发GC操作的原因;具体原因分类看博客。

Amount_freed:表示系统释放了多少内存

Heap_stats:会显示当前内存的空闲比例以及使用情况。

Pause_time:表示GC操作导致应用程序暂停的时间。、

 

可以看出,和我们上面所介绍的格式是完全一致的,最后的暂停时间31ms+7ms,一次就是GC开始时的暂停时间,一次是结束时的暂停时间。另外可以根据进程id来区分这是哪个程序中进行的GC操作,那么从上图就可以看出这条GC日志是属于24699这个程序的。

那么这是使用dalvik运行环境时所打印的GC日志,而自Android4.4版本之后加入了art运行环境,在art中打印GC日志基本和dalvik是相同的,如下图所示:

 

内存泄漏分析软件的使用:

那么通过上面学习的GC日志以及DDMS工具这两种方式,现在我们已经可以比较轻松地发现应用程序中是否存在内存泄露的现象了。但是如果真的出现了内存泄露,我们应该怎么定位到具体是哪里出的问题呢?这就需要借助一个内存分析工具了,叫做Eclipse Memory AnalyzerMAT)。我们需要先将这个工具下载下来,下载地址是:http://eclipse.org/mat/downloads.php。这个工具分为Eclipse插件版和独立版两种,如果你是使用Eclipse开发的,那么可以使用插件版MAT,非常方便。如果你是使用Android Studio开发的,那么就只能使用独立版的MAT了。

具体看博客就可以。

 

Android最佳性能实践三----性能优化

前提说明:代码优化的最基本方法还是算法和数据结构的优化,本章只是强调平时的代码规范,来对性能进行“微笑的优化。”

参考博客:http://blog.csdn.net/guolin_blog/article/details/42318689

性能优化技巧

技巧一:避免创建不必要的对象

(1)       如果我们需要拼接字符串:使用StringBuffferStringBuilder;尽量少使用加号。因为使用加号连接会创建很多多余的对象。(长见识了)

(2)       在没有特殊原因的情况下,使用基本数据类型代替封装数据类型(如:intInteger

技巧二:静态优于抽象

如果你并不需要访问一个对象中的某些字段,只是想调用它的某个方法来去完成一项通用的功能,那么可以将这个方法设置成静态方法,这会让调用的速度提升15%-20%,同时也不用为了调用这个方法而去专门创建对象了,这样还满足了上面的一条原则。另外这也是一种好的编程习惯,因为我们可以放心地调用静态方法,而不用担心调用这个方法后是否会改变对象的状态(静态方法内无法访问非静态字段)。

技巧三:对常量使用static final修饰符

我们先来看一下在一个类的最顶部定义如下代码:

这个还是按照情况定吧。

技巧四:增强型for循环的使用

1.   static class Counter {  

2.       int mCount;  

3.   }  

4.     

5.   Counter[] mArray = ...  

6.   public void two() {  

7.       int sum = 0;  

8.       for (Counter a : mArray) {  

9.           sum += a.mCount;  

10.      }  

多使用系统封装好的API

Java语言当中其实给我们提供了非常丰富的API接口,我们在编写程序时如果可以使用系统提供的API就应该尽量使用,系统提供的API完成不了我们需要的功能时才应该自己去写,因为使用系统的API在很多时候比我们自己写的代码要快得多,它们的很多功能都是通过底层的汇编模式执行的。

比如说String类当中提供的好多API都是拥有极高的效率的,像indexOf()方法和一些其它相关的API,虽说我们通过自己编写算法也能够完成同样的功能,但是效率方面会和这些方法差的比较远。这里举个例子,如果我们要实现一个数组拷贝的功能,使用循环的方式来对数组中的每一个元素一一进行赋值当然是可行的,但是如果我们直接使用系统中提供的System.arraycopy()方法将会让执行效率快9倍以上。

避免在内部调用Getters/Setters方法

我们平时写代码时都被告知,一定要使用面向对象的思维去写代码,而面向对象的三大特性我们都知道,封装、多态和继承。其中封装的基本思想就是不要把类内部的字段暴漏给外部,而是提供特定的方法来允许外部操作相应类的内部字段,从而在Java语言当中就出现了Getters/Setters这种封装技巧。

然而在Android上这个技巧就不再是那么的受推崇了,因为字段搜寻要比方法调用效率高得多,我们直接访问某个字段可能要比通过getters方法来去访问这个字段快37倍。不过我们肯定不能仅仅因为效率的原因就将封装这个技巧给抛弃了,编写代码还是要按照面向对象思维的,但是我们可以在能优化的地方进行优化,比如说避免在内部调用getters/setters方法。

这个还是按自己使用习惯吧,有时候使用Getters/Setters方法是很方便的。

Android最佳性能实践()——布局优化技巧

参考博客:http://blog.csdn.net/guolin_blog/article/details/43376527

使用<include>和<merge>标签:参考博客就可以了。