android内存溢出等各种常见问题

来源:互联网 发布:中国农业银行程序员岗 编辑:程序博客网 时间:2024/04/30 02:19

       最近开发了一款和LBS相结合的android软件。项目虽小,但在开发过程中遇到的问题却是不少。今天写此博文,一为总结,再次理一下在解决问题时的思考过程;二为分享,希望遇到同样问题的童鞋们有一个参考;三为交流学习,虽然有些解决方法没有bug,但性能上本人还不甚满意,如果您有更好的解决办法或发现任何问题,欢迎批评指正,多多交流学习。

下面列举出我所遇到的问题及解决方法(注:所有测试都是基于android 4.0.4系统)。

1).百度地图刷新得不到及时响应,出现灰色区域

   解决方法:在manifest文件中的application标签下添加 android:hardwareAccelerated="false",但添加之后还是不行。最后在 非主activity(主activity:启动软件显示的第一个activity)中添加 android:hardwareAccelerated="true",启用硬件加速,然后地图响应就很流畅了。

2).用腾讯微博开放平台发表带图片的微博时抛NetWorkOnMainThreadException

  解决方法:在onCreate方法中添加如下代码就OK了:

StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork().penaltyLog().build());

在2.3以前的系统中不会出现此问题。或者通过异步方式进行此操作,因为它说的是**OnMainThread**,那么不在主线程中进行这种耗时的网络操作,就不会有问题了。

3).Context的使用问题

  大家都知道,context容易引发内存溢出,而且很隐蔽,所以大多数情况都尽量使用Application context,因为这种context和Application有相同的生命周期,不会引起内存泄露。但当我要显示一个AlertDialog时,使用Application context就会抛出异常:android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application,必须使用Activity context。查看google提供的文档,Activity->ContextThemeWrapper->ContextWrapper->Context;Application->ContextWrapper->Context,可以看出Context是Activity和Application的父类,通过Activity和Application都可以获得Context对象。但问题就是,显示dialog相当于显示一个自定义窗口,Application context是无法获得Window对象的,而Activity可以通过getWindow()方法获得Window对象。为了防止context引发的内存溢出,请记住以下3点:

  1. 不要让生命周期长的对象引用activity context,即保证引用activity的对象要与activity本身生命周期是一样的
  2. 对于生命周期长的对象,可以使用application context
  3. 避免非静态的内部类,尽量使用静态内部类,避免生命周期问题,注意内部类对外部对象引用导致的生命周期变化
4).Bitmap内存溢出问题

  这是我遇到的最头疼的一个问题,在网上也查了很多资料,大多数都一样。如弱引用(WeakReference),软引用(SoftReference)等,这些在一定程度上的确可以优化,但并不能彻底解决问题,图片很多的时候,还是会出现内存溢出。最主要的还是要及时回收bitmap,这个及时,,如何及时?在网上看到一些方法:

 //前面还有部分代码未贴出      originalImage = BitmapFactory.decodeFile(path, options);        width = originalImage.getWidth();        height = originalImage.getHeight();        Bitmap bitmapWithReflection = Bitmap.createBitmap(dw,                dh, Config.ARGB_8888);        Canvas canvas = new Canvas(bitmapWithReflection);        canvas.drawBitmap(originalImage, 0, 0, null);      ImageView imageView = new ImageView(mContext);      imageView.setImageBitmap(originalImage);      imageView.setLayoutParams(new GalleryFlow.LayoutParams(width, height));      mImages[index++]=imageView;        bitmapWithReflection.recycle();        bitmapWithReflection = null;        System.gc();
这样如果马上回收originalImage,图片就无法显示;显示后再回收由于每初始化一张图片,originalImage对象就会指向另一块内存,而指向原来的bitmap内存的对象则被覆盖了,当我们要回收该bitmap时,却发现找不到指向该内存的对象,自然也就无法回收了。

        我的解决方法是:延迟加载图片,每初始化一张图片,就把bitmap对象存储在一个Bitmap数组中,ImageView再从该数组中取得对应的bitmap。需要回收的时候,可以通过数组中bitmap对象来释放所占用的内存。不管有多少图片,都可以保证在内存中的图片数量不超过M张(M可由自己控制,如8张。通过option参数可以控制加载到内存的图片的大小,一般800*600*4=1920000byte=1.8M,8张一般不会超出android单个程序内存限制)。部分代码如下:

public View getView(int position, View convertView, ViewGroup parent) {if(convertView==null){if(mImages[position]==null && bitmaps[position]==null){int high = position+mem_size;/** * 当图片的索引位置大于或等于mem_size时,要考虑回收两头的bitmap内存; * 否则只需考虑回收后面的内存。 */if(position>=mem_size){int low=position-mem_size;if(bitmaps[low]!=null){this.destory(low);}if(high<size && bitmaps[high]!=null){this.destory(high);}}else{if(high<size && bitmaps[high]!=null){this.destory(high);}}System.gc();try {ImageView imageView = new ImageView(mContext);bitmaps[position]=this.createView(paths.get(position));imageView.setImageBitmap(bitmaps[position]);imageView.setLayoutParams(new GalleryFlow.LayoutParams(width, height));mImages[position]=imageView;} catch (Exception e) {e.printStackTrace();}finally{convertView=mImages[position];}}else{convertView=mImages[position];}}return convertView;} private void destory(int index){        bitmaps[index].recycle();        bitmaps[index]=null;        mImages[index]=null; }

算是解决了bitmap内存溢出问题,但是性能上还有待优化



     

原创粉丝点击