HardBirch

Build Cache By SoftReference(软引用构建缓存详解)

时间:13-11-07 栏目:安卓技术篇 作者:魔豆先生 评论:0 点击: 3,668 次

一、为什么要使用软引用
        在上面关于软引用的介绍中,已经提到了软引用的特性。使用SoftReference引用的对象会有很长的生命周期,只有当系统的内存不足的时候,才会去释放这些软引用对象。所以可以使用软引用来缓存一些比较昂贵的资源,比如获取的网络图片数据。
        当应用从网络中获取网络图片数据时,用户完全有可能做一些重复性的操作去查看相同的图片信息。对于这样的问题,通常会有两种解决方法: 一种是把过去查看过的图片信息保存在内存中,每一个存储了图片信息的 Java 对象的生命周期都贯穿整个应用程序生命周期,另一种是当用户开始查看其他图片信息的时候,把存储了当前的图片信息的 Java 对象结束引用,使得垃圾收集线程可以回收其所占用的内存空间,当用户再次需要浏览该图片信息的时候,重新获取图片信息。
        很显然,第一种实现方法将造成大量的内存浪费,而第二种实现的缺陷在于即使垃圾收集线程还没有进行垃圾收集,包含图片信息的对象仍然完好地保存在内存中,应用程序也要重新构建一个对象。
        像访问磁盘文件、访问网络资源、查询数据库等操作都是影响应用程序执行性能的重要因素,如果能重新获取那些尚未被回收的 Java 对象的引用,必将减少不必要的访问,大大提高程序的运行速度。
        这样看来,使用软引用是非常有必要的一件事情。
二、如何使用软引用
        SoftReference 的特点是它的一个实例保存着一个 Java 对象的软引用,该软引用的存在不妨碍垃圾收集器线程对该 Java 对象的回收。也就是说,一旦SoftReference 保存着一个 Java 对象的软引用之后,在垃圾收集器线程对这个 Java 对象回收之前, SoftReference 类所提供的 get() 方法都会返回 这个Java 对象的强引用。另外,一旦垃圾线程回收该 Java 对象之后, get() 方法将返回 null 。
        软引用的使用方法如下面的Java代码所示 :

[代码]java代码:

1 MyObject aRef  =  new   MyObject();//创建一个对象
2 SoftReference aSoftRef = new SoftReference( aRef );//创建对象的软引用
        上面的代码执行后,对于MyObject 对象,有两个引用路径,一个是来自 aSoftRef对象的软引用,一个来自变量 aRef 的强引用,所以 MyObject对象是强可及对象。紧跟着,可以使用下面的java的代码结束 aReference 对 MyObject 实例的强引用 :

[代码]java代码:

1 aRef = null ;//断开对象的强引用
        此后, MyObject 对象成为了软可及对象。如果垃圾收集线程进行内存垃圾收集,并不会因为有一个 SoftReference 对该对象的引用而始终保留该对象。 Java 虚拟机的垃圾收集线程对软可及对象和其他一般 Java 对象进行了区别对待 ,软可及对象的清理是由垃圾收集线程根据其特定算法按照内存需求决定的。也就是说,垃圾收集线程会在虚拟机抛出 OutOfMemoryError 之前回收软可及对象,而且虚拟机会尽可能优先回收长时间闲置不用的软可及对象,对那些刚刚构建的或刚刚使用过的“新”软可及对象会被虚拟机尽可能保留。如 果想获取软引用中包含的对象,可以使用下面的Java代码:

[代码]java代码:

1 MyObject anotherRef =(MyObject) aSoftRef .get();//通过软引用获取对象
        在回收这些对象之前,可以通过上面的代码重新获得对该实例的强引用。而回收之后,当调用软引用的get() 方法时,返回的是 null 。
三、如何使用 ReferenceQueue
        作为一个 Java 对象, SoftReference 对象除了具有保存软引用的特殊性之外,也具有 Java 对象的一般性。所以,当软可及对象被回收之后,虽然这个 SoftReference 对象的 get() 方法返回 null, 但这个 SoftReference 对象已经不再具有存在的价值,需要一个适当的清除机制,避免大量 SoftReference 对象带来的内存泄漏。在 java.lang.ref 包里还提供了 ReferenceQueue 。如果在创建 SoftReference 对象的时候,使用了带有一个 ReferenceQueue 对象作为参数的构造方法,如下面的Java代码 :

[代码]java代码:

1 ReferenceQueue queue = new ReferenceQueue();//创建引用队列
2 SoftReference  ref = new SoftReference( aMyObject, queue );// 把引用加入到引用队列
        当这个 SoftReference 所软引用的 aMyOhject 被垃圾收集器回收的同时,ref 所强引用的 SoftReference 对象被列入 ReferenceQueue 。也就是说, ReferenceQueue 中保存的对象是 Reference 对象,而且是已经失去了它所软引用的对象的 Reference 对象。另外从 ReferenceQueue 这个名字也可以看出,它是一个队列,当调用它的 poll() 方法的时候,如果这个队列中不是空队列,那么将返回队列前面的那个 Reference 对象。
        在任何时候,都可以调用 ReferenceQueue 的 poll() 方法来检查是否有它所关心的非强可及对象被回收。如果队列为空,将返回一个 null, 否则该方法返回队列中最前面一个 Reference 对象。利用这个方法,可以检查哪个 SoftReference 所软引用的对象已经被回收。可以把这些失去所软引用的对象的 SoftReference 对象清除掉,如下面的Java代码所示。:

[代码]java代码:

1 SoftReference ref = null ;
2 while ((ref = (EmployeeRef) q .poll()) != null ) {
3     // 清除 ref
4 }
四、实例分析
        理解了 Java中的引用机制之后就可以在Android中构造缓存器(cache)了,在Android中应用比较多的控件是ListView,通常会使用 ListView显示网络数据列表,同时会包含图片缩略图,当数据量很大的时候,为了让用户能更流畅地流量信息,可以使用异步加载和缓存机制处理网络图 片。
通过以上对于Java软引用类型的了解,可以知道使用软引用来构建缓存是比较合适的。虽然软引用能够延长数据对象的生命周期, 但是对于移动设备来说,内存资源相对来说比较紧缺,仅使用软引用未必能达到最佳的缓存效果。通常会使用一些组合方式来进行数据缓存,最常用的是强引用、软 引用加本地缓存的方式。
        Android提供了一个AsyncTask类,它封装了基本的异步操作模型,只需要实现几个最基本的方法就可以很容易的实现异步加载图片,主要的方法是 doInBackground方法和onPostExecute方法。AsyncTask类会启动一个新的线程执行doInBackground方法,所 以我们所有的网络操作都应该在这个方法中实现,当doInBackground方法执行完成后,AsyncTask类会使用内置的Handler发送消息 在主线程中执行onPostExecute方法,所以关于对UI的操作都应该放在onPostExecute方法中实现。
        对于缓存的处理,主要思路是:在开始时,创建两个缓存区域:强引用缓存区域和软引用缓存区域。在强引用缓存区中保存有限的图片对象,根据LRU策略把一些 最不常用的图片对象移到软引用缓存区,当缓存区域中都没有图片对象时从网络加载图片。完成后把图片数据保存到SDCard中,并根据LRU策略进行管理 SDCard中保存的图片文件。
        下图为ListView异步加载远程图片的流程图:
 
图14-2  ListView异步加载远程图片的流程图
        下面通过一个ListView的使用实例来说明如何在Android应用程序中使用异步加载图片,并且在内存和本地缓存它们。
        第一步,首先建立一个Android工程,名称为AsyncListImage,由于应用需要访问网络所以需要修改AndroidManifest.xml文件,添加网络连接的权限,代码如下:

[代码]xml代码:

1 <uses-permission android:name="android.permission.INTERNET"/>
        第二步,修改main.xml文件添加listview控件,并设置listview的一些基本属性信息,如下面的xml代码:

[代码]xml代码:

01 <?xml version="1.0" encoding="utf-8"?>
02 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
03     android:orientation="vertical"
04  android:layout_width="fill_parent"
05     android:layout_height="fill_parent">
06     <ListView android:id="@+id/list"
07      android:layout_width="fill_parent"
08         android:layout_height="fill_parent"
09         android:background="#ffffffff"
10         android:cacheColorHint="#00000000"/>
11 </LinearLayout>
        第三步,修改AsyncListImage Activity类并覆盖oncreate方法,初始化listview,并创建listview控件使用的Adapter。在 AsyncListImage中定义了两种缓存区域A和B,A代表强引用缓存区域,B代表软引用缓存区域,由于使用强引用缓存区域保存数据只能保存一定的 数量,而不能一直往里面存放,需要设置数据的过期时间、LRU等算法。这里有一个方法是把常用的数据放到缓存A中,不常用的放到另外一个缓存B中。当要获 取数据时先从A中去获取,如果A中不存在那么再去B中获取。B中的数据主要是A中经过LRU生成的数据,这里的内存回收主要针对B内存,从而保持A中的数 据可以有效的被命中。
        下面是完整的Java代码:

[代码]java代码:

001 package com.devdiv.android.asynimagelist;
002
003 import java.io.File;
004 import java.lang.ref.SoftReference;
005 import java.util.HashMap;
006 import java.util.LinkedHashMap;
007 import java.util.concurrent.ConcurrentHashMap;
008
009 import android.app.Activity;
010 import android.graphics.Bitmap;
011 import android.os.Bundle;
012 import android.util.Log;
013 import android.view.View;
014 import android.view.ViewGroup;
015 import android.widget.BaseAdapter;
016 import android.widget.ImageView;
017 import android.widget.ListView;
018 import android.widget.ImageView.ScaleType;
019
020 @SuppressWarnings("serial")
021 public class AsyncListImage extends Activity implements RemoteImageCallback {
022     private ListView list;
023     private static final String TAG = AsyncListImage.class.getSimpleName();
024     private static final int HARD_CACHE_CAPACITY = 10;
025
026     private final HashMap<String, Bitmap> mHardBitmapCache = new LinkedHashMap<String, Bitmap>(HARD_CACHE_CAPACITY / 2, 0.75f, true) {
027
028         @Override
029         protected boolean removeEldestEntry(LinkedHashMap.Entry<String, Bitmap> eldest) {
030             if (size() > HARD_CACHE_CAPACITY) {
031                //当map的size大于10时,把最近不常用的key放到mSoftBitmapCache中,从而保证mHardBitmapCache的效率
032                mSoftBitmapCache.put(eldest.getKey(), new SoftReference<Bitmap>(eldest.getValue()));
033                 return true;
034             } else
035                 return false;
036         }
037     };
038     
039     /**
040      *当mHardBitmapCache的key大于10的时候,会根据LRU算法把最近没有被使用的key放入到这个缓存中。
041      * Bitmap使用了SoftReference,当内存空间不足时,此cache中的bitmap会被垃圾回收掉
042      */
043     private final static ConcurrentHashMap<String, SoftReference<Bitmap>> mSoftBitmapCache = new ConcurrentHashMap<String, SoftReference<Bitmap>>(
044             HARD_CACHE_CAPACITY / 2);
045
046     @Override
047     public void onCreate(Bundle savedInstanceState) {
048         super.onCreate(savedInstanceState);
049         setContentView(R.layout.main);
050         list = (ListView) findViewById(R.id.list);
051         
052         initCacheDir();
053         
054         MyListAdapter adapter = new MyListAdapter();
055         list.setAdapter(adapter);
056     }
057     
058     private void initCacheDir() {
059         String cacheDir = "/data/data/com.devdiv.android.asynimagelist/files/caches";
060         File f = new File(cacheDir);
061         if (!f.exists()) {
062             f.mkdirs();
063         }
064     }
065     
066     private class MyListAdapter extends BaseAdapter {
067         private String[] urls = new String[] {
068 "http://www.icosky.com/icon/thumbnails/System/Sleek%20XP%20Basic/Add%20Icon.jpg",
069 "http://www.icosky.com/icon/thumbnails/System/Sleek%20XP%20Basic/Adobe%20Illustator%20Icon.jpg",
070 "http://www.icosky.com/icon/thumbnails/System/Sleek%20XP%20Basic/Attach%20Icon.jpg",
071 "http://www.icosky.com/icon/thumbnails/System/Sleek%20XP%20Basic/Applications%20Cascade%20Icon.jpg",
072 "http://www.icosky.com/icon/thumbnails/System/Sleek%20XP%20Basic/Administrator%20Icon.jpg",
073 "http://www.icosky.com/icon/thumbnails/System/Sleek%20XP%20Basic/Clients%20Icon.jpg",
074 "http://www.icosky.com/icon/thumbnails/System/Sleek%20XP%20Basic/Coinstack%20Icon.jpg",
075 "http://www.icosky.com/icon/thumbnails/System/Sleek%20XP%20Basic/Download%20Icon.jpg",
076 "http://www.icosky.com/icon/thumbnails/System/Sleek%20XP%20Basic/Help%20Icon.jpg",
077 "http://www.icosky.com/icon/thumbnails/System/Sleek%20XP%20Basic/Home%20Icon.jpg",
078 "http://www.icosky.com/icon/thumbnails/System/Sleek%20XP%20Basic/Pen%20Icon.jpg",
079 "http://www.icosky.com/icon/thumbnails/System/Sleek%20XP%20Basic/Statistics%20Icon.jpg"
080         };
081         
082         @Override
083         public int getCount() {
084             return urls.length;
085         }
086
087         @Override
088         public String getItem(int position) {
089             return urls[position];
090         }
091
092         @Override
093         public long getItemId(int position) {
094             return position;
095         }
096
097         @Override
098         public View getView(int position, View convertView, ViewGroup parent) {
099             if (convertView == null) {
100                 convertView = new ImageView(AsyncListImage.this);
101             }
102             ImageView iv = (ImageView)convertView;
103             iv.setScaleType(ScaleType.FIT_START);
104             Bitmap bitmap = getBitmapFromCache(getItem(position));
105             if (bitmap == null) {
106                 iv.setImageResource(R.drawable.default_image);
107                 iv.setTag(getItem(position));
108                 new ImageDownloaderTask(AsyncListImage.this).execute(new String[]{getItem(position)});
109             } else {
110                 iv.setImageBitmap(bitmap);
111             }
112             iv = null;
113             return convertView;
114         }
115         
116     }
117     
118     /**
119      * 从缓存中获取图片
120      */
121     private Bitmap getBitmapFromCache(String url) {
122         // 先从mHardBitmapCache缓存中获取
123         synchronized (mHardBitmapCache) {
124             final Bitmap bitmap = mHardBitmapCache.get(url);
125             if (bitmap != null) {
126                 //如果找到的话,把元素移到linkedhashmap的最前面,从而保证在LRU算法中是最后被删除
127                 mHardBitmapCache.remove(url);
128                 Log.d(TAG, "move bitmap to the head of linkedhashmap:" + url);
129                 mHardBitmapCache.put(url,bitmap);
130                 return bitmap;
131             }
132         }
133         //如果mHardBitmapCache中找不到,到mSoftBitmapCache中找
134         SoftReference<Bitmap> bitmapReference = mSoftBitmapCache.get(url);
135         if (bitmapReference != null) {
136             final Bitmap bitmap = bitmapReference.get();
137             if (bitmap != null) {
138                 Log.d(TAG, "get bitmap from mSoftBitmapCache with key:" + url);
139                 return bitmap;
140             } else {
141                 mSoftBitmapCache.remove(url);
142                 Log.d(TAG, "remove bitmap with key:" + url);
143             }
144         }
145         return null;
146     }
147
148     @Override
149     public void onComplete(String url, Bitmap bitmap) {
150         Log.d(TAG, "onComplete after got bitmap from remote with key:" + url);
151         ImageView iv = (ImageView)list.findViewWithTag(url);
152         if (iv != null) {
153             iv.setImageBitmap(bitmap);
154             mHardBitmapCache.put(url, bitmap);
155         }
156     }
157     
158 }
        第四步,定义AsyncTask 类的子类ImageDownloaderTask类并覆盖doInBackground 方法和onPostExecute方法。在doInBackground方法中进行网络操作和文件操作,在onPostExecute方法中执行回调函 数,把获取的bitmap数据发送到UI线程与ListView中的imageView进行关联,Java代码如下。

[代码]java代码:

001 package com.devdiv.android.asynimagelist;
002
003 import java.io.BufferedOutputStream;
004 import java.io.ByteArrayOutputStream;
005 import java.io.Closeable;
006 import java.io.File;
007 import java.io.FileNotFoundException;
008 import java.io.FileOutputStream;
009 import java.io.IOException;
010 import java.io.InputStream;
011 import java.io.OutputStream;
012 import java.lang.ref.WeakReference;
013 import java.util.Arrays;
014 import java.util.Comparator;
015
016 import org.apache.http.HttpEntity;
017 import org.apache.http.HttpResponse;
018 import org.apache.http.HttpStatus;
019 import org.apache.http.client.methods.HttpGet;
020 import org.apache.http.impl.client.DefaultHttpClient;
021
022 import android.graphics.Bitmap;
023 import android.graphics.BitmapFactory;
024 import android.os.AsyncTask;
025 import android.os.Environment;
026 import android.os.StatFs;
027 import android.util.Log;
028
029 public class ImageDownloaderTask extends AsyncTask<String, Void, Bitmap> {
030     private static String TAG = ImageDownloaderTask.class.getSimpleName();
031     private static final int IO_BUFFER_SIZE = 4 * 1024;
032     private static final int MB = 1024 * 1024;
033     private static final int CACHE_SIZE = 1024 * 1024;
034     private static final int mTimeDiff = 5 * 24 * 60 * 60 * 1000;
035     private static final int FREE_SD_SPACE_NEEDED_TO_CACHE = 30;
036     private static final String WHOLESALE_CONV = "/data/data/com.devdiv.android.asynimagelist/files/caches";
037     private String url;
038     private final WeakReference<AsyncListImage> activityReference;
039
040     public ImageDownloaderTask(AsyncListImage activity) {
041         activityReference = new WeakReference<AsyncListImage>(activity);
042     }
043
044     @Override
045     protected Bitmap doInBackground(String... params) {
046         url = params[0];
047         String filename = convertUrlToFileName(url);
048         String dir = getDirectory(filename);
049         File file = new File(dir + "/" + filename);
050         if (file.exists()) {
051             removeExpiredCache(dir, filename);
052             updateFileTime(dir, filename);
053             Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
054             if (bitmap != null)
055                 return bitmap;
056         }
057         
058         final DefaultHttpClient client = new DefaultHttpClient();
059         
060         final HttpGet getRequest = new HttpGet(url);
061         try {
062             HttpResponse response = client.execute(getRequest);
063             final int statusCode = response.getStatusLine().getStatusCode();
064             if (statusCode != HttpStatus.SC_OK) {
065                 Log.w(TAG, "从" + url + "中下载图片时出错!,错误码:" + statusCode);
066                 return null;
067             }
068             final HttpEntity entity = response.getEntity();
069             if (entity != null) {
070                 InputStream inputStream = null;
071                 OutputStream outputStream = null;
072                 try {
073                     inputStream = entity.getContent();
074                     final ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
075                     outputStream = new BufferedOutputStream(dataStream,
076                             IO_BUFFER_SIZE);
077                     copy(inputStream, outputStream);
078                     outputStream.flush();
079                     final byte[] data = dataStream.toByteArray();
080                     final Bitmap bitmap = BitmapFactory.decodeByteArray(data,
081                             0, data.length);
082                     
083                     saveBmpToSd(bitmap, url);
084                     
085                     return bitmap;
086                 } finally {
087                     closeStream(inputStream);
088                     closeStream(outputStream);
089                     entity.consumeContent();
090                 }
091             }
092         } catch (IOException e) {
093             getRequest.abort();
094             Log.w(TAG, "I/O error while retrieving bitmap from " + url, e);
095         } catch (IllegalStateException e) {
096             getRequest.abort();
097             Log.w(TAG, "Incorrect URL:" + url);
098         } catch (Exception e) {
099             getRequest.abort();
100             Log.w(TAG, "Error while retrieving bitmap from " + url, e);
101         }
102         return null;
103     }
104     
105     @Override
106     protected void onPostExecute(Bitmap result) {
107         super.onPostExecute(result);
108         AsyncListImage act = activityReference.get();
109         if (act != null && result != null) {
110             act.onComplete(url, result);
111         }
112     }
113     
114     
115     /**
116      * Copy the content of the input stream into the output stream, using a temporary
117      * byte array buffer whose size is defined by {@link #IO_BUFFER_SIZE}.
118      *
119      * @param in The input stream to copy from.
120      * @param out The output stream to copy to.
121      *
122      * @throws java.io.IOException If any error occurs during the copy.
123      */
124     public static void copy(InputStream in, OutputStream out) throws IOException {
125         byte[] b = new byte[IO_BUFFER_SIZE];
126         int read;
127         while ((read = in.read(b)) != -1) {
128             out.write(b, 0, read);
129         }
130     }
131
132     /**
133      * Closes the specified stream.
134      *
135      * @param stream The stream to close.
136      */
137     public static void closeStream(Closeable stream) {
138         if (stream != null) {
139             try {
140                 stream.close();
141             } catch (IOException e) {
142                 android.util.Log.e(TAG, "Could not close stream", e);
143             }
144         }
145     }
146     
147     private void saveBmpToSd(Bitmap bm, String url) {
148         if (bm == null) {
149             Log.w(TAG, " trying to savenull bitmap");
150             return;
151         }
152         // 判断sdcard上的空间
153         if (FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {
154             Log.w(TAG, "Low free space onsd, do not cache");
155             removeCache(WHOLESALE_CONV);
156             return;
157         }
158         String filename = convertUrlToFileName(url);
159         String dir = getDirectory(filename);
160         File file = new File(dir + "/" + filename);
161         try {
162             file.createNewFile();
163             OutputStream outStream = new FileOutputStream(file);
164             bm.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
165             outStream.flush();
166             outStream.close();
167             Log.i(TAG, "Image saved tosd");
168         } catch (FileNotFoundException e) {
169             Log.w(TAG, "FileNotFoundException");
170         } catch (IOException e) {
171             Log.w(TAG, "IOException");
172         }
173     }
174
175     private String convertUrlToFileName(String url) {
176         int lastIndex = url.lastIndexOf('/');
177         return url.substring(lastIndex + 1);
178     }
179
180     private String getDirectory(String filename) {
181         return WHOLESALE_CONV;
182     }
183
184     /**
185      * 计算sdcard上的剩余空间
186      *
187      * @return
188      */
189     private int freeSpaceOnSd() {
190         StatFs stat = new StatFs(Environment.getExternalStorageDirectory()
191                 .getPath());
192         double sdFreeMB = ((double) stat.getAvailableBlocks() * (double) stat
193                 .getBlockSize())
194                 / MB;
195         return (int) sdFreeMB;
196     }
197
198     /**
199      * 修改文件的最后修改时间
200      *
201      * @param dir
202      * @param fileName
203      */
204     private void updateFileTime(String dir, String fileName) {
205         File file = new File(dir, fileName);
206         long newModifiedTime = System.currentTimeMillis();
207         file.setLastModified(newModifiedTime);
208     }
209
210     /**
211      *计算存储目录下的文件大小,
212      * 当文件总大小大于规定的CACHE_SIZE或者sdcard剩余空间小于FREE_SD_SPACE_NEEDED_TO_CACHE的规定
213      * 那么删除40%最近没有被使用的文件
214      *
215      * @param dirPath
216      * @param filename
217      */
218     private void removeCache(String dirPath) {
219         File dir = new File(dirPath);
220         File[] files = dir.listFiles();
221         if (files == null) {
222             return;
223         }
224         int dirSize = 0;
225         for (int i = 0; i < files.length; i++) {
226             if (files[i].getName().contains(WHOLESALE_CONV)) {
227                 dirSize += files[i].length();
228             }
229         }
230         if (dirSize > CACHE_SIZE * MB
231                 || FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {
232             int removeFactor = (int) ((0.4 * files.length) + 1);
233
234             Arrays.sort(files, new FileLastModifSort());
235
236             Log.i(TAG, "Clear some expiredcache files ");
237
238             for (int i = 0; i < removeFactor; i++) {
239
240                 if (files[i].getName().contains(WHOLESALE_CONV)) {
241
242                     files[i].delete();
243
244                 }
245
246             }
247
248         }
249
250     }
251
252     /**
253      * TODO 根据文件的最后修改时间进行排序 *
254      */
255     class FileLastModifSort implements Comparator<File> {
256         public int compare(File arg0, File arg1) {
257             if (arg0.lastModified() > arg1.lastModified()) {
258                 return 1;
259             } else if (arg0.lastModified() == arg1.lastModified()) {
260                 return 0;
261             } else {
262                 return -1;
263             }
264         }
265     }
266
267     /**
268      * 删除过期文件
269      *
270      * @param dirPath
271      * @param filename
272      */
273     private void removeExpiredCache(String dirPath, String filename) {
274
275         File file = new File(dirPath, filename);
276
277         if (System.currentTimeMillis() - file.lastModified() > mTimeDiff) {
278
279             Log.i(TAG, "Clear some expiredcache files ");
280
281             file.delete();
282
283         }
284
285     }
286 }
        第五步、运行工程之后,运行效果如下图示。
        运行工程,最开始时,ListView使用默认的图片填充imageview。

声明: 本文由( 魔豆先生 )原创编译,转载请保留链接: Build Cache By SoftReference(软引用构建缓存详解)

Build Cache By SoftReference(软引用构建缓存详解):等您坐沙发呢!

发表评论


QQ群互动

Linux系统与内核学习群:194051772

WP建站技术学习交流群:194062106

魔豆之路QR

魔豆的Linux内核之路

魔豆的Linux内核之路

优秀工程师当看优秀书籍

优秀程序员,要看优秀书!

赞助商广告

友荐云推荐