Android 图片请求框架原理(手写请求框架)

在这里插入图片描述主要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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: Spring Framework是一个开源的Java平台,它提供了一组全面的工具来支持Java应用程序开发。它主要包括IoC容器、AOP框架、事务管理、MVC框架、DAO框架、连接池等。它可以帮助程序员更好地组织代码,减少重复性工作,提高代码质量。手写Spring框架需要对Java编程和设计模式有较深的了解,并对Spring框架的源码有着深入的研究。 ### 回答2: Spring框架是一个开源的Java平台,用于构建企业级应用程序。它提供了一种全面的编程和配置模型,用于开发基于Java的应用程序和服务。手写Spring框架意味着从头开始实现Spring的核心功能。 手写Spring框架的基本步骤包括: 1. 创建一个核心容器类,用于管理应用程序中的Bean对象。这个容器类需要提供注册、获取和销毁Bean的功能。 2. 定义一个Bean注解,用于标识哪些类应该被容器所管理。 3. 创建一个Bean定义类,用于存储每个Bean的元数据信息,包括类名、作用域和依赖关系等。 4. 实现依赖注入功能,通过读取Bean定义中的依赖关系,将相关的Bean对象注入到目标Bean中。 5. 提供AOP(面向切面编程)功能,允许开发者在应用程序的特定点进行横切关注点的处理。 6. 实现声明式事务管理功能,使用注解或XML配置方式来处理数据库事务。 7. 提供对不同数据访问技术(如JDBC、ORM框架、NoSQL等)的支持,通过集成相应的库来简化数据访问代码。 8. 增加对Web开发的支持,如处理请求、渲染视图等。 手写Spring框架需要具备对Java语言的深入了解,熟悉反射、代理、设计模式等概念和技术。还需要对依赖注入、AOP、事务管理、Web开发等方面有一定的理解。实现一个完整的Spring框架是一个庞大而复杂的任务,需要经过反复的设计、开发和测试。通过手写Spring框架,可以更深入地理解Spring的原理和内部机制,提高对框架的使用和调试能力。 ### 回答3: 手写Spring框架是一个相当复杂的任务,但我可以简要介绍手写Spring框架的一些关键步骤和组成部分。 1. 依赖注入:Spring框架的核心概念之一是依赖注入。我们需要编写一个容器,负责管理和维护各个对象之间的依赖关系。可以使用反射机制来实现依赖注入。 2. 控制反转:Spring框架通过控制反转(IoC)来管理对象的创建和生命周期。我们需要编写一个BeanFactory,负责加载和实例化对象,并将依赖注入到相应的对象中。 3. 配置文件:手写Spring框架也需要一个配置文件,用于定义对象的依赖关系和属性。我们可以使用XML、注解或者JavaConfig等方式来定义配置文件。 4. AOP支持:Spring框架提供了面向切面编程(AOP)的支持,可以通过编写切面和通知来实现横切关注点的统一处理。我们需要实现一个AOP框架,用于拦截和处理切面逻辑。 5. MVC模式:Spring框架也提供了一个MVC框架,用于处理Web应用程序的请求和响应。我们需要编写一个DispatcherServlet,负责将请求分发给相应的控制器,并处理模型和视图的交互。 6. 整合其他技术:Spring框架还可以与其他技术进行整合,例如数据库访问、事务管理、安全性控制等。我们需要编写相应的模块,将这些技术与Spring框架集成起来。 虽然这只是一个简要的介绍,手写Spring框架是一个非常庞大的工程,需要深入理解Spring的原理和设计思想,并具备扎实的Java编程能力。但通过手写Spring框架,我们可以更好地掌握Spring的核心概念和原理,并加深对框架的理解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哒哒呵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值