android 性能优化浅谈

来源:互联网 发布:ubuntu vi 不保存退出 编辑:程序博客网 时间:2024/05/18 16:18

本文介绍了一些有效的性能优化方法,主要内容包括布局 优化、绘制优化、内存泄漏优化、响应速度 优化、ListView优化、Bitmap优化、线程优化以及一些性能优化的建议。感谢《android开发艺术探索》的指导。


一、布局优化

1,ViewStub  当使用的才会加载
2,include    重用布局
3,merge     减少布局的层级

二、绘制优化

指在View的onDraw中要避免执行大量操作。

三、内存泄漏优化

常出现的场景:
①静态常量无法释放导致的内存泄漏
②单例模式拥有某个类的对象,导致的无法释放,内存泄漏
③属性动画没有销毁,界面已经销毁。但是动画还是在运行。(在onDestroy中销毁动画)

四、响应速度优化

避免在主线程中做耗时工作。activity  5秒无法相应屏幕触摸事件或者键盘输入事件、BroadcastReceiver如果10秒还未完成操作。

五、ListView和Bitmap优化

ListView:
①采用Viewholder并避免在getView中执行耗时工作。
②要根据列表的滑动状态来控制任务的执行频率。(比如快速滑动时不适合开启大量异步任务,可以在用户滑动的时候停止异步加载。)
public void onScrollStateChanged(AbListView view, intscrollState){
   if(scrollState==OnScrollListener.SCROLL_STATE_IDLE){
       mIsGridViewIdle=true;
       mImageAdapter.notifyDataSetChanged();
   }else{
       mIsGridViewIdle=false;
   }
}


if(mIsGridViewIdle&&mCanGetBitmapFromNetWork){
   imageView.setTag(uri);
   mIMageLoader.bindBitmap(uri,imageView,mImageWidth,mImageWidth);
}
③开启硬件加速使滑动就流畅(通过设置android:hardwareAccelerated="true"可为)。


Bitmap:
BitmapFactory加载的四类方法:
①decodeFile②decodeResource③decodeStream④decodeByteArray
decoderfile和decodeResource间接调用了decodeStream


如何高效记载bitmap:
1)将BitmapFactory.Options的inJustDevodeBounds设为true并加载图片。
2)从BitmapFactory.Options中取出图片的原始宽高信息,他们对应与outWidth和outHeight参数。
3)根据采样率的规则并结合目标View的所需大小计算出采样率inSampleSize。
4)将BitmapFactoryOptions的inJustDecodeBounds参数设为false,然后加载图片。
实现:
public static Bitmap decodeSampledBitmapFromResource(Resources res,int resId,int reqWidth,intreqHeight){
   //Firstdecode with inJustDecodeBounds=tru to check dimensions
   final BitmapFactory.Options options=new BitmapFactory.Options();
   options.inJustDecodeBounds=true;
   BitmapFactory,decideResource(res,resId,options);
   //colculate inSampleSize
   options.inSampleSize=calculateInSampleSize(options,reqWidth,reqHeight);
   
   //Decode bitmap with inSampleSize set
   options.inJustDecodeBounds=false;
   return BitmapFactory.decodeResource(res,resId,options);
}
//calculateInSampleSize
public static int calculateInSampleSize(BitmapFactory.Options options,int reqWidth,int reqHeight){
    //Raw height and width of image
    final int height=options.outHeight;
    final int height=options.outWidht;
    int inSampleSize=1;


    if(height>reqHeight||widht>reqWidth){
       final int halfheight=height/2;
       final int halfwidth=width/2;
       //calculate the largest inSampleSize value that is a power of 2 and keeps both
       //height and width larger than the requested height and width.
       while((halfHeight/inSampleSize)>=reqHeight&&(halfWidth/inSampleSize)>=reqWidth){
            inSampleSize*=2;
       }
    }
    return inSampleSize;
}


使用:
如果期望得到大小为100x100像素的图片。
mImageView.setImageBitmap(decodeSampleBitmapResource(getResources(),R.id.myimage,100,100));



6线程优化

使用线程池,避免程序中存在大量的Thread。线程池可以重用内部的线程。从而避免线程创建和销毁所带来的开销。

同时还能有效的控制线程池的并发数。避免大量线程因互抢资源导致阻塞。还能 对线程进行简单管理,并提供定时执行以及指定间隔循环执行。

线程池分类:

1,FixedThreadPool

2,CachedThreadPool

3,ScheduledThreadPool

4,SingleThreadExecutor

这里就不详细说明这四种类型的功能特性,请大家自行搜索。但他们的都是通过ThreadPoolExecutor实现的。

public ThreadPoolExecutor(

int corePoolSize,    

int maximumPoolSize,  

long keepAliveTime,

TimeUnit unit,

BlockingQueue<Runnable> workQueue,

ThreadFactory threadFactory)


解析:

corePoolSize:核心线程数,默认情况下,核心线程会在线程池一直存活,及时他们 处于闲置状态。如果将ThreadPoolExecutor的allowCoreThreadTimeOut属性设置为true,那么闲置的核心线程在等待新任务到来时会有超时策略,这个时间间隔由keepAliveTime决定。

maximumPoolSize:所能容纳最大线程数,活动线程达到这个值后,后续新任务会呗阻塞。

keepAliveTime:非核心线程闲置时的超时时长,超过就被回收。当allowCoreThreadTimeOut为true的时候,同样会作用于核心线程。

unit:指定keepAliveTime参数的时间单位,值有TimeUnit.MILLISECONDS(毫秒),TimeUnit.SECONDS(秒),TimeUnit.MINUTES(秒)等。

workQueue:线程池中的任务队列,通过线程池的execute方法提交的Runnable对象会存储在这个参数中。

threadFactory:线程工厂,为线程池提供创建新线程的功能。ThreadFactory是一个接口.

它只有一个方法:Thread newThread(Runnable r);


最后给大家的优化建议

1)避免创建过多的对象。
2)不要过多使用枚举,枚举占用的内存空间要比整形大。
3)常量请使用static final 来修饰。
4)使用安卓特有的数据结构,比如SparseArray和Pair等,他们都具有更好的性能。
5)适当使用软引用,和弱引用。
6)采用内存缓存和磁盘缓存。
7)尽量采用静态内部类,这样可以避免潜在的由于内部类而导致的内存泄漏。
(内存泄漏工具分析------MAT)
8)尽量用局部变量
10)合理使用浮点类型
11)及时动态回收不用的资源(str=null,btm.Recycle())

12)移除Acitivty默认背景,getWindow().setBackgroundDtawable(null)