Android中的软引用(SoftRefrerence)和弱引用(WeakReference)
2014-11-03 14:49
337 查看
/article/7858212.html
在Android开发中,基本上很少有用到软引用或弱引用,这两个东东若用的很好,对自己开发的代码质量的提高有很大的帮助。若用的不好,会坑了自己。所以,在还没有真正的去了解它们之前,还是慎用比较好。
下面将通过两个Demo来结识软引用和弱引用在开发中的运用。
一. WeakReference:防止内存泄漏,要保证内存被虚拟机回收。
下面以一个时间更新的Demo来说明弱引用的运用。
1. main.xml文件代码如下:
2.自定义ViewGroup类DigitalClock的代码如下:
3.MainActivity的代码如下:
二. SoftReference:实现缓存机制
下面的Demo实现从网络上获取图片,然后将获取的图片显示的同时,通过软引用缓存起来。当下次再去网络上获取图片时,首先会检查要获取的图片缓存中是否存在,若存在,直接取出来,不需要再去网络上获取。
1.main.xml文件代码如下:
2.实现异步加载图片功能的类AsyncImageLoader代码如下:
3. 实现ImageCallback回调接口的类ImageCallbackImpl代码如下:
4.MainActivity的代码如下:
最后,对于这两者,作个小总结:
1. SoftReference<T>:软引用-->当虚拟机内存不足时,将会回收它指向的对象;需要获取对象时,可以调用get方法。
2. WeakReference<T>:弱引用-->随时可能会被垃圾回收器回收,不一定要等到虚拟机内存不足时才强制回收。要获取对象时,同样可以调用get方法。
3. WeakReference一般用来防止内存泄漏,要保证内存被虚拟机回收,SoftReference多用作来实现缓存机制(cache);
两个Demo的下载链接如下:http://download.csdn.net/detail/stevenhu_223/6855591
在Android开发中,基本上很少有用到软引用或弱引用,这两个东东若用的很好,对自己开发的代码质量的提高有很大的帮助。若用的不好,会坑了自己。所以,在还没有真正的去了解它们之前,还是慎用比较好。
下面将通过两个Demo来结识软引用和弱引用在开发中的运用。
一. WeakReference:防止内存泄漏,要保证内存被虚拟机回收。
下面以一个时间更新的Demo来说明弱引用的运用。
1. main.xml文件代码如下:
<span style="font-size:12px;"><?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></span>
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 } @Override protected void onFinishInflate() { // TODO Auto-generated method stub super.onFinishInflate(); mDislpayTime = (TextView) this.findViewById(R.id.time); mAmPm = new AmPm(this); mCalendar = Calendar.getInstance(); //设置时间显示格式 setDateFormat(); } @Override protected void onAttachedToWindow() { // TODO Auto-generated method stub super.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); } //注册监听时间格式改变的ContentObserver if (mFormatChangeObserver == null) { mFormatChangeObserver = new FormatChangeObserver(this); mContext.getContentResolver().registerContentObserver( Settings.System.CONTENT_URI, true, mFormatChangeObserver); } //更新时间 updateTime(); } @Override protected void onDetachedFromWindow() { // TODO Auto-generated method stub super.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(); } @Override public 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(); } @Override public 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)); } @Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub super.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() { @Override public 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 exception throw 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中显示从网上获取的图片 @Override public void imageLoad(Drawable drawable) { // TODO Auto-generated method stub mImageView.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); } } @Override public void onClick(View v) { // TODO Auto-generated method stub if (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
相关文章推荐
- Android中的软引用(SoftRefrerence)和弱引用(WeakReference)
- Android中的软引用(SoftRefrerence)和弱引用(WeakReference)
- Android中的软引用(SoftRefrerence)和弱引用(WeakReference)
- Android中的软引用(SoftRefrerence)和弱引用(WeakReference)
- Android中的软引用(SoftRefrerence)和弱引用(WeakReference)介绍
- Android中的软引用(SoftRefrerence)和弱引用(WeakReference)
- Android中的软引用(SoftRefrerence)和弱引用(WeakReference)
- Android-软引用(SoftRefrerence)和弱引用(WeakReference)
- java弱引用(WeakReference)和SoftReference的区别以及在android内存处理的作用
- java弱引用(WeakReference)和SoftReference的区别以及在android内存处理的作用
- (源码)详细分析Android中的引用机制Reference(WeakReference、SoftReference、PhantomReference)
- Android优化中弱引用WeakReference的知识
- java弱引用(WeakReference)和SoftReference的区别以及在android内存处理的作用
- android adapter 操作Activity中的方法 ------------弱引用WeakReference----断点记录
- android adapter 操作Activity中的方法 ------------弱引用WeakReference----断点记录
- java弱引用(WeakReference)和SoftReference的区别以及在android内存处理的作用
- Android 内存溢出解决方案(OOM) 整理总结 (软引用(SoftReference)、虚引用(PhantomRefrence)、弱引用(WeakReference),)
- WeakReference 在android中的应用 弱引用防止内存泄漏
- java弱引用(WeakReference)和SoftReference的区别以及在android内存处理的作用
- android开发笔记之WeakReference和SoftRefrerence