Skip to content

Commit fb4609a

Browse files
committedApr 6, 2012
~~
1 parent 32b2414 commit fb4609a

File tree

6 files changed

+1214
-0
lines changed

6 files changed

+1214
-0
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,370 @@
1+
package com.codingwith.us.img;
2+
3+
import java.util.concurrent.Callable;
4+
import java.util.concurrent.CancellationException;
5+
import java.util.concurrent.ExecutionException;
6+
import java.util.concurrent.ExecutorService;
7+
import java.util.concurrent.Executors;
8+
import java.util.concurrent.FutureTask;
9+
import java.util.concurrent.ThreadFactory;
10+
import java.util.concurrent.TimeUnit;
11+
import java.util.concurrent.TimeoutException;
12+
import java.util.concurrent.atomic.AtomicInteger;
13+
14+
import android.os.Handler;
15+
import android.os.Message;
16+
import android.os.Process;
17+
18+
public abstract class BaseAsyncTask<Params, Progress, Result> {
19+
private static final String LOG_TAG = "FifoAsyncTask";
20+
private static final int NUMBER_THREAD = 10;
21+
22+
// private static final int CORE_POOL_SIZE = 5;
23+
// private static final int MAXIMUM_POOL_SIZE = 5;
24+
// private static final int KEEP_ALIVE = 1;
25+
26+
// private static final BlockingQueue<Runnable> sWorkQueue =
27+
// new LinkedBlockingQueue<Runnable>();
28+
//
29+
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
30+
private final AtomicInteger mCount = new AtomicInteger(1);
31+
32+
public Thread newThread(Runnable r) {
33+
return new Thread(r, "PreReadTask #" + mCount.getAndIncrement());
34+
}
35+
};
36+
37+
private static final ExecutorService sExecutor = Executors
38+
.newFixedThreadPool(NUMBER_THREAD, sThreadFactory);// ֻ��һ�������̵߳��̳߳�
39+
40+
private static final int MESSAGE_POST_RESULT = 0x1;
41+
private static final int MESSAGE_POST_PROGRESS = 0x2;
42+
private static final int MESSAGE_POST_CANCEL = 0x3;
43+
44+
private static final InternalHandler sHandler = new InternalHandler();
45+
46+
private final WorkerRunnable<Params, Result> mWorker;
47+
private final FutureTask<Result> mFuture;
48+
49+
private volatile Status mStatus = Status.PENDING;
50+
51+
/**
52+
* Indicates the current status of the task. Each status will be set only
53+
* once during the lifetime of a task.
54+
*/
55+
public enum Status {
56+
/**
57+
* Indicates that the task has not been executed yet.
58+
*/
59+
PENDING,
60+
/**
61+
* Indicates that the task is running.
62+
*/
63+
RUNNING,
64+
/**
65+
* Indicates that {@link FifoAsyncTask#onPostExecute} has finished.
66+
*/
67+
FINISHED,
68+
}
69+
70+
/**
71+
* Creates a new asynchronous task. This constructor must be invoked on the
72+
* UI thread.
73+
*/
74+
public BaseAsyncTask() {
75+
mWorker = new WorkerRunnable<Params, Result>() {
76+
public Result call() throws Exception {
77+
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
78+
return doInBackground(mParams);
79+
}
80+
};
81+
82+
mFuture = new FutureTask<Result>(mWorker) {
83+
@Override
84+
protected void done() {
85+
Message message;
86+
Result result = null;
87+
88+
try {
89+
result = get();
90+
} catch (InterruptedException e) {
91+
android.util.Log.w(LOG_TAG, e);
92+
} catch (ExecutionException e) {
93+
throw new RuntimeException(
94+
"An error occured while executing doInBackground()",
95+
e.getCause());
96+
} catch (CancellationException e) {
97+
message = sHandler.obtainMessage(MESSAGE_POST_CANCEL,
98+
new PreReadTaskResult<Result>(BaseAsyncTask.this,
99+
(Result[]) null));
100+
message.sendToTarget();
101+
return;
102+
} catch (Throwable t) {
103+
throw new RuntimeException(
104+
"An error occured while executing "
105+
+ "doInBackground()", t);
106+
}
107+
108+
message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
109+
new PreReadTaskResult<Result>(BaseAsyncTask.this,
110+
result));
111+
message.sendToTarget();
112+
}
113+
};
114+
}
115+
116+
/**
117+
* Returns the current status of this task.
118+
*
119+
* @return The current status.
120+
*/
121+
public final Status getStatus() {
122+
return mStatus;
123+
}
124+
125+
/**
126+
* Override this method to perform a computation on a background thread. The
127+
* specified parameters are the parameters passed to {@link #execute} by the
128+
* caller of this task.
129+
*
130+
* This method can call {@link #publishProgress} to publish updates on the
131+
* UI thread.
132+
*
133+
* @param params
134+
* The parameters of the task.
135+
*
136+
* @return A result, defined by the subclass of this task.
137+
*
138+
* @see #onPreExecute()
139+
* @see #onPostExecute
140+
* @see #publishProgress
141+
*/
142+
protected abstract Result doInBackground(Params... params);
143+
144+
/**
145+
* Runs on the UI thread before {@link #doInBackground}.
146+
*
147+
* @see #onPostExecute
148+
* @see #doInBackground
149+
*/
150+
protected void onPreExecute() {
151+
}
152+
153+
/**
154+
* Runs on the UI thread after {@link #doInBackground}. The specified result
155+
* is the value returned by {@link #doInBackground} or null if the task was
156+
* cancelled or an exception occured.
157+
*
158+
* @param result
159+
* The result of the operation computed by
160+
* {@link #doInBackground}.
161+
*
162+
* @see #onPreExecute
163+
* @see #doInBackground
164+
*/
165+
@SuppressWarnings({ "UnusedDeclaration" })
166+
protected void onPostExecute(Result result) {
167+
}
168+
169+
/**
170+
* Runs on the UI thread after {@link #publishProgress} is invoked. The
171+
* specified values are the values passed to {@link #publishProgress}.
172+
*
173+
* @param values
174+
* The values indicating progress.
175+
*
176+
* @see #publishProgress
177+
* @see #doInBackground
178+
*/
179+
@SuppressWarnings({ "UnusedDeclaration" })
180+
protected void onProgressUpdate(Progress... values) {
181+
}
182+
183+
/**
184+
* Runs on the UI thread after {@link #cancel(boolean)} is invoked.
185+
*
186+
* @see #cancel(boolean)
187+
* @see #isCancelled()
188+
*/
189+
protected void onCancelled() {
190+
}
191+
192+
/**
193+
* Returns <tt>true</tt> if this task was cancelled before it completed
194+
* normally.
195+
*
196+
* @return <tt>true</tt> if task was cancelled before it completed
197+
*
198+
* @see #cancel(boolean)
199+
*/
200+
public final boolean isCancelled() {
201+
return mFuture.isCancelled();
202+
}
203+
204+
/**
205+
* Attempts to cancel execution of this task. This attempt will fail if the
206+
* task has already completed, already been cancelled, or could not be
207+
* cancelled for some other reason. If successful, and this task has not
208+
* started when <tt>cancel</tt> is called, this task should never run. If
209+
* the task has already started, then the <tt>mayInterruptIfRunning</tt>
210+
* parameter determines whether the thread executing this task should be
211+
* interrupted in an attempt to stop the task.
212+
*
213+
* @param mayInterruptIfRunning
214+
* <tt>true</tt> if the thread executing this task should be
215+
* interrupted; otherwise, in-progress tasks are allowed to
216+
* complete.
217+
*
218+
* @return <tt>false</tt> if the task could not be cancelled, typically
219+
* because it has already completed normally; <tt>true</tt>
220+
* otherwise
221+
*
222+
* @see #isCancelled()
223+
* @see #onCancelled()
224+
*/
225+
public final boolean cancel(boolean mayInterruptIfRunning) {
226+
return mFuture.cancel(mayInterruptIfRunning);
227+
}
228+
229+
/**
230+
* Waits if necessary for the computation to complete, and then retrieves
231+
* its result.
232+
*
233+
* @return The computed result.
234+
*
235+
* @throws CancellationException
236+
* If the computation was cancelled.
237+
* @throws ExecutionException
238+
* If the computation threw an exception.
239+
* @throws InterruptedException
240+
* If the current thread was interrupted while waiting.
241+
*/
242+
public final Result get() throws InterruptedException, ExecutionException {
243+
return mFuture.get();
244+
}
245+
246+
/**
247+
* Waits if necessary for at most the given time for the computation to
248+
* complete, and then retrieves its result.
249+
*
250+
* @param timeout
251+
* Time to wait before cancelling the operation.
252+
* @param unit
253+
* The time unit for the timeout.
254+
*
255+
* @return The computed result.
256+
*
257+
* @throws CancellationException
258+
* If the computation was cancelled.
259+
* @throws ExecutionException
260+
* If the computation threw an exception.
261+
* @throws InterruptedException
262+
* If the current thread was interrupted while waiting.
263+
* @throws TimeoutException
264+
* If the wait timed out.
265+
*/
266+
public final Result get(long timeout, TimeUnit unit)
267+
throws InterruptedException, ExecutionException, TimeoutException {
268+
return mFuture.get(timeout, unit);
269+
}
270+
271+
/**
272+
* Executes the task with the specified parameters. The task returns itself
273+
* (this) so that the caller can keep a reference to it.
274+
*
275+
* This method must be invoked on the UI thread.
276+
*
277+
* @param params
278+
* The parameters of the task.
279+
*
280+
* @return This instance of AsyncTask.
281+
*
282+
* @throws IllegalStateException
283+
* If {@link #getStatus()} returns either
284+
* {@link FifoAsyncTask.Status#RUNNING} or
285+
* {@link FifoAsyncTask.Status#FINISHED}.
286+
*/
287+
public final BaseAsyncTask<Params, Progress, Result> execute(
288+
Params... params) {
289+
if (mStatus != Status.PENDING) {
290+
switch (mStatus) {
291+
case RUNNING:
292+
throw new IllegalStateException("Cannot execute task:"
293+
+ " the task is already running.");
294+
case FINISHED:
295+
throw new IllegalStateException("Cannot execute task:"
296+
+ " the task has already been executed "
297+
+ "(a task can be executed only once)");
298+
}
299+
}
300+
301+
mStatus = Status.RUNNING;
302+
303+
onPreExecute();
304+
305+
mWorker.mParams = params;
306+
sExecutor.execute(mFuture);
307+
308+
return this;
309+
}
310+
311+
/**
312+
* This method can be invoked from {@link #doInBackground} to publish
313+
* updates on the UI thread while the background computation is still
314+
* running. Each call to this method will trigger the execution of
315+
* {@link #onProgressUpdate} on the UI thread.
316+
*
317+
* @param values
318+
* The progress values to update the UI with.
319+
*
320+
* @see #onProgressUpdate
321+
* @see #doInBackground
322+
*/
323+
protected final void publishProgress(Progress... values) {
324+
sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
325+
new PreReadTaskResult<Progress>(this, values)).sendToTarget();
326+
}
327+
328+
private void finish(Result result) {
329+
if (isCancelled())
330+
result = null;
331+
onPostExecute(result);
332+
mStatus = Status.FINISHED;
333+
}
334+
335+
private static class InternalHandler extends Handler {
336+
@SuppressWarnings({ "unchecked", "RawUseOfParameterizedType" })
337+
@Override
338+
public void handleMessage(Message msg) {
339+
PreReadTaskResult result = (PreReadTaskResult) msg.obj;
340+
switch (msg.what) {
341+
case MESSAGE_POST_RESULT:
342+
// There is only one result
343+
result.mTask.finish(result.mData[0]);
344+
break;
345+
case MESSAGE_POST_PROGRESS:
346+
result.mTask.onProgressUpdate(result.mData);
347+
break;
348+
case MESSAGE_POST_CANCEL:
349+
result.mTask.onCancelled();
350+
break;
351+
}
352+
}
353+
}
354+
355+
private static abstract class WorkerRunnable<Params, Result> implements
356+
Callable<Result> {
357+
Params[] mParams;
358+
}
359+
360+
@SuppressWarnings({ "RawUseOfParameterizedType" })
361+
private static class PreReadTaskResult<Data> {
362+
final BaseAsyncTask mTask;
363+
final Data[] mData;
364+
365+
PreReadTaskResult(BaseAsyncTask task, Data... data) {
366+
mTask = task;
367+
mData = data;
368+
}
369+
}
370+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/**
2+
*
3+
*/
4+
package com.codingwith.us.img;
5+
6+
import java.io.IOException;
7+
import java.net.MalformedURLException;
8+
import java.net.URL;
9+
10+
11+
import android.graphics.Bitmap;
12+
import android.graphics.BitmapFactory;
13+
import android.util.Log;
14+
import android.widget.ImageView;
15+
16+
/**
17+
* @author chenwei10
18+
*
19+
*/
20+
public class GetBitmapByUrlTask extends BaseAsyncTask<Object, Object, Object> {
21+
private ImageView view;
22+
private String url;
23+
24+
@Override
25+
protected Bitmap doInBackground(Object... params) {
26+
// TODO Auto-generated method stub
27+
url = (String) params[0];
28+
view = (ImageView) params[1];
29+
Bitmap bmp = null;
30+
try {
31+
bmp = ImageDownloader.GetInstance().GetBitmapFromCache(url);
32+
if (bmp == null) {
33+
bmp = BitmapFactory.decodeStream(new URL(url).openStream());
34+
}
35+
} catch (MalformedURLException e) {
36+
// TODO Auto-generated catch block
37+
e.printStackTrace();
38+
} catch (IOException e) {
39+
// TODO Auto-generated catch block
40+
e.printStackTrace();
41+
}
42+
if (bmp != null) {
43+
ImageDownloader.GetInstance().AddBitmapToCache(url, bmp);
44+
UtilFile.GetInstance().saveBmpToSd(bmp, url);
45+
}
46+
return bmp;
47+
}
48+
49+
protected void onPostExecute(Object result) {
50+
// TODO Auto-generated method stub
51+
super.onPostExecute(result);
52+
if (result != null) {
53+
Bitmap bmp = (Bitmap) result;
54+
String kk = (String) view.getTag();
55+
if (!bmp.isRecycled() & url.equalsIgnoreCase(kk)) {
56+
view.setImageBitmap(bmp);
57+
} else {
58+
Log.i("GetBitmapByUrlTask", url);
59+
}
60+
}
61+
}
62+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/**
2+
*
3+
*/
4+
package com.codingwith.us.img;
5+
6+
import java.lang.ref.SoftReference;
7+
import java.util.HashMap;
8+
import java.util.LinkedHashMap;
9+
import java.util.concurrent.ConcurrentHashMap;
10+
11+
12+
import android.graphics.Bitmap;
13+
import android.util.Log;
14+
import android.widget.ImageView;
15+
16+
/**
17+
* @author chenwei10
18+
*
19+
*/
20+
public class ImageDownloader {
21+
private static final int HARD_CACHE_CAPACITY = 0;
22+
private static final int SOFT_CACHE_CAPACITY = 0;
23+
private static ImageDownloader inst;
24+
25+
public static ImageDownloader GetInstance() {
26+
if (inst == null) {
27+
inst = new ImageDownloader();
28+
29+
}
30+
return inst;
31+
}
32+
33+
private final static ConcurrentHashMap<String, SoftReference<Bitmap>> sSoftBitmapCache = new ConcurrentHashMap<String, SoftReference<Bitmap>>(
34+
SOFT_CACHE_CAPACITY / 2);
35+
private final static HashMap<String, Bitmap> sHardBitmapCache = new LinkedHashMap<String, Bitmap>(
36+
HARD_CACHE_CAPACITY / 2, 0.75f, true) {
37+
/**
38+
*
39+
*/
40+
private static final long serialVersionUID = 1L;
41+
42+
@Override
43+
protected boolean removeEldestEntry(
44+
LinkedHashMap.Entry<String, Bitmap> eldest) {
45+
if (size() > HARD_CACHE_CAPACITY) {
46+
// Entries push-out of hard reference cache are transferred to
47+
// soft reference cache
48+
sSoftBitmapCache.put(eldest.getKey(),
49+
new SoftReference<Bitmap>(eldest.getValue()));
50+
// Log.i("removeEldestEntry",
51+
// "Transfer From hard cache to Soft cache");
52+
return true;
53+
} else
54+
return false;
55+
}
56+
};
57+
58+
public void Clear() {
59+
sHardBitmapCache.clear();
60+
sSoftBitmapCache.clear();
61+
}
62+
63+
public void AddBitmapToCache(String url, Bitmap bitmap) {
64+
if (bitmap != null) {
65+
synchronized (sHardBitmapCache) {
66+
sHardBitmapCache.put(url, bitmap);
67+
}
68+
}
69+
}
70+
71+
public Bitmap GetBitmapFromCache(String url) {
72+
// First try the hard reference cache
73+
synchronized (sHardBitmapCache) {
74+
final Bitmap bitmap = sHardBitmapCache.get(url);
75+
if (bitmap != null) {
76+
// Bitmap found in hard cache
77+
// Move element to first position, so that it is removed last
78+
sHardBitmapCache.remove(url);
79+
sHardBitmapCache.put(url, bitmap);
80+
return bitmap;
81+
}
82+
}
83+
// Then try the soft reference cache
84+
SoftReference<Bitmap> bitmapReference = sSoftBitmapCache.get(url);
85+
if (bitmapReference != null) {
86+
final Bitmap bitmap = bitmapReference.get();
87+
if (bitmap != null) {
88+
// Bitmap found in soft cache
89+
return bitmap;
90+
} else {
91+
// Soft reference has been Garbage Collected
92+
sSoftBitmapCache.remove(url);
93+
Log.i("getBitmapFromCache", "gc Soft cache!");
94+
}
95+
}
96+
return null;
97+
}
98+
99+
public void DownLoad(String url, ImageView img) {
100+
if (url == null || img == null) {
101+
return;
102+
}
103+
Bitmap bmp = null;
104+
bmp = GetBitmapFromCache(url);
105+
img.setTag(url);
106+
if (bmp != null) {
107+
img.setImageBitmap(bmp);
108+
} else {
109+
bmp = UtilFile.GetInstance().getBmpFromSd(url);
110+
if (bmp != null) {
111+
img.setImageBitmap(bmp);
112+
}else {
113+
new GetBitmapByUrlTask().execute(url, img);
114+
}
115+
}
116+
}
117+
}
+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
*
3+
*/
4+
package com.codingwith.us.img;
5+
6+
import java.security.MessageDigest;
7+
8+
/**
9+
* @author chenwei10
10+
*
11+
*/
12+
public class MD5 {
13+
static public String md5_string(String s) {
14+
byte[] unencodedPassword = s.getBytes();
15+
16+
MessageDigest md = null;
17+
18+
try {
19+
md = MessageDigest.getInstance("MD5");
20+
} catch (Exception e) {
21+
return s;
22+
}
23+
24+
md.reset();
25+
md.update(unencodedPassword);
26+
byte[] encodedPassword = md.digest();
27+
StringBuffer buf = new StringBuffer();
28+
29+
for (int i = 0; i < encodedPassword.length; i++) {
30+
if ((encodedPassword[i] & 0xff) < 0x10) {
31+
buf.append("0");
32+
}
33+
buf.append(Long.toString(encodedPassword[i] & 0xff, 16));
34+
}
35+
36+
return buf.toString();
37+
}
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
/**
2+
*
3+
*/
4+
package com.codingwith.us.img;
5+
6+
import java.io.File;
7+
import java.io.FileInputStream;
8+
import java.io.FileNotFoundException;
9+
import java.io.FileOutputStream;
10+
import java.io.IOException;
11+
import java.io.OutputStream;
12+
import java.util.Arrays;
13+
import java.util.Comparator;
14+
15+
16+
import android.graphics.Bitmap;
17+
import android.graphics.BitmapFactory;
18+
import android.os.Environment;
19+
import android.os.StatFs;
20+
import android.util.Log;
21+
22+
/**
23+
* @author chenwei10
24+
*
25+
*/
26+
public class UtilFile {
27+
private static final int FREE_SD_SPACE_NEEDED_TO_CACHE = 100;
28+
private static final String TAG = "UtilFile";
29+
private static final CharSequence WHOLESALE_CONV = "png";
30+
private static final int CACHE_SIZE = 50;
31+
private static final int MB = 1024;
32+
private static final String AppName = "aaa";
33+
private long mTimeDiff;
34+
35+
private static UtilFile inst;
36+
37+
public static UtilFile GetInstance() {
38+
if (inst == null) {
39+
inst = new UtilFile();
40+
}
41+
return inst;
42+
}
43+
44+
public boolean checksdcard() {
45+
boolean mExternalStorageAvailable = false;
46+
boolean mExternalStorageWriteable = false;
47+
String state = Environment.getExternalStorageState();
48+
if (Environment.MEDIA_MOUNTED.equals(state)) {
49+
// We can read and write the media
50+
Log.w("cksdcard", "MEDIA_MOUNTED");
51+
mExternalStorageAvailable = true;
52+
mExternalStorageWriteable = true;
53+
} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
54+
// We can only read the media
55+
Log.w("cksdcard", "MEDIA_MOUNTED_READ_ONLY");
56+
mExternalStorageAvailable = true;
57+
mExternalStorageWriteable = false;
58+
} else {
59+
// Something else is wrong. It may be one of many other states,
60+
// but all we need to know is we can neither read nor write
61+
Log.w("cksdcard", "Something else is wrong");
62+
mExternalStorageAvailable = false;
63+
mExternalStorageWriteable = false;
64+
}
65+
return mExternalStorageWriteable;
66+
}
67+
68+
public Bitmap getBmpFromSd(String url) {
69+
if (!checksdcard()) {
70+
return null;
71+
}
72+
String filename = convertUrlToFileName(url);
73+
String dir = getDirectory(filename);
74+
File imageFileOnExternalDirectory = new File(dir + "/" + filename);
75+
if (!imageFileOnExternalDirectory.exists()) {
76+
return null;
77+
}
78+
// Decode image size
79+
BitmapFactory.Options options = new BitmapFactory.Options();
80+
options.inJustDecodeBounds = true;
81+
FileInputStream fis = null;
82+
try {
83+
int scale = 1;
84+
// Decode with inSampleSize
85+
BitmapFactory.Options o2 = new BitmapFactory.Options();
86+
o2.inSampleSize = scale;
87+
88+
fis = new FileInputStream(imageFileOnExternalDirectory);
89+
Bitmap bm = BitmapFactory.decodeStream(fis, null, o2);
90+
if (fis != null) {
91+
fis.close();
92+
}
93+
return bm;
94+
} catch (FileNotFoundException e) {
95+
// TODO Auto-generated catch block
96+
e.printStackTrace();
97+
} catch (IOException e) {
98+
// TODO Auto-generated catch block
99+
e.printStackTrace();
100+
} finally {
101+
102+
}
103+
104+
return null;
105+
}
106+
107+
public void saveBmpToSd(Bitmap bm, String url) {
108+
if (bm == null) {
109+
Log.w(TAG, " trying to savenull bitmap");
110+
return;
111+
}
112+
// 判断sdcard上的空间
113+
if (FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {
114+
Log.w(TAG, "Low free space onsd, do not cache");
115+
return;
116+
}
117+
String filename = convertUrlToFileName(url);
118+
String dir = getDirectory(filename);
119+
File file = new File(dir + "/" + filename);
120+
if (file.exists()) {
121+
file.setLastModified(System.currentTimeMillis());
122+
return ;
123+
}
124+
try {
125+
file.createNewFile();
126+
OutputStream outStream = new FileOutputStream(file);
127+
bm.compress(Bitmap.CompressFormat.PNG, 100, outStream);
128+
outStream.flush();
129+
outStream.close();
130+
Log.i(TAG, "Image saved tosd");
131+
} catch (FileNotFoundException e) {
132+
Log.w(TAG, "FileNotFoundException");
133+
} catch (IOException e) {
134+
Log.w(TAG, "IOException");
135+
}
136+
}
137+
138+
private String getDirectory(String filename) {
139+
// TODO Auto-generated method stub
140+
String directory = Environment.getExternalStorageDirectory()
141+
.getAbsolutePath() + "/" + AppName + "/photo";
142+
File dir = new File(directory);
143+
if (!dir.exists()) {
144+
dir.mkdirs();
145+
}
146+
return directory;
147+
}
148+
149+
private String convertUrlToFileName(String url) {
150+
// TODO Auto-generated method stub
151+
return MD5.md5_string(url);
152+
}
153+
154+
/**
155+
* 计算sdcard上的剩余空间
156+
*
157+
* @return
158+
*/
159+
private int freeSpaceOnSd() {
160+
StatFs stat = new StatFs(Environment.getExternalStorageDirectory()
161+
.getPath());
162+
double sdFreeMB = ((double) stat.getAvailableBlocks() * (double) stat
163+
.getBlockSize()) / MB;
164+
return (int) sdFreeMB;
165+
}
166+
167+
/**
168+
* 修改文件的最后修改时间
169+
*
170+
* @param dir
171+
* @param fileName
172+
*/
173+
public void updateFileTime(String dir, String fileName) {
174+
File file = new File(dir, fileName);
175+
long newModifiedTime = System.currentTimeMillis();
176+
file.setLastModified(newModifiedTime);
177+
}
178+
179+
// 本地缓存优化
180+
181+
/**
182+
* 计算存储目录下的文件大小,
183+
* 当文件总大小大于规定的CACHE_SIZE或者sdcard剩余空间小于FREE_SD_SPACE_NEEDED_TO_CACHE的规定
184+
* 那么删除40%最近没有被使用的文件
185+
*
186+
* @param dirPath
187+
* @param filename
188+
*/
189+
public void removeCache(String dirPath) {
190+
File dir = new File(dirPath);
191+
File[] files = dir.listFiles();
192+
if (files == null) {
193+
return;
194+
}
195+
int dirSize = 0;
196+
for (int i = 0; i < files.length; i++) {
197+
if (files[i].getName().contains(WHOLESALE_CONV)) {
198+
dirSize += files[i].length();
199+
}
200+
}
201+
if (dirSize > CACHE_SIZE * MB
202+
|| FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {
203+
int removeFactor = (int) ((0.4 * files.length) + 1);
204+
205+
Arrays.sort(files, new FileLastModifSort());
206+
207+
Log.i(TAG, "Clear some expiredcache files ");
208+
209+
for (int i = 0; i < removeFactor; i++) {
210+
211+
if (files[i].getName().contains(WHOLESALE_CONV)) {
212+
213+
files[i].delete();
214+
215+
}
216+
217+
}
218+
219+
}
220+
221+
}
222+
223+
/**
224+
* 删除过期文件
225+
*
226+
* @param dirPath
227+
* @param filename
228+
*/
229+
public void removeExpiredCache(String dirPath, String filename) {
230+
231+
File file = new File(dirPath, filename);
232+
233+
if (System.currentTimeMillis() - file.lastModified() > mTimeDiff) {
234+
235+
Log.i(TAG, "Clear some expiredcache files ");
236+
237+
file.delete();
238+
239+
}
240+
241+
}
242+
243+
/**
244+
* TODO 根据文件的最后修改时间进行排序 *
245+
*/
246+
class FileLastModifSort implements Comparator<File> {
247+
public int compare(File arg0, File arg1) {
248+
if (arg0.lastModified() > arg1.lastModified()) {
249+
return 1;
250+
} else if (arg0.lastModified() == arg1.lastModified()) {
251+
return 0;
252+
} else {
253+
return -1;
254+
}
255+
}
256+
}
257+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,370 @@
1+
package www.codingwith.us.task;
2+
3+
import java.util.concurrent.Callable;
4+
import java.util.concurrent.CancellationException;
5+
import java.util.concurrent.ExecutionException;
6+
import java.util.concurrent.ExecutorService;
7+
import java.util.concurrent.Executors;
8+
import java.util.concurrent.FutureTask;
9+
import java.util.concurrent.ThreadFactory;
10+
import java.util.concurrent.TimeUnit;
11+
import java.util.concurrent.TimeoutException;
12+
import java.util.concurrent.atomic.AtomicInteger;
13+
14+
import android.os.Handler;
15+
import android.os.Message;
16+
import android.os.Process;
17+
18+
public abstract class BaseAsyncTask<Params, Progress, Result> {
19+
private static final String LOG_TAG = "FifoAsyncTask";
20+
private static final int NUMBER_THREAD = 10;
21+
22+
// private static final int CORE_POOL_SIZE = 5;
23+
// private static final int MAXIMUM_POOL_SIZE = 5;
24+
// private static final int KEEP_ALIVE = 1;
25+
26+
// private static final BlockingQueue<Runnable> sWorkQueue =
27+
// new LinkedBlockingQueue<Runnable>();
28+
//
29+
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
30+
private final AtomicInteger mCount = new AtomicInteger(1);
31+
32+
public Thread newThread(Runnable r) {
33+
return new Thread(r, "PreReadTask #" + mCount.getAndIncrement());
34+
}
35+
};
36+
37+
private static final ExecutorService sExecutor = Executors
38+
.newFixedThreadPool(NUMBER_THREAD, sThreadFactory);// ֻ��һ�������̵߳��̳߳�
39+
40+
private static final int MESSAGE_POST_RESULT = 0x1;
41+
private static final int MESSAGE_POST_PROGRESS = 0x2;
42+
private static final int MESSAGE_POST_CANCEL = 0x3;
43+
44+
private static final InternalHandler sHandler = new InternalHandler();
45+
46+
private final WorkerRunnable<Params, Result> mWorker;
47+
private final FutureTask<Result> mFuture;
48+
49+
private volatile Status mStatus = Status.PENDING;
50+
51+
/**
52+
* Indicates the current status of the task. Each status will be set only
53+
* once during the lifetime of a task.
54+
*/
55+
public enum Status {
56+
/**
57+
* Indicates that the task has not been executed yet.
58+
*/
59+
PENDING,
60+
/**
61+
* Indicates that the task is running.
62+
*/
63+
RUNNING,
64+
/**
65+
* Indicates that {@link FifoAsyncTask#onPostExecute} has finished.
66+
*/
67+
FINISHED,
68+
}
69+
70+
/**
71+
* Creates a new asynchronous task. This constructor must be invoked on the
72+
* UI thread.
73+
*/
74+
public BaseAsyncTask() {
75+
mWorker = new WorkerRunnable<Params, Result>() {
76+
public Result call() throws Exception {
77+
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
78+
return doInBackground(mParams);
79+
}
80+
};
81+
82+
mFuture = new FutureTask<Result>(mWorker) {
83+
@Override
84+
protected void done() {
85+
Message message;
86+
Result result = null;
87+
88+
try {
89+
result = get();
90+
} catch (InterruptedException e) {
91+
android.util.Log.w(LOG_TAG, e);
92+
} catch (ExecutionException e) {
93+
throw new RuntimeException(
94+
"An error occured while executing doInBackground()",
95+
e.getCause());
96+
} catch (CancellationException e) {
97+
message = sHandler.obtainMessage(MESSAGE_POST_CANCEL,
98+
new PreReadTaskResult<Result>(BaseAsyncTask.this,
99+
(Result[]) null));
100+
message.sendToTarget();
101+
return;
102+
} catch (Throwable t) {
103+
throw new RuntimeException(
104+
"An error occured while executing "
105+
+ "doInBackground()", t);
106+
}
107+
108+
message = sHandler
109+
.obtainMessage(MESSAGE_POST_RESULT,
110+
new PreReadTaskResult<Result>(BaseAsyncTask.this,
111+
result));
112+
message.sendToTarget();
113+
}
114+
};
115+
}
116+
117+
/**
118+
* Returns the current status of this task.
119+
*
120+
* @return The current status.
121+
*/
122+
public final Status getStatus() {
123+
return mStatus;
124+
}
125+
126+
/**
127+
* Override this method to perform a computation on a background thread. The
128+
* specified parameters are the parameters passed to {@link #execute} by the
129+
* caller of this task.
130+
*
131+
* This method can call {@link #publishProgress} to publish updates on the
132+
* UI thread.
133+
*
134+
* @param params
135+
* The parameters of the task.
136+
*
137+
* @return A result, defined by the subclass of this task.
138+
*
139+
* @see #onPreExecute()
140+
* @see #onPostExecute
141+
* @see #publishProgress
142+
*/
143+
protected abstract Result doInBackground(Params... params);
144+
145+
/**
146+
* Runs on the UI thread before {@link #doInBackground}.
147+
*
148+
* @see #onPostExecute
149+
* @see #doInBackground
150+
*/
151+
protected void onPreExecute() {
152+
}
153+
154+
/**
155+
* Runs on the UI thread after {@link #doInBackground}. The specified result
156+
* is the value returned by {@link #doInBackground} or null if the task was
157+
* cancelled or an exception occured.
158+
*
159+
* @param result
160+
* The result of the operation computed by
161+
* {@link #doInBackground}.
162+
*
163+
* @see #onPreExecute
164+
* @see #doInBackground
165+
*/
166+
@SuppressWarnings({ "UnusedDeclaration" })
167+
protected void onPostExecute(Result result) {
168+
}
169+
170+
/**
171+
* Runs on the UI thread after {@link #publishProgress} is invoked. The
172+
* specified values are the values passed to {@link #publishProgress}.
173+
*
174+
* @param values
175+
* The values indicating progress.
176+
*
177+
* @see #publishProgress
178+
* @see #doInBackground
179+
*/
180+
@SuppressWarnings({ "UnusedDeclaration" })
181+
protected void onProgressUpdate(Progress... values) {
182+
}
183+
184+
/**
185+
* Runs on the UI thread after {@link #cancel(boolean)} is invoked.
186+
*
187+
* @see #cancel(boolean)
188+
* @see #isCancelled()
189+
*/
190+
protected void onCancelled() {
191+
}
192+
193+
/**
194+
* Returns <tt>true</tt> if this task was cancelled before it completed
195+
* normally.
196+
*
197+
* @return <tt>true</tt> if task was cancelled before it completed
198+
*
199+
* @see #cancel(boolean)
200+
*/
201+
public final boolean isCancelled() {
202+
return mFuture.isCancelled();
203+
}
204+
205+
/**
206+
* Attempts to cancel execution of this task. This attempt will fail if the
207+
* task has already completed, already been cancelled, or could not be
208+
* cancelled for some other reason. If successful, and this task has not
209+
* started when <tt>cancel</tt> is called, this task should never run. If
210+
* the task has already started, then the <tt>mayInterruptIfRunning</tt>
211+
* parameter determines whether the thread executing this task should be
212+
* interrupted in an attempt to stop the task.
213+
*
214+
* @param mayInterruptIfRunning
215+
* <tt>true</tt> if the thread executing this task should be
216+
* interrupted; otherwise, in-progress tasks are allowed to
217+
* complete.
218+
*
219+
* @return <tt>false</tt> if the task could not be cancelled, typically
220+
* because it has already completed normally; <tt>true</tt>
221+
* otherwise
222+
*
223+
* @see #isCancelled()
224+
* @see #onCancelled()
225+
*/
226+
public final boolean cancel(boolean mayInterruptIfRunning) {
227+
return mFuture.cancel(mayInterruptIfRunning);
228+
}
229+
230+
/**
231+
* Waits if necessary for the computation to complete, and then retrieves
232+
* its result.
233+
*
234+
* @return The computed result.
235+
*
236+
* @throws CancellationException
237+
* If the computation was cancelled.
238+
* @throws ExecutionException
239+
* If the computation threw an exception.
240+
* @throws InterruptedException
241+
* If the current thread was interrupted while waiting.
242+
*/
243+
public final Result get() throws InterruptedException, ExecutionException {
244+
return mFuture.get();
245+
}
246+
247+
/**
248+
* Waits if necessary for at most the given time for the computation to
249+
* complete, and then retrieves its result.
250+
*
251+
* @param timeout
252+
* Time to wait before cancelling the operation.
253+
* @param unit
254+
* The time unit for the timeout.
255+
*
256+
* @return The computed result.
257+
*
258+
* @throws CancellationException
259+
* If the computation was cancelled.
260+
* @throws ExecutionException
261+
* If the computation threw an exception.
262+
* @throws InterruptedException
263+
* If the current thread was interrupted while waiting.
264+
* @throws TimeoutException
265+
* If the wait timed out.
266+
*/
267+
public final Result get(long timeout, TimeUnit unit)
268+
throws InterruptedException, ExecutionException, TimeoutException {
269+
return mFuture.get(timeout, unit);
270+
}
271+
272+
/**
273+
* Executes the task with the specified parameters. The task returns itself
274+
* (this) so that the caller can keep a reference to it.
275+
*
276+
* This method must be invoked on the UI thread.
277+
*
278+
* @param params
279+
* The parameters of the task.
280+
*
281+
* @return This instance of AsyncTask.
282+
*
283+
* @throws IllegalStateException
284+
* If {@link #getStatus()} returns either
285+
* {@link FifoAsyncTask.Status#RUNNING} or
286+
* {@link FifoAsyncTask.Status#FINISHED}.
287+
*/
288+
public final BaseAsyncTask<Params, Progress, Result> execute(Params... params) {
289+
if (mStatus != Status.PENDING) {
290+
switch (mStatus) {
291+
case RUNNING:
292+
throw new IllegalStateException("Cannot execute task:"
293+
+ " the task is already running.");
294+
case FINISHED:
295+
throw new IllegalStateException("Cannot execute task:"
296+
+ " the task has already been executed "
297+
+ "(a task can be executed only once)");
298+
}
299+
}
300+
301+
mStatus = Status.RUNNING;
302+
303+
onPreExecute();
304+
305+
mWorker.mParams = params;
306+
sExecutor.execute(mFuture);
307+
308+
return this;
309+
}
310+
311+
/**
312+
* This method can be invoked from {@link #doInBackground} to publish
313+
* updates on the UI thread while the background computation is still
314+
* running. Each call to this method will trigger the execution of
315+
* {@link #onProgressUpdate} on the UI thread.
316+
*
317+
* @param values
318+
* The progress values to update the UI with.
319+
*
320+
* @see #onProgressUpdate
321+
* @see #doInBackground
322+
*/
323+
protected final void publishProgress(Progress... values) {
324+
sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
325+
new PreReadTaskResult<Progress>(this, values)).sendToTarget();
326+
}
327+
328+
private void finish(Result result) {
329+
if (isCancelled())
330+
result = null;
331+
onPostExecute(result);
332+
mStatus = Status.FINISHED;
333+
}
334+
335+
private static class InternalHandler extends Handler {
336+
@SuppressWarnings({ "unchecked", "RawUseOfParameterizedType" })
337+
@Override
338+
public void handleMessage(Message msg) {
339+
PreReadTaskResult result = (PreReadTaskResult) msg.obj;
340+
switch (msg.what) {
341+
case MESSAGE_POST_RESULT:
342+
// There is only one result
343+
result.mTask.finish(result.mData[0]);
344+
break;
345+
case MESSAGE_POST_PROGRESS:
346+
result.mTask.onProgressUpdate(result.mData);
347+
break;
348+
case MESSAGE_POST_CANCEL:
349+
result.mTask.onCancelled();
350+
break;
351+
}
352+
}
353+
}
354+
355+
private static abstract class WorkerRunnable<Params, Result> implements
356+
Callable<Result> {
357+
Params[] mParams;
358+
}
359+
360+
@SuppressWarnings({ "RawUseOfParameterizedType" })
361+
private static class PreReadTaskResult<Data> {
362+
final BaseAsyncTask mTask;
363+
final Data[] mData;
364+
365+
PreReadTaskResult(BaseAsyncTask task, Data... data) {
366+
mTask = task;
367+
mData = data;
368+
}
369+
}
370+
}

0 commit comments

Comments
 (0)
Please sign in to comment.