Afinal是什么,到github看看吧:Afinal
而该文章中,为Afinal扩展了什么,详细代码可以到我的github看看:Afinal扩展
1、添加publishStart
添加这个方法,主要是为了给http相关的操作进行扩展。
通过这个扩展,可以使得在http请求进行之前,先加载之前曾经请求的http缓存。
在下面的类中,进行修改:
1 net.tsz.afinal.http.HttpHandler
修改为:
1 @Override
2 protected Object doInBackground(Object... params) {
3 if (params != null && params.length == 3) {
4 targetUrl = String.valueOf(params[1]);
5 isResume = (Boolean) params[2];
6 }
7 try {
8 publishStart();
9 makeRequestWithRetries((HttpUriRequest) params[0]);
10
11 } catch (IOException e) {
12 String msg = e.getMessage();
13 if (msg == null) {
14 msg = e.toString();
15 }
16 publishProgress(UPDATE_FAILURE, e, 0, msg); // 结束
17 }
18
19 return null;
20 }
因为publicProgress方法是final方法,不能被重写;
所以封装一下publicProgress(UPDATE_START)方法的调用,那么pubicStart()方法就可以被重写了。
1 protected void publishStart() {
2 publishProgress(UPDATE_START); // 开始
3 }
使用时,继承HttpHandler,重写如下,进行缓存的加载:
1 @Override
2 protected void publishStart() {
3 super.publishStart();
4 if (ajaxCallBack instanceof AsyncCallBack) {
5 final AsyncCallBack asyncCallBack = ((AsyncCallBack) ajaxCallBack);
6 if (asyncCallBack.toLoad == 1) {
7 String urlId = getUrlId();
8 final Response response = Response.load(urlId);
9 if (response != null) {
10 parse(response, null);
11 AppContext.runUI(new Runnable() {
12 @Override
13 public void run() {
14 asyncCallBack.onLoadResponse(response);
15 }
16 });
17 }
18 }
19 }
20 }
2、加载图片时,显示进度
显示如下加载进度:
修改如下类:
1 net.tsz.afinal.FinalBitmap
修改如下:
1 public static abstract class AsyncDrawable extends Drawable {
2 private final BitmapLoadAndDisplayTask mTask;
3 public Drawable mDrawable;
4
5 /**
6 * 画笔对象的引用
7 */
8 private Paint paint;
9
10 /**
11 * 圆环的颜色
12 */
13 private int roundColor;
14
15 /**
16 * 圆环进度的颜色
17 */
18 private int roundProgressColor;
19
20 /**
21 * 中间进度百分比的字符串的颜色
22 */
23 private int textColor;
24
25 /**
26 * 中间进度百分比的字符串的字体
27 */
28 private float textSize;
29
30 /**
31 * 圆环的宽度
32 */
33 private float roundWidth;
34 /**
35 * 圆环的半径
36 */
37 private float roundRadius;
38
39 /**
40 * 当前进度
41 */
42 private int progress;
43
44 public AsyncDrawable(Context context, BitmapLoadAndDisplayTask bitmapWorkerTask) {
45 mTask = bitmapWorkerTask;
46 paint = new Paint(Paint.ANTI_ALIAS_FLAG);
47 paint.setAntiAlias(true);
48 DisplayMetrics metrics = context.getResources().getDisplayMetrics();
49 textSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 12, metrics);
50 roundWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3, metrics);
51 roundRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 15, metrics);
52 roundColor = Color.WHITE;
53 roundProgressColor = Color.BLUE;
54 textColor = Color.WHITE;
55 progress = -1;
56 }
57
58 public BitmapLoadAndDisplayTask getBitmapWorkerTask() {
59 return mTask;
60 }
61
62 @Override
63 public void draw(Canvas canvas) {
64 Rect bounds = getBounds();
65 if (mDrawable != null) {
66 mDrawable.setBounds(bounds);
67 mDrawable.draw(canvas);
68 }
69 if (progress == -1) {
70 return;
71 }
72 // if (bounds.width() / 2 < roundRadius || bounds.height() / 2 <
73 // roundRadius) {
74 // return;
75 // }
76
77 /**
78 * 画最外层的大圆环
79 */
80 int centreX = bounds.centerX(); // 获取圆心的x坐标
81 int centreY = bounds.centerY(); // 获取圆心的x坐标
82
83 paint.setColor(roundColor); // 设置圆环的颜色
84 paint.setStyle(Paint.Style.STROKE); // 设置空心
85 paint.setStrokeWidth(roundWidth); // 设置圆环的宽度
86 canvas.drawCircle(centreX, centreY, roundRadius, paint); // 画出圆环
87
88 /**
89 * 画圆弧 ,画圆环的进度
90 */
91 paint.setStrokeWidth(roundWidth); // 设置圆环的宽度
92 paint.setColor(roundProgressColor); // 设置进度的颜色
93 RectF oval = new RectF(centreX - roundRadius, centreY - roundRadius, centreX + roundRadius, centreY + roundRadius); // 用于定义的圆弧的形状和大小的界限
94 paint.setStyle(Paint.Style.STROKE);
95 canvas.drawArc(oval, 0, 360 * progress / 100, false, paint); // 根据进度画圆弧
96
97 /**
98 * 画进度百分比
99 */
100 paint.setStrokeWidth(0);
101 paint.setColor(textColor);
102 paint.setTextSize(textSize);
103 // paint.setTypeface(Typeface.DEFAULT_BOLD); // 设置字体
104 String progressText = progress + "%";
105 float textWidth = paint.measureText(progressText); // 测量字体宽度,我们需要根据字体的宽度设置在圆环中间
106 canvas.drawText(progressText, centreX - textWidth / 2, centreY + textSize / 2, paint); // 画出进度百分比
107 }
108
109 public void setProgress(int progress) {
110 this.progress = progress;
111 invalidateSelf();
112 }
113
114 @Override
115 public int getOpacity() {
116 return 0;
117 }
118
119 @Override
120 public void setAlpha(int arg0) {
121 }
122
123 @Override
124 public void setColorFilter(ColorFilter arg0) {
125 }
126 };
以上类,详细的实现可以看draw方法会progress进行绘制的操作
1 public static class AsyncColorDrawable extends AsyncDrawable {
2 public static int color = 0xaabbbbbb;
3
4 public AsyncColorDrawable(Context context, BitmapLoadAndDisplayTask bitmapWorkerTask) {
5 this(context, bitmapWorkerTask, color);
6 }
7
8 public AsyncColorDrawable(Context context, BitmapLoadAndDisplayTask bitmapWorkerTask, float radius) {
9 super(context, bitmapWorkerTask);
10 if (radius == -1) {
11 ShapeDrawable shapeDrawable = new ShapeDrawable(new OvalShape());
12 shapeDrawable.getPaint().setColor(color);
13 mDrawable = shapeDrawable;
14 } else if (radius == 0) {
15 mDrawable = new ColorDrawable(color);
16 } else if (radius > 0) {
17 float[] outerR = new float[] { radius, radius, radius, radius, radius, radius, radius, radius };
18 RoundRectShape roundRectShape = new RoundRectShape(outerR, null, null);
19 ShapeDrawable shapeDrawable = new ShapeDrawable(roundRectShape);
20 shapeDrawable.getPaint().setColor(color);
21 mDrawable = shapeDrawable;
22 }
23 }
24
25 public AsyncColorDrawable(Context context, BitmapLoadAndDisplayTask bitmapWorkerTask, int color) {
26 super(context, bitmapWorkerTask);
27 mDrawable = new ColorDrawable(color);
28 }
29 }
以上只是简单的一个继承,实现了一个背景是灰色的默认显示,如加载前的默认显示和加载失败之后的显示。
1 private class BitmapLoadAndDisplayTask extends AsyncTask<Object, Integer, Bitmap> {
2
3 @Override
4 protected Bitmap doInBackground(Object... params) {
5 dataString = (String) params[0];
6 Bitmap bitmap = null;
7
8 synchronized (mPauseWorkLock) {
9 while (mPauseWork && !isCancelled()) {
10 try {
11 mPauseWorkLock.wait();
12 } catch (InterruptedException e) {
13 }
14 }
15 }
16
17 if (bitmap == null && !isCancelled() && !mExitTasksEarly) {
18 if (displayConfig.getLoading()) {
19 bitmap = processBitmap(dataString, displayConfig, new ProgressCallBack() {
20 @Override
21 public void callBack(long count, long current) {
22 int progress = (int) (current * 100 / count);
23 publishProgress(progress);
24 }
25 });
26 } else {
27 bitmap = processBitmap(dataString, displayConfig, null);
28 }
29 }
30
31 if (bitmap != null) {
32 mImageCache.addToMemoryCache(dataString, bitmap);
33 }
34 return bitmap;
35 }
36
37 @Override
38 protected void onProgressUpdate(Integer... values) {
39 int progress = values[0];
40 final View[] imageViews = getAttachedImageView();
41 for (View imageView : imageViews) {
42 if (imageView instanceof ImageView) {
43 Drawable drawable = ((ImageView) imageView).getDrawable();
44 if (drawable instanceof AsyncDrawable) {
45 ((AsyncDrawable) drawable).setProgress(progress);
46 }
47 }
48 }
49 }
50 }
以上主要是看onProgressUpdate的更新方法。
那么还要修改http请求,使得加载图片有进度的显示
修改如下类:
1 net.tsz.afinal.bitmap.download.SimpleDownloader
1 private byte[] getFromHttp(String urlString, ProgressCallBack callBack) {
2 HttpURLConnection urlConnection = null;
3 BufferedOutputStream out = null;
4 FlushedInputStream in = null;
5
6 try {
7 final URL url = new URL(urlString);
8 urlConnection = (HttpURLConnection) url.openConnection();
9 in = new FlushedInputStream(new BufferedInputStream(urlConnection.getInputStream(), IO_BUFFER_SIZE));
10 ByteArrayOutputStream baos = new ByteArrayOutputStream();
11 int b;
12 if (callBack == null) {
13 while ((b = in.read()) != -1) {
14 baos.write(b);
15 }
16 } else {
17 int len = urlConnection.getContentLength();
18 if (len == 0) {
19 return null;
20 }
21 final int progressSize;
22 if (len < PEOGRESS_SIZE * 5) {
23 progressSize = len / 5;
24 } else {
25 progressSize = PEOGRESS_SIZE;
26 }
27 long current = 0;
28 callBack.callBack(len, current);
29 int callLen = 0;
30 while ((b = in.read()) != -1) {
31 baos.write(b);
32 callLen++;
33 if (current == len || callLen > progressSize) {
34 // SystemClock.sleep(500);
35 current += callLen;
36 callBack.callBack(len, current);
37 callLen = 0;
38 }
39 }
40 }
41 return baos.toByteArray();
42 } catch (final IOException e) {
43 Log.e(TAG, "Error in downloadBitmap - " + urlString + " : " + e);
44 } finally {
45 if (urlConnection != null) {
46 urlConnection.disconnect();
47 }
48 try {
49 if (out != null) {
50 out.close();
51 }
52 if (in != null) {
53 in.close();
54 }
55 } catch (final IOException e) {
56 }
57 }
58 return null;
59 }
3、同一个链接,避免多次http请求
doDisplay方法中:
修改如下,主要是封装了一个createAsyncDrawable方法
1 if (bitmap != null) {
2 if (imageView instanceof ImageView) {
3 ((ImageView) imageView).setImageBitmap(bitmap);
4 } else {
5 imageView.setBackgroundDrawable(new BitmapDrawable(bitmap));
6 }
7 }
8 else {
9 createAsyncDrawable(imageView, uri, displayConfig);
10 }
主要实现方式是:维持一个对AsyncDrawable对象的集合的缓存引用:mAsyncDrawablesCache
1 private AsyncDrawable createAsyncDrawable(View imageView, String uri, BitmapDisplayConfig config) {
2 AsyncDrawable asyncDrawable = mAsyncDrawablesCache.get(uri);
3 if (asyncDrawable != null) {
4 setImageDrawable(imageView, asyncDrawable);
5 BitmapLoadAndDisplayTask task = asyncDrawable.getBitmapWorkerTask();
6 task.putImageView(imageView);
7 Log.i("setImage", "putImageView,imageView,url=" + task + "," + imageView + "," + uri);
8 return asyncDrawable;
9 }
10 BitmapLoadAndDisplayTask task = new BitmapLoadAndDisplayTask(imageView, config);
11 Log.i("setImage", "BitmapLoadAndDisplayTask,imageView,url=" + task + "," + imageView + "," + uri);
12 Bitmap bitmap = config.getLoadingBitmap();
13 asyncDrawable = bitmap == null ? new AsyncColorDrawable(imageView.getContext(), task, config.getLoadingRadius()) : new AsyncBitmapDrawable(
14 imageView.getContext(), task, bitmap);
15 asyncDrawable.roundProgressColor = config.getLoadingColor();
16 setImageDrawable(imageView, asyncDrawable);
17 mAsyncDrawablesCache.put(uri, asyncDrawable);
18 task.executeOnExecutor(bitmapLoadAndDisplayExecutor, uri);
19 return asyncDrawable;
20 }
1 private static final SoftMemoryCache<AsyncDrawable> mAsyncDrawablesCache = new SoftMemoryCache<AsyncDrawable>();
BitmapLoadAndDisplayTask 中又维持一个View的列表引用:
1 private class BitmapLoadAndDisplayTask extends AsyncTask<Object, Integer, Bitmap> {
2 private String dataString;
3 private ArrayList<WeakReference<View>> imageViewReferences = new ArrayList<WeakReference<View>>();
4 private final BitmapDisplayConfig displayConfig;
5
6 public BitmapLoadAndDisplayTask(View imageView, BitmapDisplayConfig config) {
7 // imageViewReference = new WeakReference<View>(imageView);
8 imageViewReferences.add(new WeakReference<View>(imageView));
9 displayConfig = config;
10 }
11
12 public void putImageView(View imageView) {
13 imageViewReferences.add(new WeakReference<View>(imageView));
14 }
15 //省略...
16 @Override
17 protected void onProgressUpdate(Integer... values) {
18 int progress = values[0];
19 final View[] imageViews = getAttachedImageView();
20 for (View imageView : imageViews) {
21 if (imageView instanceof ImageView) {
22 Drawable drawable = ((ImageView) imageView).getDrawable();
23 if (drawable instanceof AsyncDrawable) {
24 ((AsyncDrawable) drawable).setProgress(progress);
25 }
26 }
27 }
28 }
29
30 @Override
31 protected void onPostExecute(Bitmap bitmap) {
32 mAsyncDrawablesCache.remove(dataString);
33 if (isCancelled() || mExitTasksEarly) {
34 bitmap = null;
35 }
36 // 判断线程和当前的imageview是否是匹配
37
38 Log.i("setImage", "onPostExecute");
39 // final View imageView = getAttachedImageView();
40
41 final View[] imageViews = getAttachedImageView();
42 for (View imageView : imageViews) {
43 if (bitmap != null && imageView != null) {
44 mConfig.displayer.loadCompletedisplay(imageView, bitmap, displayConfig);
45 } else if (bitmap == null && imageView != null) {
46 mConfig.displayer.loadFailDisplay(imageView, displayConfig.getLoadfailBitmap());
47 }
48 }
49 }
50
51 // 获取线程匹配的imageView,防止出现闪动的现象
52 private View[] getAttachedImageView() {
53 View[] views = new View[imageViewReferences.size()];
54 int i = 0;
55 for (WeakReference<View> imageViewReference : imageViewReferences) {
56 final View imageView = imageViewReference.get();
57 if (imageView != null) {
58 final BitmapLoadAndDisplayTask bitmapWorkerTask = getBitmapTaskFromImageView(imageView);
59 Log.i("setImage", "getAttachedImageView,imageView,url=" + this + "," + imageView + "," + dataString);
60 if (this == bitmapWorkerTask) {
61 views[i++] = imageView;
62 }
63 }
64 }
65 return views;
66 }
67 }
4、三级缓存
哪三级缓存:
- 根据url和图片大小,构造key,获取内存中的bitmap;如果为空,则 2;
- 根据 1 中构造的key,获取磁盘中的bitmap data缓存;如果为空,则 3;
- 根据url,获取磁盘中的bitmap data缓存;如果不为空,则 4 ;如果为空则加载http 图片,如 5 ;
- 根据加载的bitmap data,裁剪成需要的bitmap大小,并且添加进磁盘和内存缓存;
- 根据url进行http请求,返回bitmap data,把bitmap data储存进磁盘缓存,并且裁剪成需要的大小的bitmap data,然后分别添加进磁盘缓存和bitmap缓存。
修改如下类:
1 net.tsz.afinal.bitmap.core.BitmapProcess
主要方法:http请求成功之后:调用mCache.addToDiskCache()
1 public Bitmap getBitmap(String url, BitmapDisplayConfig config, ProgressCallBack callBack) {
2
3 Bitmap bitmap = getFromDisk(url, config);
4
5 if (bitmap == null) {
6 byte[] data = mDownloader.download(url, callBack);
7 if (data != null && data.length > 0) {
8 mCache.addToDiskCache(url, data);
9 if (config != null)
10 bitmap = BitmapDecoder.decodeSampledBitmapFromByteArray(data, 0, data.length, config.getBitmapWidth(), config.getBitmapHeight());
11 else
12 bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
13 }
14 }
15 return bitmap;
16 }
主要方法:从磁盘缓存加载url对应的图片之后,进行裁剪,调用:BitmapDecoder.decodeSampledBitmapFromByteArray()方法:
1 public Bitmap getFromDisk(String key, BitmapDisplayConfig config) {
2 BytesBuffer buffer = sMicroThumbBufferPool.get();
3 Bitmap b = null;
4 try {
5 boolean found = mCache.getImageData(key, buffer);
6 if (found && buffer.length - buffer.offset > 0) {
7 if (config != null) {
8 b = BitmapDecoder.decodeSampledBitmapFromByteArray(buffer.data, buffer.offset, buffer.length, config.getBitmapWidth(),
9 config.getBitmapHeight());
10 } else {
11 b = BitmapFactory.decodeByteArray(buffer.data, buffer.offset, buffer.length);
12 }
13 }
14 } finally {
15 sMicroThumbBufferPool.recycle(buffer);
16 }
17 return b;
18 }
在以下内部类进行修改:
1 net.tsz.afinal.FinalBitmap.BitmapLoadAndDisplayTask
主要方法:把裁剪后的图片添加到内存缓存:
1 @Override
2 protected Bitmap doInBackground(Object... params) {
3 dataString = (String) params[0];
4 Bitmap bitmap = null;
5
6 synchronized (mPauseWorkLock) {
7 while (mPauseWork && !isCancelled()) {
8 try {
9 mPauseWorkLock.wait();
10 } catch (InterruptedException e) {
11 }
12 }
13 }
14 if (bitmap == null && !isCancelled() && !mExitTasksEarly) {
15 if (displayConfig.getLoading()) {
16 bitmap = processBitmap(dataString, displayConfig, new ProgressCallBack() {
17 @Override
18 public void callBack(long count, long current) {
19 int progress = (int) (current * 100 / count);
20 publishProgress(progress);
21 }
22 });
23 } else {
24 bitmap = processBitmap(dataString, displayConfig, null);
25 }
26 }
27
28 if (bitmap != null) {
29 mImageCache.addToMemoryCache(dataString, bitmap);
30 }
31 return bitmap;
32 }