GridView内存及时释放,不需要使用软引用
2015-03-26 16:41
141 查看
突然写上瘾了,就把这个得意之作发上来吧,这个内存释放可是花费了我将近一周呢,显示搞懂gridview机制,然后是进行优化,反正是搞死我了。
先说软引用吧,不得不说软引用是个非常好的解决OOM的方法,只要系统内存不够就会释放掉软引用中不需要的bitmap,但是经我测试这个也并不是及时释放的,我一屏显示20张图片的话,有时内存中会存在60多张图片,这个是我不能容忍的,我最多让它存在30张,多了如果我在此时处理一个需要很大内存的动作,系统会提高heapsize,这是会出现OOM的。
我的解决办法:人为及时释放内存,保证内存中图片不超过30张。
原理:gridview有两个参数,getFirstVisiblePosition和getLastVisiblePosition,这两个参数意思是当前显示的第一张图片的position和最后一张图片的position,有了这两个我们就可以有选择的释放内存了,此范围外的都是可以释放的。
我的代码:
其中cleanbitmapArrayList方法是不需要整个gridview的时候调用的,它会释放所有的bitmap资源,cleanGridView方法除了自身调用外,比如处理大内存消耗动作而且还要保留此gridview时也可以调用,可清除额外内存,其中有点要说明,Integer)bitmapArrayList.get(k).get("ID")>=(gridviewFirst-3),之所以减三加三,是我自己做的一个缓存区,可以调大,但是如果不减任何数肯定会报错,如果有try to use a recyclee
bitmap 那就是这里出问题了,数字一般最好为你一行显示的个数。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
这都是12年写的文章了,现在已经有更好的代替方法,直接使用LruCache和DiskLruCache做缓存就行,Android既然已经提供了这么好用的缓存我们就不用再多此一举啦。
先说软引用吧,不得不说软引用是个非常好的解决OOM的方法,只要系统内存不够就会释放掉软引用中不需要的bitmap,但是经我测试这个也并不是及时释放的,我一屏显示20张图片的话,有时内存中会存在60多张图片,这个是我不能容忍的,我最多让它存在30张,多了如果我在此时处理一个需要很大内存的动作,系统会提高heapsize,这是会出现OOM的。
我的解决办法:人为及时释放内存,保证内存中图片不超过30张。
原理:gridview有两个参数,getFirstVisiblePosition和getLastVisiblePosition,这两个参数意思是当前显示的第一张图片的position和最后一张图片的position,有了这两个我们就可以有选择的释放内存了,此范围外的都是可以释放的。
我的代码:
[代码]java代码:
/** * * Copyright 2012 HISENSE. All rights reserved. * DirListAdapter.java * */ package com.hisense.hicloud.album.hiview; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.GridView; import android.widget.ImageView; import com.hisense.hicloud.album.HiCloudAlbum; import com.hisense.hicloud.album.HiCloudApplication; import com.hisense.hicloud.album.R; import com.hisense.hicloud.album.imagecache.AsyncImageLoader; import com.hisense.hicloud.album.imagecache.HiImageView; import com.hisense.hicloud.album.imagecache.LocationImageCache; import com.hisense.hicloud.album.imagecache.AsyncImageLoader.BitmapCallback; import com.hisense.hicloud.album.imagecache.LocationImageCache.OnLoadImageListener; import com.hisense.hicloud.album.scanfiles.ImageListBean; import com.hisense.hicloud.album.sys.SYSPath; /** * @author qiuxiaolong (qiuxiaolong1@hisense.com) * @date 2012-2-13 */ public class LocalImageAdapter2 extends BaseAdapter { private Context context; private static ArrayList<String> imagePathList; private LayoutInflater inflater; private ViewHolder holder = null; private AsyncImageLoader imageLoader; private String LocalThumbPath;//本地图片缩略图地址 private static String TAG = "LocalImageAdapter2"; /**存放bitmap与position*/ public static ArrayList<HashMap<String,Object>> bitmapArrayList = new ArrayList<HashMap<String,Object>>(); //获取LocalGridView对象 private GridView gridview; /**记步,记录getView执行次数,六次一循环*/ private static int local_i = 0; /**记录gridview中第一张和最后一张图片的position*/ private static int gridviewFirst = 0; private static int gridviewLast = 0; public LocalImageAdapter2(){} public LocalImageAdapter2(Context context,ArrayList<String> callList,GridView gridview) { this.context = context; this.imagePathList = callList; for (String url : imagePathList) { Log.d("==========Image Url==========", url); } inflater = LayoutInflater.from(this.context); imageLoader = new AsyncImageLoader(true, context); this.gridview = gridview; //judge that whether the bitmapArrayList is null CloudImageAdapter cloudimageadapter = new CloudImageAdapter(); if(cloudimageadapter.getbitmapArrayListSize() != 0){ //clean the bitmapArrayList cloudimageadapter.cleanbitmapArrayList(); } } public void removeAdpterList(ArrayList<String> removeList) { System.out.println("=============删除元数据:"+removeList.size()); System.out.println("=============前:"+imagePathList.size()); imagePathList.removeAll(removeList); System.out.println("=============后:"+imagePathList.size()); } public int getCount() { return imagePathList.size(); } public Object getItem(int position) { return imagePathList.get(position); } public long getItemId(int position) { return position; } /**return bitmapArrayList size*/ public int getbitmapArrayListSize(){ return bitmapArrayList.size(); } /**clean bitmapArrayList all*/ public void cleanbitmapArrayList(){ for(int k = 0;k < bitmapArrayList.size();k++){ if(bitmapArrayList.get(k).get("bitmap") != null){ //get bitmap from hashmap Bitmap bitmap1 = (Bitmap) bitmapArrayList.get(k).get("bitmap"); try{ if(!bitmap1.isRecycled()){ bitmap1.recycle(); Log.i(TAG,"clean bitmapArrayList success,print position:" + (Integer)bitmapArrayList.get(k).get("ID")); //remove this element bitmapArrayList.remove(k); k--; } }catch(Exception e){ Log.e(TAG,"clean bitmapArrayList error"); e.printStackTrace(); } } } } /**clean bitmap that not in gridview*/ public void cleanGridView(){ //select bitmaps what can be recycled for(int k = 0;k < bitmapArrayList.size();k++){ //keep these bitmaps which between first and last if((Integer)bitmapArrayList.get(k).get("ID")>=(gridviewFirst-3) && (Integer)bitmapArrayList.get(k).get("ID") <= (gridviewLast + 3)){ //in the range,do nothing Log.i(TAG,"in the range continue,print the k:" + k + ";and print the position:" + (Integer)bitmapArrayList.get(k).get("ID")); continue; } //get the bitmap from hashmap Bitmap bitmap1 = (Bitmap) bitmapArrayList.get(k).get("bitmap"); if(bitmap1 != null){ try{ Log.i(TAG,"start to recycle,print the position:" + (Integer)bitmapArrayList.get(k).get("ID") + ";print first position:" + gridviewFirst + ";print last position:" + gridviewLast); if(!bitmap1.isRecycled()){ Log.i(TAG,"can be recycled,the id of bitmap:" + bitmap1.toString()); //do the action bitmap1.recycle(); Log.i(TAG,"success to recycle,print the position:" + (Integer)bitmapArrayList.get(k).get("ID")); //remove this element bitmapArrayList.remove(k); k--; } }catch(RuntimeException e){ Log.e(TAG,"the bitmap can't be recycled,print the position:" + (Integer)bitmapArrayList.get(k).get("ID")); e.printStackTrace(); } } } //do gc System.gc(); } public View getView( final int position, View convertView, final ViewGroup parent) { Log.e(TAG,"print the position:" + position + ";print bitmapArrayList size:" + bitmapArrayList.size()); //get current first position and last position gridviewFirst = gridview.getFirstVisiblePosition(); gridviewLast = gridview.getLastVisiblePosition(); //do the clean action for every six if(local_i == 6){ local_i = 0; //do the clean action //cleanGridView(); } if (convertView == null) { holder = new ViewHolder(); if(HiCloudAlbum.album_orientation == HiCloudAlbum.ALBUM_ORIENTATION_LANDSCAPE) convertView = inflater.inflate(R.layout.image_local_gridview_item_land, null); else convertView = inflater.inflate(R.layout.image_local_gridview_item, null); holder.img = (HiImageView) convertView .findViewById(R.id.image_thumbnail); holder.mask = (ImageView) convertView.findViewById(R.id.masklayer); holder.uploaded = (ImageView)convertView.findViewById(R.id.uploadedlayer); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.img.setTag(imagePathList.get(position)); if (LocalGridView.getAlreadUploadList().contains(imagePathList.get(position))) { holder.uploaded.setVisibility(View.VISIBLE); holder.mask.setVisibility(View.GONE); }else { if (LocalGridView.getSelectedItemsList().contains(imagePathList.get(position))) { holder.mask.setVisibility(View.VISIBLE); }else { holder.mask.setVisibility(View.GONE); } holder.uploaded.setVisibility(View.GONE); } //计算本地缩略图存放地址 LocalThumbPath = SYSPath.LocalThumCachePATH + "/" + imagePathList.get(position).substring(imagePathList.get(position).lastIndexOf("/")+1) + "_Thum.jpg"; Bitmap bitmap = null; boolean flag = false; Log.d(TAG,"输出LocalThumbPath" + LocalThumbPath); //if the bitmap is in the bitmapArrayList,then get it from bitmapArrayList /*for(int i = 0;i<bitmapArrayList.size();i++){ //Comparison the position if(bitmapArrayList.get(i).get("ID").toString().equals(String.valueOf(position))){ Log.i(TAG,"have the same position,print this position:" + position); //get bitmap from hashmap bitmap = (Bitmap)bitmapArrayList.get(i).get("bitmap"); holder.img.setImageBitmap(null); holder.img.setImageBitmap(bitmap); //set to be true,then skip getting bitmap from local flag = true; break; } }*/ if(flag == false){ //mark add local_i++; Log.i(TAG,"print the local_i" + local_i); //get bitmap from local //bitmap = AsyncImageLoader.getCacheBitmap(LocalThumbPath,position); bitmap = AsyncImageLoader.getCacheBitmap(imagePathList.get(position)); if (bitmap != null) { Log.i(TAG,"success to get the bitmap at section one"); holder.img.setImageBitmap(null); holder.img.setImageBitmap(bitmap); //bitmapArrayList add bitmapArrayListAdd(position,bitmap,"one"); }else{ Log.i(TAG,"can't find bitmap from local,bitmap is null,now start to create thumb picture and get bitmap from it"); //bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.fipper_loading); holder.img.setImageBitmap(null); imageLoader.loadLocalBitmap(imagePathList.get(position),LocalThumbPath,new BitmapCallback() { //imageLoader.loadLocalBitmap(imagePathList.get(position),LocalThumbPath, position,new BitmapCallback() { public void imageLoaded(Bitmap imageBitmap, String imageUrl) { // TODO Auto-generated method stub HiImageView iv = (HiImageView) parent.findViewWithTag(imageUrl); if (iv != null && imageBitmap != null) { Log.i(TAG,"success to get the bitmap at section two"); iv.setImageBitmap(null); iv.setImageBitmap(imageBitmap); //bitmapArrayList add bitmapArrayListAdd(position,imageBitmap,"two"); } } }); } } return convertView; } /**bitmapArrayList add*/ private void bitmapArrayListAdd(int position,Bitmap bitmap,String section){ Log.d(TAG,"at section "+section+" print the id of bitmap:" + bitmap.toString() + ";print the position" + position); //create map to put information HashMap<String,Object> map = new HashMap<String,Object>(); map.put("ID", position); //map.put("bitmap", bitmap); //add bitmapArrayList bitmapArrayList.add(map); Log.d(TAG,"success and over at section " + section); } public class ViewHolder { public HiImageView img; public ImageView mask; public ImageView uploaded; } }
其中cleanbitmapArrayList方法是不需要整个gridview的时候调用的,它会释放所有的bitmap资源,cleanGridView方法除了自身调用外,比如处理大内存消耗动作而且还要保留此gridview时也可以调用,可清除额外内存,其中有点要说明,Integer)bitmapArrayList.get(k).get("ID")>=(gridviewFirst-3),之所以减三加三,是我自己做的一个缓存区,可以调大,但是如果不减任何数肯定会报错,如果有try to use a recyclee
bitmap 那就是这里出问题了,数字一般最好为你一行显示的个数。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
这都是12年写的文章了,现在已经有更好的代替方法,直接使用LruCache和DiskLruCache做缓存就行,Android既然已经提供了这么好用的缓存我们就不用再多此一举啦。
相关文章推荐
- 使用句柄和引用计数器避免浅拷贝和浅赋值后内存空间二次释放
- 【C++】使用局部变量赋值而非引用,导致内存多次释放的野指针问题
- Bitmap的使用习惯——及时释放Bitmap占用的内存
- block里面的self要使用弱引用,否则会无法释放内存
- Bitmap的使用习惯——及时释放Bitmap占用的内存
- 【C++】使用局部变量赋值而非引用,导致内存多次释放的野指针问题
- 引用之局部变量释放内存空间后的随机指向
- C++备忘 STL释放内存 ,weka使用备忘
- 指针的引用与正常指针 释放内存的另一例比较
- 使用CRT调试内存分配堆来找出未释放的内存空间
- 销毁COM对象引用时内存异常。(未释放资源导致)
- 关于什么时候使用CoTaskMemAlloc/CoTaskMemFree来申请/释放内存
- 在IIS6下w3wp.exe的内存及CPU占用不能及时释放问题
- 转(w3wp的内存占用不能及时释放)
- session不及时释放导致内存溢出的性能问题分析
- 使用CRT调试内存分配堆来找出未释放的内存空间
- 使用CRT调试内存分配堆来找出未释放的内存空间
- GridView里使用 DropDownList 更新数据列,不需要写一句代码
- 使用Singleton需要考虑内存释放
- 使用二级指针分配和释放内存示例 malloc(), free()