主要3个类:
BitmapRequest:网络图片请求类,()对应于图中的请求1、2、3、4……)包含各种请求参数,如:url,预加载图片等。
RequsetDispatcher:请求分发类,是个线程,(对应于图中的消费窗口),负责请求的处理。在缓存中寻找是否之前把图片保存到缓存中,如果没有直接请求网络下载图片。
RequsetManager:请求管理类,负责对请求类和请求分发类进行管理,负责生成队列,添加请求入队列,生成若干个请求分发线程对请求进行处理。
基本原理,请求管理类会产生一个请求队列对象,LinkedBlockQueue,然后通过new 生成若干个请求分发线程并启动(数量自己定,不大于应用的最大线程数),然后将请求队列对象通过构造方法传给每个线程。每次请求下载图片时,都会生成一个BitmapRequset对象,这个对象设置好各种参数,然后将这个对象放入请求队列中。这样一来,每个线程其实都持有同一个请求队列对象,并通过请求队列对象take方法获取请求并处理。
BitmapRequest:
public class BitmapRequest {
//图片标识
private String urlMD5;
public String getUrlMD5() {
return urlMD5;
}
public void setUrlMD5(String urlMD5) {
this.urlMD5 = urlMD5;
}
private Context context;
//占位图片
private int resId;
//设置图片的ImageView
private SoftReference<ImageView> imageView;
//请求监听
private RequestListener requestListener;
//请求图片地址
private String url;
public BitmapRequest(Context context){
this.context = context;
}
public BitmapRequest load(String url){
this.url = url;
this.urlMD5 = MD5Util.toMD5(url);
return this;
}
public BitmapRequest loading(int resId){
this.resId = resId;
return this;
}
public BitmapRequest listener(RequestListener listener){
this.requestListener = listener;
return this;
}
public void into(ImageView imageView){
imageView.setTag(this.urlMD5);
this.imageView = new SoftReference<>(imageView);
RequestManager.getInstance().addBitmapRequest(this);
}
public int getResId() {
return resId;
}
public ImageView getImageView() {
return imageView.get();
}
public RequestListener getRequestListener() {
return requestListener;
}
public String getUrl() {
return url;
}
}
其中的load、loading等方法都是设置参数的意思,这样的写法可以达到链式代码的效果。
RequsetDispatcher:
public class RequestDispatcher extends Thread{
private Handler handler = new Handler(Looper.getMainLooper());
private LinkedBlockingQueue<BitmapRequest> linkedBlockingQueue;
public RequestDispatcher(LinkedBlockingQueue<BitmapRequest> linkedBlockingDeque){
this.linkedBlockingQueue = linkedBlockingDeque;
}
@Override
public void run() {
super.run();
while (!isInterrupted()){
try {
//从队列中获取图片请求
BitmapRequest request = linkedBlockingQueue.take();
//显示占位图片
showLoadingImage(request);
//加载图片
Bitmap bitmap = findBitmap(request);
//将图片显示到ImageView
showImageView(request,bitmap);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void showLoadingImage(BitmapRequest request) {
if(request.getResId() > 0 && request.getImageView() != null){
final int resId = request.getResId();
final ImageView imageView = request.getImageView();
handler.post(new Runnable() {
@Override
public void run() {
imageView.setImageResource(resId);
}
});
}
}
private Bitmap findBitmap(BitmapRequest request) {
Bitmap bitmap;
bitmap = DoubleLruCache.getInstance().get(request);
if(bitmap == null){
bitmap = downloadBitmap(request.getUrl());
MemoryLruCache.getInstance().put(request,bitmap);
DiskBitmapCache.getInstance().put(request,bitmap);
}
return bitmap;
}
public Bitmap downloadBitmap(String uri){
InputStream inputStream = null;
Bitmap bitmap = null;
try {
URL url = new URL(uri);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
inputStream = connection.getInputStream();
bitmap = BitmapFactory.decodeStream(inputStream);
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if(inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return bitmap;
}
private void showImageView(final BitmapRequest request, final Bitmap bitmap) {
if(request.getImageView() != null && bitmap != null && request.getUrlMD5().equals(request.getImageView().getTag())){
final ImageView imageView = request.getImageView();
handler.post(new Runnable() {
@Override
public void run() {
imageView.setImageBitmap(bitmap);
//设置监听器
if(request.getRequestListener() != null){
RequestListener listener = request.getRequestListener();
listener.onSuccess(bitmap);
}
}
});
}
}
}
RequestManager:
public class RequestManager {
private static final String TAG = "RequestManager";
private LinkedBlockingQueue<BitmapRequest> linkedBlockingQueue = new LinkedBlockingQueue<>();
private static RequestManager requestManager;
private RequestDispatcher[] requestDispatchers;
public RequestManager(){
start();
}
public static RequestManager getInstance(){
if(requestManager == null){
requestManager = new RequestManager();
}
return requestManager;
}
public void addBitmapRequest(BitmapRequest request){
if(request != null && !linkedBlockingQueue.contains(request)){
linkedBlockingQueue.add(request);
Log.d(TAG, "addBitmapRequest: ");
}
}
private void start() {
stop();
startAllDispatcher();
}
private void stop() {
if(requestDispatchers != null && requestDispatchers.length > 0){
for (RequestDispatcher requestDispatcher : requestDispatchers){
if(!requestDispatcher.isInterrupted()){
requestDispatcher.interrupt();
}
}
}
}
private void startAllDispatcher() {
int threadCount = Runtime.getRuntime().availableProcessors();
requestDispatchers = new RequestDispatcher[threadCount];
Log.d(TAG, "startAllDispatcher: " + threadCount);
for (int i = 0; i < threadCount; i++) {
RequestDispatcher requestDispatcher = new RequestDispatcher(linkedBlockingQueue);
requestDispatcher.start();
requestDispatchers[i] = requestDispatcher;
}
}
}
图片缓存:原理很简单,为了避免重复下载,要下载图片时,先从内存缓存中寻找是否有保存,如果没有,那么从硬盘缓冲中寻找,还是没有才会通过网络请求下载图片,并保存到缓存中。
具体细节可以参考:https://github.com/lyx19970504/SimpleBitmapRequest