Afinal扩展

| 分类 android  utils  | 标签 Android  学习  Afinal 

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、加载图片时,显示进度

显示如下加载进度:

img

修改如下类:

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、三级缓存

哪三级缓存:

  1. 根据url和图片大小,构造key,获取内存中的bitmap;如果为空,则 2;
  2. 根据 1 中构造的key,获取磁盘中的bitmap data缓存;如果为空,则 3;
  3. 根据url,获取磁盘中的bitmap data缓存;如果不为空,则 4 ;如果为空则加载http 图片,如 5 ;
  4. 根据加载的bitmap data,裁剪成需要的bitmap大小,并且添加进磁盘和内存缓存;
  5. 根据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    }

上一篇     下一篇