zoukankan      html  css  js  c++  java
  • XDroidRequest网络请求框架,新开源

    XDroidRequest 是一款网络请求框架,它的功能也许会适合你。这是本项目的第三版了,前两版由于扩展性问题一直不满意,思考来 思考去还是觉得Google的Volley的扩展性最强,于是借鉴了Volley的责任链模式,所以有了这个第三版.

    Provide

    1 适配 Android 6.0 ,不再使用HttpClient相关API
    2 一行代码发送请求,提供多种回调函数供选择,
    3 支持8种网络请求方式 GET,POST,PUT,DELETE,HEAD,OPTIONS,TRACE,PATCH
    4 支持请求的优先级设置,优先级高的将先于优先级低的发送请求
    5 支持取消请求,可以取消当前已发送的请求(可自定义取消请求的依据条件),也可以取消请求队列中还未发送的请求
    6 支持多请求并发,多个请求同时发送,底层使用固定数量线程池,可设置线程池的大小
    7 支持重复请求的判断,当有重复的请求将挂起,等待第一个请求完成后,挂起的请求使用已经请求完毕的缓存,如果未开启缓存,则会继续请求网络
    8 支持请求失败重试,默认重试2次,重试超时时间会递增,递增速率可设置,默认为1倍递增
    9 支持多文件与大文件上传,可以与参数一起发送至服务器,提供上传进度回调
    10 支持大文件下载,提供下载进度回调
    11 支持发送JSON数据
    12 自动网络判定,可设置此时是否显示缓存数据
    13 请求结果自动解析,可泛型任何JAVA BEAN,默认实现了GSON解析,可自定义
    14 多种错误类型判定
    15 扩展性强,可自定义发送请求方式与解析请求结果
    16 支持强大的缓存控制
    17 支持缓存配置,可配置磁盘缓存路径,磁盘缓存最大值,磁盘缓存当前占有大小,磁盘缓存清理
    内存缓存最大值大小,内存缓存清理
    18 支持缓存管理与控制,包括本地请求缓存一系列信息查询以及对缓存的手动操作

    About cache

    1 XDroidRequest使用了二级缓存,内存缓存与磁盘缓存,内存缓存使用LruCache,磁盘缓存使用DiskLruCache
    2 setShouldCache(true) ,一个开关控制是否使用缓存的功能
    3 setUseCacheDataAnyway(false), 是否总是使用缓存,这个开关开启后,将每次首先从内存和本地查找缓存,有的话直接使用缓存,
    请求会在后台执行,完成后会更新缓存。如果没有缓存将直接进行网络请求获取,完成后会更新缓存.
    4 setUseCacheDataWhenRequestFailed(true) ,是否在请求失败后使用缓存数据,无网络属于请求失败,可以保证即使没有网络,或者
    请求也有数据展示.
    5 setUseCacheDataWhenTimeout(true) ,是否在请求超时后直接使用缓存,这里的超时时间并不是网络请求的超时时间,而是我们
    设定一个时间,超过这个时间后,不管请求有没有完成都直接使用缓存,后台的请求完成后会自动更新缓存
    6 setUseCacheDataWhenUnexpired(true),是否使用缓存当缓存未过期的时候,这个开关也是经常开启的开关,每个缓存都会对应一个过期
    时间,先从内存查找缓存,没有的话再从磁盘查找,有缓存且过期的话,将直接使用缓存数据,当过期之后会进行网络请求,请求完成后会更新
    内存缓存与磁盘。没有缓存将直接进行网络请求,请求完成后会更新内存与磁盘缓存
    7 setRetryWhenRequestFailed(true) ,是否进行重试,当请求失败的时候,默认开启,重试2次,不需要重试功能的话可关闭
    8 setNeverExpired(false); 设置缓存是否永不过期 

    Here is the sample

    Download demo.apk

    Screenshot

     

    Usage

    1.初始化,应用启动的时候进行,主要初始化缓存的路径等信息

    XRequest.initXRequest(getApplicationContext());

    2.发起请求

    ① GET请求

    /**
             * 简单的Get请求
             * @param mRequestTag 请求的tag,可根据此tag取消请求
             * @param url 请求地址
             * @param OnRequestListener 请求结果回调
             */
            XRequest.getInstance().sendGet(mRequestTag, url, new OnRequestListenerAdapter<String>() {
                @Override
                public void onDone(Request<?> request, Map<String, String> headers, String result, DataType dataType) {
                    super.onDone(request, headers, result, dataType);
                }
            });

    ② POST请求

    String url = "http://apis.baidu.com/heweather/weather/free";
    RequestParams params = new RequestParams();
    params.putHeaders("apikey", "可以到apistore申请");
    params.putParams("city", "hefei");
    
    XRequest.getInstance().sendPost(mRequestTag, url,  params, new OnRequestListenerAdapter<String>() {
    
        @Override
        public void onRequestFailed(Request<?> request, HttpException httpException) {
            super.onRequestFailed(request, httpException);
            switch (httpException.getHttpErrorCode()) {
            case HttpError.ERROR_NOT_NETWORK:
                Toast.makeText(context, "网络未连接,请检查", Toast.LENGTH_SHORT).show();
                break;
            }
        }
    
        @Override
        public void onRequestRetry(Request<?> request, int currentRetryCount, HttpException previousError) {
            Toast.makeText(context, "获取信息失败,系统已经为您重试" + currentRetryCount+"次", Toast.LENGTH_SHORT).show();
    
            CLog.i("POST请求结果失败,正在重试,当前重试次数:" + currentRetryCount);
        }
    
        @Override
        public void onRequestDownloadProgress(Request<?> request, long transferredBytesSize, long totalSize) {
            CLog.i("onRequestDownloadProgress current:%d , total : %d" ,transferredBytesSize,totalSize);
        }
    
        @Override
        public void onRequestUploadProgress(Request<?> request, long transferredBytesSize, long totalSize, int currentFileIndex,
                File currentFile) {
            CLog.i("onRequestUploadProgress current:%d , total : %d" ,transferredBytesSize,totalSize);
        }
    
        @Override
        public void onDone(Request<?> request, Map<String, String> headers, String result, DataType dataType) {
            super.onDone(request, headers, result, dataType);
        }
    });

    ③ 发送JSON字符串参数

    RequestParams params = new RequestParams();
    params.putParams(
            "{"uid":863548,"stickys":[{"id":29058,"iid":0,"content":"内容","color":"green","createtime":"2015-04-16 16:26:17","updatetime":"2015-04-16 16:26:17"}]}");
    XRequest.getInstance().sendPost(mRequestTag, url, params, new OnRequestListenerAdapter<String>() {
        @Override
        public void onDone(Request<?> request, Map<String, String> headers, String result, DataType dataType) {
            super.onDone(request, headers, result, dataType);
        }
    });

    ④上传文件

    String url = "http://192.168.1.150/upload_multi.php";
    RequestParams params = new RequestParams();
    params.put("file[0]", new File(Environment.getExternalStorageDirectory().getAbsolutePath(), "app-debug.apk"));
    params.put("file[1]", new File(Environment.getExternalStorageDirectory().getAbsolutePath(), "photoview.apk"));
    params.putParams("file_name", "上传的文件名称");
    
    XRequest.getInstance().upload(mRequestTag, url,  params, new OnRequestListenerAdapter<String>() {
    
        @Override
        public void onRequestPrepare(Request<?> request) {
            Toast.makeText(context, "请求准备", Toast.LENGTH_SHORT).show();
            CLog.i("请求准备");
        }
    
        @Override
        public void onRequestFailed(Request<?> request,HttpException httpException) {
            Toast.makeText(context, "请求结果失败", Toast.LENGTH_SHORT).show();
            CLog.i("请求结果失败");
        }
    
        @Override
        public void onRequestRetry(Request<?> request, int currentRetryCount, HttpException previousError) {
            Toast.makeText(context, "获取信息失败,系统已经为您重试" + currentRetryCount+"次", Toast.LENGTH_SHORT).show();
    
            CLog.i("请求结果失败,正在重试,当前重试次数:" + currentRetryCount);
        }
    
        @Override
        public void onRequestUploadProgress(Request<?> request, long transferredBytesSize, long totalSize, int currentFileIndex,
                File currentFile) {
            CLog.i("正在上传第%s个文件,当前进度:%d , 总大小 : %d" ,currentFileIndex,transferredBytesSize,totalSize);
    
            mUploadProgressBar.setMax((int) totalSize);
            mUploadProgressBar.setProgress((int) transferredBytesSize);
        }
        @Override
        public void onDone(Request<?> request, Map<String, String> headers, String response, DataType dataType) {
            Toast.makeText(context, "请求完成", Toast.LENGTH_SHORT).show();
        }
    
    
    });

    测试了上传百兆以上文件无压力,如果你想测试多文件上传,下面的PHP多文件上传代码供参考。要注意的是PHP默认上传2M以内文件,需要自己改下 配置文件,网上很多,搜索即可

    <?php
     foreach($_FILES['file']['error'] as $k=>$v)
     {
        $uploadfile = './upload/'. basename($_FILES['file']['name'][$k]);
        if (move_uploaded_file($_FILES['file']['tmp_name'][$k], $uploadfile)) 
        {
            echo "File : ", $_FILES['file']['name'][$k] ," is valid, and was successfully uploaded.
    ";
        }
    
        else 
        {
            echo "Possible file : ", $_FILES['file']['name'][$k], " upload attack!
    ";
        }   
    
     }
    
     echo "成功接收附加字段:". $_POST['file_name'];
    
    ?>

    ⑤下载文件

    String url = "http://192.168.1.150/upload/xiaokaxiu.apk";
    String downloadPath = "/sdcard/xrequest/download";
    String fileName = "test.apk";
    XRequest.getInstance().download(mRequestTag, url, downloadPath,fileName, new OnRequestListenerAdapter<File>() {
        @Override
        public void onRequestDownloadProgress(Request<?> request, long transferredBytesSize, long totalSize) {
            CLog.i("正在下载, 当前进度:%d , 总大小 : %d" ,transferredBytesSize,totalSize);
            mDownloadProgressBar.setMax((int) totalSize);
            mDownloadProgressBar.setProgress((int) transferredBytesSize);
        }
        @Override
        public void onDone(Request<?> request, Map<String, String> headers, File result, DataType dataType) {
            CLog.i("下载完成 : %s",result != null?result.toString():"获取File为空");
        }
    });

    ⑥关于回调

    请求回调OnRequestListener,回调函数很多,根据自己需求选择性复写即可,传入OnRequestListener默认实现类OnRequestListenerAdapter即可

    XRequest.getInstance().sendGet(mRequestTag, url, cacheKey, params, new OnRequestListener<String>() {
    
                /**
                 * 请求前准备回调
                 * 运行线程:主线程
                 * @param request 当前请求对象
                 */
                @Override
                public void onRequestPrepare(Request<?> request) {
                    Toast.makeText(context, "GET请求准备", Toast.LENGTH_SHORT).show();
    
                    CLog.i("GET请求准备");
                }
    
                /**
                 * 请求完成回调
                 * 运行线程:主线程
                 * @param request 当前请求对象
                 * @param headers 请求结果头文件Map集合
                 * @param result 请求结果泛型对象
                 */
                @Override
                public void onRequestFinish(Request<?> request, Map<String, String> headers, String result) {
                    Toast.makeText(context, "GET请求结果获取成功", Toast.LENGTH_SHORT).show();
                    CLog.i("GET请求结果获取成功");
                }
    
                /**
                 * 请求失败回调
                 * 运行线程:主线程
                 * @param request 当前请求对象
                 * @param httpException 错误类对象,包含错误码与错误描述
                 */
                @Override
                public void onRequestFailed(Request<?> request, HttpException httpException) {
                    Toast.makeText(context, "GET请求结果失败", Toast.LENGTH_SHORT).show();
                    CLog.i("GET请求结果失败");
                }
    
                /**
                 * 请求失败重试回调
                 * 运行线程:主线程
                 * @param request 当前请求对象
                 * @param currentRetryCount 当前重试次数
                 * @param previousError 上一个错误类对象,包含错误码与错误描述
                 */
                @Override
                public void onRequestRetry(Request<?> request, int currentRetryCount, HttpException previousError) {
                    Toast.makeText(context, "获取信息失败,系统已经为您重试" + currentRetryCount+"次", Toast.LENGTH_SHORT).show();
    
                    CLog.i("GET请求结果失败,正在重试,当前重试次数:" + currentRetryCount);
                }
    
                /**
                 * 下载进度回调
                 * 运行线程:子线程
                 * @param request 当前请求对象
                 * @param transferredBytesSize 当前下载大小
                 * @param totalSize 总大小
                 * 
                 */
                @Override
                public void onRequestDownloadProgress(Request<?> request, long transferredBytesSize, long totalSize) {
                    CLog.i("onRequestDownloadProgress current:%d , total : %d" ,transferredBytesSize,totalSize);
                }
    
                /**
                 * 上传进度回调
                 * 运行线程:子线程
                 * @param request 当前请求对象
                 * @param transferredBytesSize 当前写入进度
                 * @param totalSize 总进度
                 * @param currentFileIndex 当前正在上传的是第几个文件
                 * @param currentFile 当前正在上传的文件对象
                 * 
                 */
                @Override
                public void onRequestUploadProgress(Request<?> request, long transferredBytesSize, long totalSize, int currentFileIndex,
                        File currentFile) {
                    CLog.i("onRequestUploadProgress current:%d , total : %d" ,transferredBytesSize,totalSize);
                }
    
                /**
                 * 缓存数据加载完成回调
                 * 运行线程:主线程
                 * @param request 当前请求对象
                 * @param headers 缓存的头信息Map集合
                 * @param result 缓存的数据结果对象
                 */
                @Override
                public void onCacheDataLoadFinish(Request<?> request, Map<String, String> headers, String result) {
                    Toast.makeText(context, "GET请求缓存加载成功", Toast.LENGTH_SHORT).show();
                    CLog.i("GET请求缓存加载成功");
                }
    
                /**
                 * 解析网络数据回调,请求完成后,如果需要做耗时操作(比如写入数据库)可在此回调中进行,不会阻塞UI
                 * 运行线程:子线程
                 * @param request 当前请求对象
                 * @param networkResponse 网络请求结果对象,包含byte数据流与头信息等
                 * @param result 解析byte数据流构建的对象
                 */
                @Override
                public void onParseNetworkResponse(Request<?> request, NetworkResponse networkResponse, String result) {
                    CLog.i("GET请求网络数据解析完成");
                }
    
                /**
                 * 此请求最终完成回调,每次请求只会调用一次,无论此请求走的缓存数据还是网络数据,最后交付的结果走此回调
                 * 运行线程:主线程
                 * @param request 当前请求对象
                 * @param headers 最终交付数据的头信息
                 * @param result 最终交付的请求结果对象
                 * @param dataType 最终交付的数据类型枚举,网络数据/缓存数据
                 */
                @Override
                public void onDone(Request<?> request, Map<String, String> headers, String result, DataType dataType) {
                    Toast.makeText(context, "GET请求完成", Toast.LENGTH_SHORT).show();
                }
    
            });

    下面是选择性复写回调函数

    String url = "http://apis.baidu.com/heweather/weather/free";
            RequestParams params = new RequestParams();
            params.putHeaders("apikey", "可以到apistore申请");
            params.putParams("city", "hefei");
    
            String cacheKey = url + "post";  //与GET请求的URL一样,为了避免同样的缓存key、这里重新指定缓存key
            XRequest.getInstance().sendPost(mRequestTag, url, cacheKey, params, new OnRequestListenerAdapter<String>() {
    
                @Override
                public void onRequestFailed(Request<?> request, HttpException httpException) {
                    super.onRequestFailed(request, httpException);
                    switch (httpException.getHttpErrorCode()) {
                    case HttpError.ERROR_NOT_NETWORK:
                        Toast.makeText(context, "网络未连接,请检查", Toast.LENGTH_SHORT).show();
                        break;
                    }
                }
    
                @Override
                public void onRequestRetry(Request<?> request, int currentRetryCount, HttpException previousError) {
                    Toast.makeText(context, "获取信息失败,系统已经为您重试" + currentRetryCount+"次", Toast.LENGTH_SHORT).show();
    
                    CLog.i("POST请求结果失败,正在重试,当前重试次数:" + currentRetryCount);
                }
    
                @Override
                public void onRequestDownloadProgress(Request<?> request, long transferredBytesSize, long totalSize) {
                    CLog.i("onRequestDownloadProgress current:%d , total : %d" ,transferredBytesSize,totalSize);
                }
    
                @Override
                public void onRequestUploadProgress(Request<?> request, long transferredBytesSize, long totalSize, int currentFileIndex,
                        File currentFile) {
                    CLog.i("onRequestUploadProgress current:%d , total : %d" ,transferredBytesSize,totalSize);
                }
    
                @Override
                public void onDone(Request<?> request, Map<String, String> headers, String result, DataType dataType) {
                    super.onDone(request, headers, result, dataType);
                }
            });
    
        }

    ⑦自动解析

    String url = "http://apis.baidu.com/apistore/aqiservice/citylist";
    RequestParams params = new RequestParams();
    params.putHeaders("apikey", "可以到apistore申请");
    XRequest.getInstance().sendPost(mRequestTag, url, params, CityRootBean.class, new OnRequestListenerAdapter<CityRootBean<CityBean>>() {
    
        @Override
        public void onDone(Request<?> request, Map<String, String> headers, CityRootBean<CityBean> result,
                DataType dataType) {
            CLog.i("Bean信息:" + (result == null ? "null" : result.toString()));
        }
    });

    ⑧缓存配置

    (1)初始化的时候如果想要指定缓存路径,大小等信息,可参照如下代码

    public class App extends Application {
    
        @Override
        public void onCreate() {
            super.onCreate();
    
            configXReqeustCache();
    
        }
    
        @SuppressLint("SdCardPath")
        private void configXReqeustCache() {
            //磁盘缓存路径
            File DISK_CACHE_DIR_PATH = new File("/sdcard/xrequest/diskcache");
            //磁盘缓存最大值
            int DISK_CACHE_MAX_SIZE = 30*1024*1024;
    
            //XRequest.initXRequest(getApplicationContext());
    
            XRequest.initXRequest(getApplicationContext(), DISK_CACHE_MAX_SIZE, DISK_CACHE_DIR_PATH);
        }
    }

    (2)查找当前缓存数据占用的空间

    long diskCacheCurrentSize = RequestCacheManager.getInstance().getAllDiskCacheSize();

    (3)查找缓存路径

    String diskCacheDir = RequestCacheManager.getInstance().getDiskCacheDirectory().getPath();

    (4)查询当前缓存最大值

    long diskCacheMaxSize = RequestCacheManager.getInstance().getDiskCacheMaxSize();

    (5)清除所有缓存

    RequestCacheManager.getInstance().deleteAllDiskCacheData();

    ⑨请求配置

    在发送请求的时候,有的重载函数需要传入一个RequestCacheConfig对象,不需要传入此对象的重载函数内部传入的是默认的 RequestCacheConfig对象,通过RequestCacheConfig对象控制缓存于网络数据等,下面是默认的RequestCacheConfig配置

    public static RequestCacheConfig buildDefaultCacheConfig() {
    RequestCacheConfig cacheConfig=new RequestCacheConfig();
        cacheConfig.setShouldCache(true);  //开启缓存
        cacheConfig.setUseCacheDataAnyway(false);  //关闭总是优先使用缓存
        cacheConfig.setUseCacheDataWhenRequestFailed(true); //开启请求失败使用缓存
        cacheConfig.setUseCacheDataWhenTimeout(false); //关闭超时使用缓存
        cacheConfig.setUseCacheDataWhenUnexpired(true);  //开启当缓存未过期时使用缓存
        cacheConfig.setRetryWhenRequestFailed(true); //开启请求失败重试
        cacheConfig.setNeverExpired(false); //关闭缓存永不过期
    
        TimeController timeController=new TimeController();
        timeController.setExpirationTime(DEFAULT_EXPIRATION_TIME); //设置缓存的过期时间
        timeController.setTimeout(DEFAULT_TIMEOUT); //设置缓存超时时间,对应“setUseCacheDataWhenTimeout”函数的超时时间
        cacheConfig.setTimeController(timeController); //把时间控制器设置给RequestCacheConfig
    
        return cacheConfig;
    }

    每次请求如果需要重新指定配置,自己构造这样一个对象传入即可

    ⑩原始发送请求方式

    XRequest其实是使用装饰者模式,对一系列请求步骤进行了封装,目的是为了更简单的使用,如果有复杂的需求,需要更高的自由度的话, 可以参考如下发送请求代码

    MultipartGsonRequest<Bean> request = new MultipartGsonRequest<T>(cacheConfig, url, cacheKey, Bean.class, onRequestListener);
    request.setRequestParams(params);
    request.setHttpMethod(HttpMethod.POST);
    request.setTag(tag);
    
    XRequest.getInstance().addToRequestQueue(request);
  • 相关阅读:
    CentOS6.8下查看yum及rpm安装后的软件位置
    rabbitmq的web管理界面无法使用guest用户登录
    CentOS6.8搭建rabbitmq消息中间件
    Study 3 —— Python运算符
    CentOS6.x网易163yum源配置
    CentOS6.8下Jenkins+maven+tomcat+git+shell自动构建、部署web应用环境的搭建
    CentOS6.8下安装memcached并设置开机自启动
    CentOS6.8下安装redis并配置开机自启动
    CentOS下查找java环境变量
    CentOS下设置vim的tab键为4格
  • 原文地址:https://www.cnblogs.com/android-blogs/p/5177092.html
Copyright © 2011-2022 走看看