在android程序中,为了避免OOM的出现,最为直接的方式就是将Bitmap占用的内存Recycle掉。但是在一个布局或者控件中,图片非常多,来源又不一样。这个时候,写代码手动的释放,也蛮费事的。
所以我封装了一个工具类,只要将当前activity所在的布局传入工具类,工具类会自动释放布局中所有Imageview占用的图片资源。
说明:此工具类用于回收布局中被Imageview占用的图片资源,传入根布局,或者继承自ViewGroup类的子类。
适用范围: ViewGroup的直接或间接子类
常用的的布局类(如线性布局,相对布局,帧布局,绝对布局)都是继承自ViewGroup基类,为了弄明白适用范围,我们来看一下ViewGroup的直接和间接子类:
Known Direct Subclasses(儿子辈)
AbsoluteLayout, AdapterView<T extends Adapter>, FragmentBreadCrumbs, FrameLayout, GridLayout, LinearLayout,
PagerTitleStrip, RelativeLayout,SlidingDrawer, ViewPager
Known Indirect Subclasses(孙子辈)
Base class that can be used to implement virtualized lists of items.
An abstract base class for spinner widgets.
Base class for a
AdapterView
that will perform animations when switching between its views.Simple
ViewAnimator
that will animate between two or more views that have been added to it.Provides the glue to show AppWidget views.
This class is a calendar widget for displaying and selecting dates.
This class is a widget for selecting a date.
A view that shows items in a vertically scrolling two-level list.
This class was deprecated in API level 16. This widget is no longer supported. Other horizontally scrolling widgets include
HorizontalScrollView
andViewPager
from the support library.A transparent overlay for gesture input that can be placed on top of other widgets or contain other widgets.
A view that shows items in two-dimensional scrolling grid.
Layout container for a view hierarchy that can be scrolled by the user, allowing it to be larger than the physical display.
A view that shows items in a vertically scrolling list.
A view containing controls for a MediaPlayer.
A widget that enables the user to select a number form a predefined range.
PagerTabStrip is an interactive indicator of the current, next, and previous pages of a
ViewPager
.This class is used to create a multiple-exclusion scope for a set of radio buttons.
Layout container for a view hierarchy that can be scrolled by the user, allowing it to be larger than the physical display.
A widget that provides a user interface for the user to enter a search query and submit a request to a search provider.
A view that displays one child at a time and lets the user pick among them.
Container for a tabbed window view.
Displays a list of tab labels representing each page in the parent's tab collection.
A layout that arranges its children into rows and columns.
A layout that arranges its children horizontally.
Specialized
ViewSwitcher
that contains only children of typeTextView
.A view for selecting the time of day, in either 24 hour or AM/PM mode.
A view group with two children, intended for use in ListViews.
Base class for a
FrameLayout
container that will perform animations when switching between its views.Simple
ViewAnimator
that will animate between two or more views that have been added to it.
ViewAnimator
that switches between two views, and has a factory from which these views are created.A View that displays web pages.
The
ZoomControls
class displays a simple set of controls used for zooming and provides callbacks to register for events.
以上内容在ViewGroup的文档中都有介绍,这里不再赘述。
回收的内容:
说完了布局文件,接下来说一下需要回收Imageview中的哪些东东。
ImageView显示图片有两种方式:
1.代码或者xml文件中设置为背景
2.代码或者xml文件中设置Imageview的内容,如xml中的src,代码中的setImageResource等等。
总之,看起来背景图片和内容图片不一样,我们分开回收。默认回收内容图片,背景图片是否回收可以自行设置。
使用场景:
当Activity退出时,需要清理和释放图片资源时,使用此类。
好了,废话不多说了,上代码:
package com.liubing; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; /** * 工具类 * 释放布局中所有Imageview组件占用的图片,可设置是否释放背景图 * 用于退出时释放资源,调用完成后,请不要刷新界面 * @author liubing * */ public class RecycleBitmapInLayout { private static final String TAG = "RecycleBitmapInLayout"; /*是否释放背景图 true:释放;false:不释放*/ private boolean flagWithBackgroud = false; /** * * @param flagWithBackgroud 是否同时释放背景图 */ public RecycleBitmapInLayout(boolean flagWithBackgroud) { this.flagWithBackgroud = flagWithBackgroud; } /** * 释放Imageview占用的图片资源 * 用于退出时释放资源,调用完成后,请不要刷新界面 * @param layout 需要释放图片的布局 * */ public void recycle(ViewGroup layout) { for (int i = 0; i < layout.getChildCount(); i++) { //获得该布局的所有子布局 View subView = layout.getChildAt(i); //判断子布局属性,如果还是ViewGroup类型,递归回收 if (subView instanceof ViewGroup) { //递归回收 recycle((ViewGroup)subView); } else { //是Imageview的子例 if (subView instanceof ImageView) { //回收占用的Bitmap recycleImageViewBitMap((ImageView)subView); //如果flagWithBackgroud为true,则同时回收背景图 if (flagWithBackgroud) { recycleBackgroundBitMap((ImageView)subView); } } } } } private void recycleBackgroundBitMap(ImageView view) { if (view != null) { BitmapDrawable bd = (BitmapDrawable) view.getBackground(); rceycleBitmapDrawable(bd); } } private void recycleImageViewBitMap(ImageView imageView) { if (imageView != null) { BitmapDrawable bd = (BitmapDrawable) imageView.getDrawable(); rceycleBitmapDrawable(bd); } } private void rceycleBitmapDrawable(BitmapDrawable bd) { if (bd != null) { Bitmap bitmap = bd.getBitmap(); rceycleBitmap(bitmap); } bd = null; } private void rceycleBitmap(Bitmap bitmap) { if (bitmap != null && !bitmap.isRecycled()) { Log.e(TAG, "rceycleBitmap"); bitmap.recycle(); bitmap = null; } } }
使用方法:当退出activity时调用,如
@Override public boolean onKeyDown(int keyCode, KeyEvent event) { // TODO Auto-generated method stub if (keyCode == event.KEYCODE_BACK && event.getRepeatCount() == 0) { //回收图片 new RecycleBitmapInLayout(true).recycle(rootLayout); //退出时,请求杀死进程 android.os.Process.killProcess(android.os.Process.myPid()); } return super.onKeyDown(keyCode, event); }
存在问题:释放的时机不恰当,会造成”trying to use a recycled bitmap android.graphics.Bitmap”的错误,请谨慎使用
总结:是一个管杀不管埋的工具类。
附Demo:点我下载
原文链接:http://www.67tgb.com/?p=517
欢迎访问:望月听涛