您的位置:

Android内存优化

一、内存泄漏

1、什么是内存泄漏

内存泄漏指在程序运行过程中分配的内存空间没有及时释放,导致内存空间占用过多,造成程序的崩溃或者系统的崩溃的现象。一般体现为App启动后,内存不断增加,操作时间越长,内存越大,容易造成ANR或者崩溃。

2、常见的内存泄漏场景

a.静态变量被持有:

``` public class Singleton{ private static Singleton instance; public static Singleton getInstance(){ if(instance ==null){ instance =new Singleton(); } return instance; } //... } ```

在单例模式中,只要有一个对象持有了该类的引用,那么这个对象和其中的所有成员信息都不会被回收,从而引发了内存泄漏。

b.handler引起内存泄漏:

``` public class MainActivity extends Activity{ private Handler mHandler =new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); } }; //... } ```

在Activity中使用了handler,由于handler持有外部类Activity的引用,那么当Activity被摧毁时,由于handler还持有Acitivity的引用,会导致Activity无法被回收。此时,建议在Activity退出时清除handler的消息队列。

c.监听器泄漏:

``` public class MainActivity extends Activity{ private MyOnClickListener mListener =new MyOnClickListener(){ @Override public void onClick(View view) { } }; //... @Override protected void onDestroy() { super.onDestroy(); mButton.setOnClickListener(null); } } ```

在Activity中使用监听器时,如果不及时销毁,会造成Activity的内存泄漏,同样的,在Activity销毁时,需要及时清除持有监听器的引用。

二、Bitmap优化

1、Bitmap内存计算

Bitmap在内存中占用的大小=图片的宽度*图片的高度*每个像素点的字节数。

2、Bitmap内存优化

a.采样率缩放

``` public static Bitmap decodeSampledBitmapFromFile(String filename,int width,int height){ final BitmapFactory.Options options =new BitmapFactory.Options(); options.inJustDecodeBounds =true; BitmapFactory.decodeFile(filename,options); options.inSampleSize =calculateInSampleSize(options,width,height); options.inJustDecodeBounds =false; return BitmapFactory.decodeFile(filename,options); } public static int calculateInSampleSize(BitmapFactory.Options options,int reqWidth,int reqHeight){ final int height =options.outHeight; final int width =options.outWidth; int inSampleSize =1; if(height> reqHeight|| width >reqWidth ){ final int heightRatio =Math.round((float)height/ (float)reqHeight); final int widthRatio =Math.round((float)width/ (float)reqWidth); inSampleSize =heightRatio b.使用软引用和弱引用

``` public HashMap > imageCache =new HashMap >(); //... SoftReference reference = new SoftReference (bitmap); imageCache.put(url, reference); ```

c.LruCache

``` public class MemoryCache extends LruCache { public MemoryCache(int maxSize) { super(maxSize); } @Override protected int sizeOf(String key, Bitmap value) { return value.getRowBytes()*value.getHeight(); } @Override protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) { super.entryRemoved(evicted, key, oldValue, newValue); //释放oldValue的内存空间 oldValue.recycle(); } } //... int maxMemory = (int)(Runtime.getRuntime().maxMemory()/1024); int cacheSize =maxMemory/8; mMemoryCache =new MemoryCache(cacheSize); ```

三、布局优化

1、Layout XML的优化

a.使用include标签

``` ```

b.使用RelativeLayout,减少deep-level嵌套

``` ```

c.不使用过于复杂的布局文件

2、代码布局优化

a.手动布局时,减少measure和layout的操作次数

``` private LinearLayout layoutExample; layoutExample.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT)); layoutExample.setOrientation(LinearLayout.VERTICAL); TextView textView=new TextView(context); textView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); textView.setText("Custom Text"); layoutExample.addView(textView); setContentView(layoutExample); ```

b.使用自定义View,复用已有的控件

四、资源文件优化

1、资源文件分类

将资源文件按不同的类型进行分类,方便开发和维护。

2、资源文件压缩

a.使用lint工具

打开Android Studio中的预编译检查功能,可检测和提示不必要的资源文件,方便开发时的及时优化。

b.使用TinyPNG或者PngQuant工具

可以无损或者有损地对图片资源进行压缩,减小apk的大小。

五、线程优化

1、线程池的使用

a.避免反复地创建和销毁线程,提高线程的重复利用率。

b.通过Executors类创建线程池,来控制线程的数量和资源。

``` //使用newFixedThreadPool来创建线程池 ExecutorService threadPool = Executors.newFixedThreadPool(THREAD_POOL_SIZE); //提交任务 threadPool.execute(new Runnable() { @Override public void run() { //... } }); ```

2、AsyncTask的使用

通过AsyncTask来处理UI线程和后台线程的交互,避免在主线程中进行长时间的操作,从而导致ANR。

``` public class DownloadTask extends AsyncTask { @Override protected String doInBackground(String... params) { //这里进行耗时操作 return result; } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); //更新进度条 } @Override protected void onPostExecute(String s) { super.onPostExecute(s); //更新UI } } ```

3、使用Handler和ThreadLocal减少内存占用

a.Handler

``` private static class MyHandler extends Handler{ private final WeakReference mActivity; public MyHandler(Activity activity){ mActivity =new WeakReference (activity); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); if(mActivity.get()!=null){ //执行UI操作或者其他操作 } } } private MyHandler mHandler =new MyHandler(this); ```

b.ThreadLocal

``` private ThreadLocal threadLocal =new ThreadLocal (){ @Override protected SimpleDateFormat initialValue() { return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); } }; private class SimpleThread extends Thread{ @Override public void run() { SimpleDateFormat sdf =threadLocal.get(); //... } } ```

六、APP启动优化

1、延迟加载

a.使用Fragment或者ViewPager可以延迟加载不必要的资源或者页面。

``` public class MyFragment extends Fragment{ //... @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); if(isVisibleToUser){ //加载数据或者页面 }else{ //释放资源 } } } ```

b.通过线程池进行延迟加载和预加载,提高App启动速度。

2、懒加载

延迟加载过后,还可以通过懒加载的方式加载不必要的资源,提高App的启动速度。

``` public class LazyLoadFragment extends Fragment{ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView =inflater.inflate(R.layout.fragment_lazy,container,false); return rootView; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); if(getUserVisibleHint()){ //加载数据或者页面 } } @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); if(isVisibleToUser&&isAdded()){ //加载数据或者页面 } } } ```

七、总结

内存优化是Android开发中的一个重要环节,在开发过程中,多注意内存泄漏的问题,对Bitmap进行优化和管理,对布局和资源文件进行分类和压缩,选用合适的线程池和AsyncTask,延迟和懒加载,可以大大提高App的启动速度和运行效率。