网络请求框架封装(NetWorkUtils)

逃离我推掉我的手 2022-05-21 03:27 342阅读 0赞

效果图:

NetWorkUtils.gif

项目描述:

网络请求框架二次封装,目前完成了基于OkHttp的get/post/postJson/uploadFile/downloadFile等功能开发,支持扩展,底层实现可自由切换;
  • 扩展请继承ExecutorFactory实现具体的IExecutor即可,底层可以是OkHttp,也可以是HttpClient或者URLConnection;

使用方式:

  1. public class MyApplication extends Application {
  2. @Override
  3. public void onCreate() {
  4. super.onCreate();
  5. //在程序入口进行工厂初始化,默认的为okhttp的实现工厂
  6. NetWorkUtils.init(new OkHttpExecutorFactory());
  7. }
  8. }
  9. //get方式请求
  10. private void doGet() {
  11. String url = "http://127.0.0.1:8080/test/test";
  12. RequestParams params = new RequestParams.Builder().url(url).method(Method.GET).params("key1", "hello").params("key2", "doGet").tag(this).build();
  13. NetWorkUtils.getInstance().doStart(params, callback);
  14. }
  15. //post方式请求
  16. private void doPost() {
  17. String url = "http://127.0.0.1:8080/test/test";
  18. RequestParams params = new RequestParams.Builder().url(url).method(Method.POST).params("key1", "hello").params("key2", "doPost").tag(this).build();
  19. NetWorkUtils.getInstance().doStart(params, callback);
  20. }
  21. //postJson方式请求
  22. private void doPostJson() {
  23. String url = "http://127.0.0.1:8080/test/test";
  24. String body = "{ \"key1\":\"hello\",\"key2\":\"doPostJson\" }";
  25. RequestParams params = new RequestParams.Builder().url(url).method(Method.POST_JSON).body(body).tag(this).build();
  26. NetWorkUtils.getInstance().doStart(params, callback);
  27. }
  28. //文件上传
  29. private void doUploadFile() {
  30. String url = "http://127.0.0.1:8080/test/upload";
  31. String filePath = Environment.getExternalStorageDirectory().getPath() + File.separator + "atlas-master.zip";
  32. RequestParams params = new RequestParams.Builder().url(url).method(Method.UPLOAD).files("fileKey", new File(filePath)).tag(this).build();
  33. NetWorkUtils.getInstance().doStart(params, callback);
  34. }
  35. //文件下载
  36. private void doDownload() {
  37. String url = "http://127.0.0.1:8080/test/download";
  38. String filePath = Environment.getExternalStorageDirectory().getPath() + File.separator + "atlas-master.zip";
  39. RequestParams params = new RequestParams.Builder().url(url).method(Method.DOWNLOAD).downLoadFilePath(filePath).tag(this).build();
  40. NetWorkUtils.getInstance().doStart(params, callback);
  41. }
  42. //请求回调,主线程中进行
  43. private ICallBack callback = new ICallBack() {
  44. @Override
  45. public void onStart() {
  46. Log.d(NetWorkUtils.class.getSimpleName(), "网络开始加载");
  47. }
  48. @Override
  49. public void onComplite() {
  50. Log.d(NetWorkUtils.class.getSimpleName(), "网络加载完成");
  51. }
  52. @Override
  53. public void onError(Exception e) {
  54. Log.d(NetWorkUtils.class.getSimpleName(), "出现错误");
  55. }
  56. @Override
  57. public void onSuccess(Object tag, String result) {
  58. Log.d(NetWorkUtils.class.getSimpleName(), "result = "+result);
  59. /**
  60. * 可以根据不同的tag来解析数据
  61. * if(tag.equest("doGet")){
  62. *
  63. * }else if(tag.equest("doPost")){
  64. *
  65. * }
  66. * ............
  67. */
  68. }
  69. @Override
  70. public void onProgress(float progress) {
  71. Log.d(NetWorkUtils.class.getSimpleName(), "上传或下载进度 : "+progress);
  72. }
  73. };
  74. //支持根据tag来取消具体的网络请求
  75. protected void onDestroy() {
  76. NetWorkUtils.getInstance().cancleRequest(this);
  77. super.onDestroy();
  78. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94

技术要点:

  • 抽象工厂模式
  • 构建者模式
  • OkHttp使用
  • OkHttp上传与下载的进度监听
  • 线程回调

背景介绍:

网络请求在app开发中占据很重要的角色,也算是核心技术要点之一。github上也有很多著名的开源库,如Xutils,AsyncHttpClient,Okhttp等等。我相信很多人如同我一样,习惯性的拿这些开源的加入到自己的项目中,但当有一天,因为某些原因我们需要对网络层进行一次切换,那么是不是问题就变的严重了,我们需要改大量的代码来满足这次更改。为了避免这样的问题发生,我们需要对网络层进行二次包装一下;

项目结构:

image.png

  • IExecutor 网络请求接口类,定义了get/post/postJson/uploadFile/downloadFile等;
  • ExecutorFactory IExecutor的创建工厂,抽象类;
  • OkHttpExecutor 实现了IExecutor的接口,实现了具体的get/post/postJson/uploadFile/downloadFile等方法;
  • OkHttpExecutorFactory 实现了ExecutorFactory,并返回了OkHttpExecutor实例;
  • MainHandler UI线程回调;
  • RequestParams 请求参数,采用构建者模式;
  • NetWorkUtils 网络请求工具类,单利,全局唯一 ;
注意:默认的okhttp enqueue(call)后,是回调在子线成中的;

执行流程,代码分析:

  • NetWorkUtils.init(new OkHttpExecutorFactory()) 后发生了什么?

    1. public static IExecutor executor;
    2. public static NetWorkUtils mInstance;
    3. private NetWorkUtils(ExecutorFactory factory) {
    4. executor = factory.create();
    5. }
    6. /**
    7. * init networkutils
    8. * 设置底层使用哪种网络实现,目前只实现了OkHttpExecutorFactory,如果想扩展的话请继承ExecutorFactory自行实现
    9. * @param factory
    10. */
    11. public static void init(ExecutorFactory factory) {
    12. if (mInstance == null) {
    13. synchronized (NetWorkUtils.class) {
    14. if (mInstance == null) {
    15. mInstance = new NetWorkUtils(factory);
    16. }
    17. }
    18. }
    19. }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    我们看到进行了NetWorkUtils单利的初始化,并通过工厂获取到了IExecutor的具体实现类;
  • OkHttpExecutorFactory继承自ExecutorFactory,并实现了create抽象方法:

    1. public class OkHttpExecutorFactory extends ExecutorFactory {
    2. @Override
    3. public IExecutor create() {
    4. HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
    5. @Override
    6. public void log(String message) {
    7. Log.d(NetWorkUtils.class.getSimpleName(), message);
    8. }
    9. });
    10. //建造者模式,生成配置对象
    11. OkhttpConfig config = new OkhttpConfig.Builder().retryOnConnectionFailure(false).connectTimeout(10000).readTimeout(5000).writeTimeout(5000).interceptors(httpLoggingInterceptor).build();
    12. return new OkHttpExecutor(config);
    13. }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    通过OkhttpConfig构建者创建了OkHttpExecutor 并返回;
  • OkHttpExecutor实现了IExecutor接口并实现了接口中所有的方法,所以这个才是具体的网络请求实现:

    1. public static OkHttpClient mClient;
    2. public static final Map<Object, ArrayList<Call>> calls = new HashMap<>();
    3. public OkHttpExecutor(OkhttpConfig config) {
    4. //配置okhttpclient,全局唯一
    5. OkHttpClient.Builder builder = new OkHttpClient.Builder().retryOnConnectionFailure(config.retryOnConnectionFailure).connectTimeout(config.connectTimeout, TimeUnit.MILLISECONDS)
    6. .readTimeout(config.readTimeout, TimeUnit.MILLISECONDS).writeTimeout(config.writeTimeout, TimeUnit.MILLISECONDS);
    7. if (config.cache != null) {
    8. builder.cache(config.cache);
    9. }
    10. if (config.x509TrustManager != null && config.sslSocketFactory != null) {
    11. builder.sslSocketFactory(config.sslSocketFactory, config.x509TrustManager);
    12. }
    13. if (config.interceptors != null && config.interceptors.size() > 0) {
    14. for (int i = 0; i < config.interceptors.size(); i++) {
    15. builder.addInterceptor(config.interceptors.get(i));
    16. }
    17. }
    18. if (config.networkInterceptors != null && config.networkInterceptors.size() > 0) {
    19. for (int i = 0; i < config.networkInterceptors.size(); i++) {
    20. builder.addNetworkInterceptor(config.networkInterceptors.get(i));
    21. }
    22. }
    23. mClient = builder.build();
    24. }
    25. @Override
    26. public void doGet(RequestParams requestParams, ICallBack callback) {
    27. callback.onStart();
    28. Request request = new Request.Builder().url(OkhttpUtils.getUrlWithParams(requestParams)).get().headers(OkhttpUtils.getHeaders(requestParams)).tag(requestParams.tag).build();
    29. Call call = mClient.newCall(request);
    30. call.enqueue(new OkhttpCallback(requestParams));
    31. cacheCall(requestParams, call);
    32. }
    33. @Override
    34. public void doPost(RequestParams requestParams, ICallBack callback) {
    35. callback.onStart();
    36. Request request = new Request.Builder().url(requestParams.url).post(OkhttpUtils.getPostBody(requestParams)).headers(OkhttpUtils.getHeaders(requestParams)).tag(requestParams.tag).build();
    37. Call call = mClient.newCall(request);
    38. call.enqueue(new OkhttpCallback(requestParams));
    39. cacheCall(requestParams, call);
    40. }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    部分代码,具体的请查看源码;
    在构造器中,我们通过OkhttpConfig实例化了一个OkHttpClient,并在doGet,doPost中使用OkHttpClient进行具体的网络请求,如果对okhttp不熟悉的同学,可以百度先学习下okhttp;
    注意,ICallBack是我们自定义的callback,因为前面我提到过okhttp的回调是在子线成中进行的,所以我们有必要把它变为UI线程回调;
    OkhttpCallback这个是我们继承自okhttp的Callback,然后在里面进行UI线程的切换,最后在回调到我们自己的ICallBack的;
  • OkhttpCallback 继承自okhttp的Callback:

    1. public class OkhttpCallback implements Callback {
    2. public static final Handler handler = new MainHandler(Looper.getMainLooper());
    3. RequestParams requestParams;
    4. public OkhttpCallback(RequestParams requestParams) {
    5. this.requestParams = requestParams;
    6. }
    7. @Override
    8. public void onFailure(Call call, IOException e) {
    9. e.printStackTrace();
    10. TempleteBean templeteBean = new TempleteBean();
    11. templeteBean.call = call;
    12. templeteBean.e = e;
    13. templeteBean.requestParams = requestParams;
    14. Message.obtain(handler, MainHandler.FAILD, templeteBean).sendToTarget();
    15. }
    16. @Override
    17. public void onResponse(Call call, Response response) throws IOException {
    18. TempleteBean templeteBean = new TempleteBean();
    19. templeteBean.call = call;
    20. templeteBean.response = response;
    21. templeteBean.requestParams = requestParams;
    22. //downloadfile
    23. if (requestParams.method.equals(Method.DOWNLOAD)) {
    24. downLoadFile(templeteBean, response);
    25. }
    26. Message.obtain(handler, MainHandler.SUCCESS, templeteBean).sendToTarget();
    27. }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    我们使用了TempleteBean进行数据的封装,并通过MainHandler发送到了UI线程中;
    new MainHandler(Looper.getMainLooper()) 传入UI线程的looper即可回调在UI线程中;
  • MainHandler 继承自安卓系统中的Handler:

    1. public class MainHandler extends Handler {
    2. public static final int SUCCESS = 101;
    3. public static final int FAILD = 102;
    4. public static final int PROGRESS = 103;
    5. public MainHandler(Looper looper) {
    6. super(looper);
    7. }
    8. @Override
    9. public void handleMessage(Message msg) {
    10. switch (msg.what) {
    11. case SUCCESS:
    12. onSuccess(msg);
    13. break;
    14. case FAILD:
    15. onFaild(msg);
    16. break;
    17. case PROGRESS:
    18. onProgress(msg);
    19. break;
    20. }
    21. }
    22. private void onSuccess(Message msg) {
    23. TempleteBean bean = (TempleteBean) msg.obj;
    24. RequestParams requestParams = bean.requestParams;
    25. ICallBack callback = requestParams.callback;
    26. Response response = bean.response;
    27. if (!response.isSuccessful()) {
    28. Log.d(NetWorkUtils.class.getSimpleName(), "!response.isSuccessful()" +response.code());
    29. return;
    30. }
    31. if (requestParams.method.equals(Method.DOWNLOAD)) {
    32. callback.onSuccess(requestParams.tag, requestParams.downLoadFilePath);
    33. callback.onComplite();
    34. return;
    35. }
    36. try {
    37. String result = response.body().string();
    38. Log.d(NetWorkUtils.class.getSimpleName(), result);
    39. callback.onSuccess(requestParams.tag, result);
    40. } catch (Exception e) {
    41. e.printStackTrace();
    42. callback.onError(e);
    43. }
    44. callback.onComplite();
    45. }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    执行结果最终会进入到这个handler中,而这个handler是UI线程的,所以我们通过TempleteBean 获取到数据,在将结果回调到我们自己定义地的callback中;
    至此,整个请求流程就完成了,然后我们回头看下NetWorkUtils;
  • NetWorkUtils 请求工具类,也是单利的,全局唯一的,我们在程序入口init的时候进行了单利的初始化:

    1. public void doStart(RequestParams params, ICallBack callBack) {
    2. if (params == null || callBack == null) return;
    3. params.callback = callBack;
    4. switch (params.method) {
    5. case GET:
    6. executor.doGet(params, callBack);
    7. break;
    8. case POST:
    9. executor.doPost(params, callBack);
    10. break;
    11. case POST_JSON:
    12. executor.doPostJson(params, callBack);
    13. break;
    14. case UPLOAD:
    15. executor.doUploadFile(params, callBack);
    16. break;
    17. case DOWNLOAD:
    18. executor.doDownLoad(params, callBack);
    19. break;
    20. }
    21. }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    我们NetWorkUtils.getInstance().doStart(params,callback)即可发起网络请求;

发表评论

表情:
评论列表 (有 0 条评论,342人围观)

还没有评论,来说两句吧...

相关阅读