您的位置:首页 > 其它

使用软引用构建缓存(转载)

2012-12-21 16:29 417 查看
一、为什么要使用软引用

在上面关于软引用的介绍中,已经提到了软引用的特性。使用SoftReference引用的对象会有很长的生命周期,只有当系统的内存不足的时候,才会去释放这些软引用对象。所以可以使用软引用来缓存一些比较昂贵的资源,比如获取的网络图片数据。

当应用从网络中获取网络图片数据时,用户完全有可能做一些重复性的操作去查看相同的图片信息。对于这样的问题,通常会有两种解决方法:一种是把过去查看过的图片信息保存在内存中,每一个存储了图片信息的Java对象的生命周期都贯穿整个应用程序生命周期,另一种是当用户开始查看其他图片信息的时候,把存储了当前的图片信息的Java对象结束引用,使得垃圾收集线程可以回收其所占用的内存空间,当用户再次需要浏览该图片信息的时候,重新获取图片信息。

很显然,第一种实现方法将造成大量的内存浪费,而第二种实现的缺陷在于即使垃圾收集线程还没有进行垃圾收集,包含图片信息的对象仍然完好地保存在内存中,应用程序也要重新构建一个对象。

像访问磁盘文件、访问网络资源、查询数据库等操作都是影响应用程序执行性能的重要因素,如果能重新获取那些尚未被回收的Java对象的引用,必将减少不必要的访问,大大提高程序的运行速度。

这样看来,使用软引用是非常有必要的一件事情。

二、如何使用软引用

SoftReference的特点是它的一个实例保存着一个Java对象的软引用,该软引用的存在不妨碍垃圾收集器线程对该Java对象的回收。也就是说,一旦SoftReference保存着一个Java对象的软引用之后,在垃圾收集器线程对这个Java对象回收之前,SoftReference类所提供的get()方法都会返回这个Java对象的强引用。另外,一旦垃圾线程回收该Java对象之后,get()方法将返回null。

软引用的使用方法如下面的Java代码所示:

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

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

1
MyObjectanotherRef=(MyObject)aSoftRef.get();
//通过软引用获取对象
在回收这些对象之前,可以通过上面的代码重新获得对该实例的强引用。而回收之后,当调用软引用的get()方法时,返回的是null。

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

1
ReferenceQueuequeue=
new
ReferenceQueue();
//创建引用队列
2
SoftReferenceref=
new
SoftReference(aMyObject,queue);
//把引用加入到引用队列
当这个SoftReference所软引用的aMyOhject被垃圾收集器回收的同时,ref所强引用的SoftReference对象被列入ReferenceQueue。也就是说,ReferenceQueue中保存的对象是Reference对象,而且是已经失去了它所软引用的对象的Reference对象。另外从ReferenceQueue这个名字也可以看出,它是一个队列,当调用它的poll()方法的时候,如果这个队列中不是空队列,那么将返回队列前面的那个Reference对象。

在任何时候,都可以调用ReferenceQueue的poll()方法来检查是否有它所关心的非强可及对象被回收。如果队列为空,将返回一个null,否则该方法返回队列中最前面一个Reference对象。利用这个方法,可以检查哪个SoftReference所软引用的对象已经被回收。可以把这些失去所软引用的对象的SoftReference对象清除掉,如下面的Java代码所示。:

1
SoftReferenceref=
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的使用实例来说明如何在Android应用程序中使用异步加载图片,并且在内存和本地缓存它们。

第一步,首先建立一个Android工程,名称为AsyncListImage,由于应用需要访问网络所以需要修改AndroidManifest.xml文件,添加网络连接的权限,代码如下:

1
<
uses-permission
android:name
=
"android.permission.INTERNET"
/>
第二步,修改main.xml文件添加listview控件,并设置listview的一些基本属性信息,如下面的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
>
第三步,修改AsyncListImageActivity类并覆盖oncreate方法,初始化listview,并创建listview控件使用的Adapter。在AsyncListImage中定义了两种缓存区域A和B,A代表强引用缓存区域,B代表软引用缓存区域,由于使用强引用缓存区域保存数据只能保存一定的数量,而不能一直往里面存放,需要设置数据的过期时间、LRU等算法。这里有一个方法是把常用的数据放到缓存A中,不常用的放到另外一个缓存B中。当要获取数据时先从A中去获取,如果A中不存在那么再去B中获取。B中的数据主要是A中经过LRU生成的数据,这里的内存回收主要针对B内存,从而保持A中的数据可以有效的被命中。

下面是完整的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
ListViewlist;
023
private
static
final
StringTAG=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(BundlesavedInstanceState){
048
super
.onCreate(savedInstanceState);
049
setContentView(R.layout.main);
050
list=(ListView)findViewById(R.id.list);
051
052
initCacheDir();
053
054
MyListAdapteradapter=
new
MyListAdapter();
055
list.setAdapter(adapter);
056
}
057
058
private
void
initCacheDir(){
059
StringcacheDir=
"/data/data/com.devdiv.android.asynimagelist/files/caches"
;
060
Filef=
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
StringgetItem(
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
ViewgetView(
int
position,ViewconvertView,ViewGroupparent){
099
if
(convertView==
null
){
100
convertView=
new
ImageView(AsyncListImage.
this
);
101
}
102
ImageViewiv=(ImageView)convertView;
103
iv.setScaleType(ScaleType.FIT_START);
104
Bitmapbitmap=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
BitmapgetBitmapFromCache(Stringurl){
122
//先从mHardBitmapCache缓存中获取
123
synchronized
(mHardBitmapCache){
124
final
Bitmapbitmap=mHardBitmapCache.get(url);
125
if
(bitmap!=
null
){
126
//如果找到的话,把元素移到linkedhashmap的最前面,从而保证在LRU算法中是最后被删除
127
mHardBitmapCache.remove(url);
128
Log.d(TAG,
"movebitmaptotheheadoflinkedhashmap:"
+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
Bitmapbitmap=bitmapReference.get();
137
if
(bitmap!=
null
){
138
Log.d(TAG,
"getbitmapfrommSoftBitmapCachewithkey:"
+url);
139
return
bitmap;
140
}
else
{
141
mSoftBitmapCache.remove(url);
142
Log.d(TAG,
"removebitmapwithkey:"
+url);
143
}
144
}
145
return
null
;
146
}
147
148
@Override
149
public
void
onComplete(Stringurl,Bitmapbitmap){
150
Log.d(TAG,
"onCompleteaftergotbitmapfromremotewithkey:"
+url);
151
ImageViewiv=(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代码如下。

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
StringTAG=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
StringWHOLESALE_CONV=
"/data/data/com.devdiv.android.asynimagelist/files/caches"
;
037
private
Stringurl;
038
private
final
WeakReference<AsyncListImage>activityReference;
039
040
public
ImageDownloaderTask(AsyncListImageactivity){
041
activityReference=
new
WeakReference<AsyncListImage>(activity);
042
}
043
044
@Override
045
protected
BitmapdoInBackground(String...params){
046
url=params[
0
];
047
Stringfilename=convertUrlToFileName(url);
048
Stringdir=getDirectory(filename);
049
Filefile=
new
File(dir+
"/"
+filename);
050
if
(file.exists()){
051
removeExpiredCache(dir,filename);
052
updateFileTime(dir,filename);
053
Bitmapbitmap=BitmapFactory.decodeFile(file.getAbsolutePath());
054
if
(bitmap!=
null
)
055
return
bitmap;
056
}
057
058
final
DefaultHttpClientclient=
new
DefaultHttpClient();
059
060
final
HttpGetgetRequest=
new
HttpGet(url);
061
try
{
062
HttpResponseresponse=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
HttpEntityentity=response.getEntity();
069
if
(entity!=
null
){
070
InputStreaminputStream=
null
;
071
OutputStreamoutputStream=
null
;
072
try
{
073
inputStream=entity.getContent();
074
final
ByteArrayOutputStreamdataStream=
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
Bitmapbitmap=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
(IOExceptione){
093
getRequest.abort();
094
Log.w(TAG,
"I/Oerrorwhileretrievingbitmapfrom"
+url,e);
095
}
catch
(IllegalStateExceptione){
096
getRequest.abort();
097
Log.w(TAG,
"IncorrectURL:"
+url);
098
}
catch
(Exceptione){
099
getRequest.abort();
100
Log.w(TAG,
"Errorwhileretrievingbitmapfrom"
+url,e);
101
}
102
return
null
;
103
}
104
105
@Override
106
protected
void
onPostExecute(Bitmapresult){
107
super
.onPostExecute(result);
108
AsyncListImageact=activityReference.get();
109
if
(act!=
null
&&result!=
null
){
110
act.onComplete(url,result);
111
}
112
}
113
114
115
/**
116
*Copythecontentoftheinputstreamintotheoutputstream,usingatemporary
117
*bytearraybufferwhosesizeisdefinedby{@link#IO_BUFFER_SIZE}.
118
*
119
*@paraminTheinputstreamtocopyfrom.
120
*@paramoutTheoutputstreamtocopyto.
121
*
122
*@throwsjava.io.IOExceptionIfanyerroroccursduringthecopy.
123
*/
124
public
static
void
copy(InputStreamin,OutputStreamout)
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
*Closesthespecifiedstream.
134
*
135
*@paramstreamThestreamtoclose.
136
*/
137
public
static
void
closeStream(Closeablestream){
138
if
(stream!=
null
){
139
try
{
140
stream.close();
141
}
catch
(IOExceptione){
142
android.util.Log.e(TAG,
"Couldnotclosestream"
,e);
143
}
144
}
145
}
146
147
private
void
saveBmpToSd(Bitmapbm,Stringurl){
148
if
(bm==
null
){
149
Log.w(TAG,
"tryingtosavenullbitmap"
);
150
return
;
151
}
152
//判断sdcard上的空间
153
if
(FREE_SD_SPACE_NEEDED_TO_CACHE>freeSpaceOnSd()){
154
Log.w(TAG,
"Lowfreespaceonsd,donotcache"
);
155
removeCache(WHOLESALE_CONV);
156
return
;
157
}
158
Stringfilename=convertUrlToFileName(url);
159
Stringdir=getDirectory(filename);
160
Filefile=
new
File(dir+
"/"
+filename);
161
try
{
162
file.createNewFile();
163
OutputStreamoutStream=
new
FileOutputStream(file);
164
bm.compress(Bitmap.CompressFormat.JPEG,
100
,outStream);
165
outStream.flush();
166
outStream.close();
167
Log.i(TAG,
"Imagesavedtosd"
);
168
}
catch
(FileNotFoundExceptione){
169
Log.w(TAG,
"FileNotFoundException"
);
170
}
catch
(IOExceptione){
171
Log.w(TAG,
"IOException"
);
172
}
173
}
174
175
private
StringconvertUrlToFileName(Stringurl){
176
int
lastIndex=url.lastIndexOf(
'/'
);
177
return
url.substring(lastIndex+
1
);
178
}
179
180
private
StringgetDirectory(Stringfilename){
181
return
WHOLESALE_CONV;
182
}
183
184
/**
185
*计算sdcard上的剩余空间
186
*
187
*@return
188
*/
189
private
int
freeSpaceOnSd(){
190
StatFsstat=
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
*@paramdir
202
*@paramfileName
203
*/
204
private
void
updateFileTime(Stringdir,StringfileName){
205
Filefile=
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
*@paramdirPath
216
*@paramfilename
217
*/
218
private
void
removeCache(StringdirPath){
219
Filedir=
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.getName().contains(WHOLESALE_CONV)){
227
dirSize+=files.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,
"Clearsomeexpiredcachefiles"
);
237
238
for
(
int
i=
0
;i<removeFactor;i++){
239
240
if
(files.getName().contains(WHOLESALE_CONV)){
241
242
files.delete();
243
244
}
245
246
}
247
248
}
249
250
}
251
252
/**
253
*TODO根据文件的最后修改时间进行排序*
254
*/
255
class
FileLastModifSort
implements
Comparator<File>{
256
public
int
compare(Filearg0,Filearg1){
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
*@paramdirPath
271
*@paramfilename
272
*/
273
private
void
removeExpiredCache(StringdirPath,Stringfilename){
274
275
Filefile=
new
File(dirPath,filename);
276
277
if
(System.currentTimeMillis()-file.lastModified()>mTimeDiff){
278
279
Log.i(TAG,
"Clearsomeexpiredcachefiles"
);
280
281
file.delete();
282
283
}
284
285
}
286
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: