Android中的软引用(SoftRefrerence)和弱引用(WeakReference)

来源:互联网 发布:多维数据可视化方法 编辑:程序博客网 时间:2024/05/21 09:48

   在Android开发中,基本上很少有用到软引用或弱引用,这两个东东若用的很好,对自己开发的代码质量的提高有很大的帮助。若用的不好,会坑了自己。所以,在还没有真正的去了解它们之前,还是慎用比较好。

   下面将通过两个Demo来结识软引用和弱引用在开发中的运用。

   一. WeakReference:防止内存泄漏,要保证内存被虚拟机回收。

        下面以一个时间更新的Demo来说明弱引用的运用。

         1. main.xml文件代码如下:   

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="vertical" >    <com.stevenhu.wrt.DigitalClock        android:layout_width="match_parent"        android:layout_height="match_parent"        android:orientation="horizontal">                <TextView android:id="@+id/time"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:textSize="50pt"            />                <TextView android:id="@+id/ampm"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:textSize="25pt"            />            </com.stevenhu.wrt.DigitalClock></LinearLayout>
       2.自定义ViewGroup类DigitalClock的代码如下:

package com.stevenhu.wrt;import java.lang.ref.WeakReference;import java.text.DateFormatSymbols;import java.util.Calendar;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.database.ContentObserver;import android.graphics.Canvas;import android.os.Handler;import android.provider.Settings;import android.text.format.DateFormat;import android.util.AttributeSet;import android.view.View;import android.widget.LinearLayout;import android.widget.TextView;import android.widget.Toast;public class DigitalClock extends LinearLayout {// 12小时、24小时制private final static String M12 = "h:mm";private final static String M24 = "kk:mm";private Calendar mCalendar;private String mFormat;private TextView mDislpayTime;private AmPm mAmPm;private ContentObserver mFormatChangeObserver;private final Handler mHandler = new Handler();private BroadcastReceiver mReceiver;private Context mContext;public DigitalClock(Context context, AttributeSet attrs) {super(context, attrs);mContext = context;// TODO Auto-generated constructor stub}@Overrideprotected void onFinishInflate() {// TODO Auto-generated method stubsuper.onFinishInflate();mDislpayTime = (TextView) this.findViewById(R.id.time);mAmPm = new AmPm(this);mCalendar = Calendar.getInstance();//设置时间显示格式setDateFormat();}@Overrideprotected void onAttachedToWindow() {// TODO Auto-generated method stubsuper.onAttachedToWindow();//动态注册监听时间改变的广播if (mReceiver == null) {mReceiver = new TimeChangedReceiver(this);IntentFilter filter = new IntentFilter();filter.addAction(Intent.ACTION_TIME_TICK);filter.addAction(Intent.ACTION_TIME_CHANGED);filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);mContext.registerReceiver(mReceiver, filter);}//注册监听时间格式改变的ContentObserverif (mFormatChangeObserver == null) {mFormatChangeObserver = new FormatChangeObserver(this);mContext.getContentResolver().registerContentObserver(Settings.System.CONTENT_URI, true, mFormatChangeObserver);}//更新时间updateTime();}@Overrideprotected void onDetachedFromWindow() {// TODO Auto-generated method stubsuper.onDetachedFromWindow();if (mReceiver != null) {mContext.unregisterReceiver(mReceiver);}if (mFormatChangeObserver != null) {mContext.getContentResolver().unregisterContentObserver(mFormatChangeObserver);}mFormatChangeObserver = null;mReceiver = null;}static class AmPm {private TextView mAmPmTextView;private String mAmString, mPmString;AmPm(View parent) {mAmPmTextView = (TextView) parent.findViewById(R.id.ampm);String[] ampm = new DateFormatSymbols().getAmPmStrings();mAmString = ampm[0];mPmString = ampm[1];}void setShowAmPm(boolean show) {if (mAmPmTextView != null) {mAmPmTextView.setVisibility(show ? View.VISIBLE : View.GONE);}}void setIsMorning(boolean isMorning) {if (mAmPmTextView != null) {mAmPmTextView.setText(isMorning ? mAmString : mPmString);}}}/*时间刷新涉及到View的更新显示(特别是每秒刷新显示,这样的频率特别高),当然,此处的时间显示是每分钟更新一次 * 所以在监听时间更新的广播中采用弱引用,防止在不断刷新当前界面View时产生内存泄露 */private static class TimeChangedReceiver extends BroadcastReceiver {//采用弱引用private WeakReference<DigitalClock> mClock;private Context mContext;public TimeChangedReceiver(DigitalClock clock) {mClock = new WeakReference<DigitalClock>(clock);mContext = clock.getContext();}@Overridepublic void onReceive(Context context, Intent intent) {// Post a runnable to avoid blocking the broadcast.final boolean timezoneChanged = intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED);//从弱引用中获取对象final DigitalClock clock = mClock.get();if (clock != null) {clock.mHandler.post(new Runnable() {public void run() {if (timezoneChanged) {clock.mCalendar = Calendar.getInstance();}clock.updateTime();}});} else {try {mContext.unregisterReceiver(this);} catch (RuntimeException e) {// Shouldn't happen}}}};// 监听时间显示的格式改变private static class FormatChangeObserver extends ContentObserver {// 采用弱应用private WeakReference<DigitalClock> mClock;private Context mContext;public FormatChangeObserver(DigitalClock clock) {super(new Handler());mClock = new WeakReference<DigitalClock>(clock);mContext = clock.getContext();}@Overridepublic void onChange(boolean selfChange) {DigitalClock digitalClock = mClock.get();//从弱引用中取出对象if (digitalClock != null) {//根据弱引用中取出的对象进行时间更新digitalClock.setDateFormat();digitalClock.updateTime();} else {try {mContext.getContentResolver().unregisterContentObserver(this);} catch (RuntimeException e) {// Shouldn't happen}}}}// 更新时间private void updateTime() {Toast.makeText(mContext, "updateTime", Toast.LENGTH_SHORT).show();mCalendar.setTimeInMillis(System.currentTimeMillis());CharSequence newTime = DateFormat.format(mFormat, mCalendar);mDislpayTime.setText(newTime);mAmPm.setIsMorning(mCalendar.get(Calendar.AM_PM) == 0);}private void setDateFormat() {// 获取时间制mFormat = android.text.format.DateFormat.is24HourFormat(getContext()) ? M24: M12;// 根据时间制显示上午、下午mAmPm.setShowAmPm(mFormat.equals(M12));}@Overrideprotected void onDraw(Canvas canvas) {// TODO Auto-generated method stubsuper.onDraw(canvas);//Toast.makeText(mContext, "ddd", Toast.LENGTH_SHORT).show();}}
      3.MainActivity的代码如下:  

package com.stevenhu.wrt;import android.app.Activity;import android.os.Bundle;public class MainActivity extends Activity {    /** Called when the activity is first created. */    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);    }}
  
    二. SoftReference:实现缓存机制

     下面的Demo实现从网络上获取图片,然后将获取的图片显示的同时,通过软引用缓存起来。当下次再去网络上获取图片时,首先会检查要获取的图片缓存中是否存在,若存在,直接取出来,不需要再去网络上获取。

     1.main.xml文件代码如下:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="vertical" >   <Button        android:id="@+id/get_image"       android:layout_width="fill_parent"       android:layout_height="wrap_content"       android:text="get Image"/>      <LinearLayout        android:layout_width="match_parent"       android:layout_height="match_parent"       android:orientation="vertical">    <ImageView        android:id="@+id/one"       android:layout_width="wrap_content"       android:layout_height="wrap_content"/>       <ImageView        android:id="@+id/two"       android:layout_width="wrap_content"       android:layout_height="wrap_content"/>         <ImageView        android:id="@+id/three"       android:layout_width="wrap_content"       android:layout_height="wrap_content"/>   </LinearLayout>  </LinearLayout>
    2.实现异步加载图片功能的类AsyncImageLoader代码如下:

package com.stevenhu.lit;import java.lang.ref.SoftReference;import java.net.URL;import java.util.HashMap;import java.util.Map;import android.graphics.drawable.Drawable;import android.os.Handler;import android.os.Message;//实现图片异步加载的类public class AsyncImageLoader {//以Url为键,SoftReference为值,建立缓存HashMap键值对。private Map<String, SoftReference<Drawable>> mImageCache = new HashMap<String, SoftReference<Drawable>>();//实现图片异步加载public Drawable loadDrawable(final String imageUrl, final ImageCallback callback){//查询缓存,查看当前需要下载的图片是否在缓存中if(mImageCache.containsKey(imageUrl)){SoftReference<Drawable> softReference = mImageCache.get(imageUrl);if (softReference.get() != null){return softReference.get();}}final Handler handler = new Handler(){@Overridepublic void dispatchMessage(Message msg) {//回调ImageCallbackImpl中的imageLoad方法,在主线(UI线程)中执行。callback.imageLoad((Drawable)msg.obj);}};/*若缓存中没有,新开辟一个线程,用于进行从网络上下载图片, * 然后将获取到的Drawable发送到Handler中处理,通过回调实现在UI线程中显示获取的图片 */new Thread(){public void run() {Drawable drawable = loadImageFromUrl(imageUrl);//将得到的图片存放到缓存中mImageCache.put(imageUrl, new SoftReference<Drawable>(drawable));Message message = handler.obtainMessage(0, drawable);handler.sendMessage(message);};}.start();//若缓存中不存在,将从网上下载显示完成后,此处返回null;return null;}//定义一个回调接口public interface ImageCallback{void imageLoad(Drawable drawable);}//通过Url从网上获取图片Drawable对象;protected Drawable loadImageFromUrl(String imageUrl){try {return Drawable.createFromStream(new URL(imageUrl).openStream(),"debug");} catch (Exception e) {// TODO: handle exceptionthrow new RuntimeException(e);}}}
     3. 实现ImageCallback回调接口的类ImageCallbackImpl代码如下:

package com.stevenhu.lit;import android.graphics.drawable.Drawable;import android.widget.ImageView;import com.stevenhu.lit.AsyncImageLoader.ImageCallback;public class ImageCallbackImpl implements ImageCallback{private ImageView mImageView;public ImageCallbackImpl(ImageView imageView){mImageView = imageView;}//在ImageView中显示从网上获取的图片@Overridepublic void imageLoad(Drawable drawable) {// TODO Auto-generated method stubmImageView.setImageDrawable(drawable);}}
     4.MainActivity的代码如下:

package com.stevenhu.lit;import android.app.Activity;import android.graphics.drawable.Drawable;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.ImageView;public class MainActivity extends Activity implements OnClickListener{//创建异步加载图片类对象private AsyncImageLoader mImageLoader = new AsyncImageLoader();    /** Called when the activity is first created. */    @Override    public void onCreate(Bundle savedInstanceState)     {            super.onCreate(savedInstanceState);        setContentView(R.layout.main);        Button get = (Button)findViewById(R.id.get_image);        get.setOnClickListener(this);    }        private void loadImage(final String url, final int id)    {    ImageView imageView = (ImageView)findViewById(id);    ImageCallbackImpl callbackImpl = new ImageCallbackImpl(imageView);    Drawable cacheImage = mImageLoader.loadDrawable(url, callbackImpl);    //若缓存中存在,直接取出来显示    if (cacheImage != null)    {    imageView.setImageDrawable(cacheImage);    }    }@Overridepublic void onClick(View v) {// TODO Auto-generated method stubif (v.getId() == R.id.get_image){//从网络上获取海贼王的三张图片显示loadImage("http://wenwen.soso.com/p/20111003/20111003194816-1615366606.jpg", R.id.one);        loadImage("http://t10.baidu.com/it/u=2492256852,4267838923&fm=23&gp=0.jpg", R.id.two);        loadImage("http://wenwen.soso.com/p/20100410/20100410102416-1948049438.jpg", R.id.three);}}}      

 最后,对于这两者,作个小总结:

   1.  SoftReference<T>:软引用-->当虚拟机内存不足时,将会回收它指向的对象;需要获取对象时,可以调用get方法。

    2.  WeakReference<T>:弱引用-->随时可能会被垃圾回收器回收,不一定要等到虚拟机内存不足时才强制回收。要获取对象时,同样可以调用get方法。

    3. WeakReference一般用来防止内存泄漏,要保证内存被虚拟机回收,SoftReference多用作来实现缓存机制(cache);

                       两个Demo的下载链接如下:http://download.csdn.net/detail/stevenhu_223/6855591

5 0
原创粉丝点击