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

       最近开发了一款和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内存溢出问题,但是性能上还有待优化



     

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值