Android 网络请求模块

前言

目前的移动流量越来越便宜,手机内存也越来越大。随着Android 手机多年的发展,用户对Android 系统的接受度、认可度越来越高,加之Android 系统的开源性,更多的移动硬件接入Android生态系统,物联网和人工智能的时代来临了,我们进入了一个全新的人工智能时代,万物联网,一切都为智能而生,与此同时,人们对移动终端请求网络的速度和效率要求也越来越苛刻。网络请求的流畅性决定了一款app 产品的用户对产品的依赖度;
目前网路请求处理不当,会造成哪些问题:

  • 请求超时,获取数据缓慢。造成系统流畅性降低;如果-UI界面请求的网路加载进度条一直转圈,超时处理;
  • 耗费网络流量,增加用户的使用成本;比如,从网上下载过大的视频,照片,尤其是在移动网络中使用;
  • 网络的安全性,敏感数据在网络上传递的过程中没有加密或者加密级别太低,秘钥被盗用,数据被黑客拦截,篡改数据包,重新请求;造成用户数据泄露等等;

目前业内常用的网络请求框架:

Volley、async-http、okhttp2、retrofit2;这些框架已经在项目中多次被应用,根据现在近来做的项目,总结一下我自己在工作中用到的网络请求框架,以及平时遇到的问题;
现在的公司使用的是OkHttp3+retrofit2二者结合使用;
首先在build.gradle (Moudle:app) 中引入Okhttp框架包,for example:

compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
compile 'com.squareup.retrofit2:adapter-rxjava:2.3.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.8.1'

整个请求分为三部分: 统一的数据结构(code、msg、data)


以登录请求举例:
LoginService.java
支持多种方式访问网络GET、POST、PUT、DELETE等请求协议
加入基础ApiService,减少Api冗余
支持动态配置和自定义底层框架Okhttpclient、Retrofit.

package com.fintech.cuidaren.retrofit.services;


import com.fintech.cuidaren.base.BaseConfig;
import com.fintech.cuidaren.bean.BeanDictData;
import com.fintech.cuidaren.bean.BeanLogin;
import com.fintech.cuidaren.bean.BeanPass;
import com.fintech.cuidaren.bean.BeanSaveLatitude;
import com.fintech.cuidaren.bean.BeanUpdateData;
import com.fintech.cuidaren.bean.UserLogin;

import java.util.List;

import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Query;
// 提供请求的api
public interface ApiService {

    String BASE_SERVICE = BaseConfig.SERVER_URL;

    @POST("/business-service/api/login/login")
    Call<UserLogin> login(@Body BeanLogin beanLogin);

    //修改密码
    @POST("business-service/api/login/updatePassword")
    Call<String> updatePassword(@Body BeanPass beanPass);

    //获取数据字典所有数据
    @GET("/business-service/api/dataDictController/getAll")
    Call<List<BeanDictData>> getAllDict();

    //发布新版本
    @GET("/common-service/api/appVersionController/publishAppVersion")
    Call<BeanUpdateData> getAppVersion(@Query("os")String os, @Query("version")String version);
}

创建HttpAction 基类;
创建一个OkHttpClient 对象;

package com.fintech.cuidaren.retrofit.services;

import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public abstract class BaseHttpAction {

    OkHttpClient httpClient;

    public BaseHttpAction(OkHttpClient httpClient) {
        this.httpClient = httpClient;
    }

    protected <T> T createService(String url, final Class<T> service) {
        return new Retrofit.Builder().baseUrl(url)
                .addConverterFactory(GsonConverterFactory.create())
                .client(httpClient)
                .build()
                .create(service);
    }
    public OkHttpClient getHttpClient() {
        return httpClient;
    }

}

为每个api 构建一个Action类,并继承BaseHttpAction.java 类;

package com.fintech.cuidaren.retrofit.action;

import com.fintech.cuidaren.bean.BeanDictData;
import com.fintech.cuidaren.bean.BeanLogin;
import com.fintech.cuidaren.bean.BeanPass;
import com.fintech.cuidaren.bean.BeanSaveLatitude;
import com.fintech.cuidaren.bean.BeanUpdateData;
import com.fintech.cuidaren.bean.UserLogin;
import com.fintech.cuidaren.retrofit.services.AbsRemoteAction;
import com.fintech.cuidaren.retrofit.services.AccessTokenInterceptor;
import com.fintech.cuidaren.retrofit.services.LoginService;
import com.fintech.cuidaren.retrofit.services.RetrofitCallback;

import java.util.List;

import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import retrofit2.Call;

public class LoginAction extends BaseHttpAction {


    private final LoginService mloginService;

    public LoginAction(OkHttpClient httpClient) {
        super(httpClient);
        mloginService = (LoginService) createService(LoginService.BASE_SERVICE, LoginService.class);
    }

    private void updateToken(String token) {
        OkHttpClient httpClient = getHttpClient();
        for (Interceptor interceptor : httpClient.interceptors()) {
            if (interceptor instanceof AccessTokenInterceptor) {
                ((AccessTokenInterceptor) interceptor).updateToken(token);
                break;
            }
        }
    }

//请求成功的回调 onSuccess()
// 请求失败的回调 onFailure()

    public void login(BeanLogin beanLogin, final LoginDataListener mLoginDataListener) {
        Call<UserLogin> call = mloginService.login(beanLogin);
        call.enqueue(new RetrofitCallback<UserLogin>() {
            @Override
            public void onSuccess(UserLogin model) {
                mLoginDataListener.loginData(model);
                updateToken(model.getToken());
            }

            @Override
            public void onFailure(int code, String msg) {

            }

            @Override
            public void onThrowable(Throwable t) {

            }
        });
    }

    public interface LoginDataListener {
        void loginData(UserLogin mUserLogin);
    }

    public void GetDictAllData(final getDictDataListener getDictDataListener) {
        Call<List<BeanDictData>> call = mloginService.getAllDict();
        call.enqueue(new RetrofitCallback<List<BeanDictData>>() {
            @Override
            public void onSuccess(List<BeanDictData> model) {
                getDictDataListener.getDictData(model);
            }

            @Override
            public void onFailure(int code, String msg) {

            }

            @Override
            public void onThrowable(Throwable t) {

            }
        });
    }

    public interface getDictDataListener {
        void getDictData(List<BeanDictData> beanDictData);
    }

    // 修改密码:
    public void modifyPwd (BeanPass beanPass, final UpdatePwdListener mUpdatePwdListener) {
        Call<String> call = mloginService.updatePassword(beanPass);
        call.enqueue(new RetrofitCallback<String>() {
            @Override
            public void onSuccess(String model) {

            }

            @Override
            public void onFailure(int code, String msg) {

            }

            @Override
            public void onThrowable(Throwable t) {
                mUpdatePwdListener.getUpdatePwdResult();
            }
        });
    }

    public interface UpdatePwdListener {
        void getUpdatePwdResult();
    }

    // 退出登录

    //发布新版本
    public void publishAppVersion(String os,String  version, final publishAppVersionListener publishAppVersionListener) {
        Call<BeanUpdateData> call = mloginService.getAppVersion(os,version);
        call.enqueue(new RetrofitCallback<BeanUpdateData>() {
            @Override
            public void onSuccess(BeanUpdateData model) {
                publishAppVersionListener.getPublishAppVersion(model);
            }

            @Override
            public void onFailure(int code, String msg) {

            }

            @Override
            public void onThrowable(Throwable t) {

            }
        });
    }
    public interface publishAppVersionListener {
        void getPublishAppVersion(BeanUpdateData beanUpdateData);
    }

    public void setSaveLatitudeAndLongitude(BeanSaveLatitude beanSaveLatitude, final setSaveLatitudeAndLongitudeListener saveLatitudeAndLongitudeListener) {
        Call<String> call = mloginService.saveLatitudeAndLongitude(beanSaveLatitude);
        call.enqueue(new RetrofitCallback<String>() {
            @Override
            public void onSuccess(String model) {

            }

            @Override
            public void onFailure(int code, String msg) {

            }

            @Override
            public void onThrowable(Throwable t) {
                saveLatitudeAndLongitudeListener.saveLatitudeAndLongitude();
            }
        });
    }
    public interface setSaveLatitudeAndLongitudeListener {
        void saveLatitudeAndLongitude();
    }
}

新建ManagerAction.java 类,(对所有的Action 进行统一管理)
代码模块如下:

public class ManagerAcion{
    private static  ManagerAcion instance;
    private String accesstoken;
    private Context contexts;
    private LoginAction loginAction;


    private ManagerAcion(Context context){
        contexts=context;
        accesstoken = PreferencesManager.getInstance(context).get("Access_token");
        initRepositories();
    }
public synchronized static DataManger init(Context context) {
        if (instance != null) {
            throw new RuntimeException("DataManager already init!");
        }
        return instance = new DataManger(context.getApplicationContext());
    }

    private void initRepositories() {
        OkHttpClient httpClient = createHttpClient();
        mLoginAction = new LoginAction(httpClient);
    }
     public LoginAction getLoginAction() {
        return mLoginAction;
    }
        private OkHttpClient createHttpClient() {
        final Map<String, String> headers = new HashMap<>();
        headers.put("X-UserToken", accesstoken);
        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
        if (BuildConfig.DEBUG) {
            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        } else {
            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BASIC);
        }

        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient okHttpClient = new OkHttpClient();
        OkHttpClient.Builder builder = okHttpClient.newBuilder()
                .addInterceptor(loggingInterceptor)
                .addInterceptor(new AccessTokenInterceptor(headers))
                .hostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS)
                .writeTimeout(10, TimeUnit.SECONDS);
        Interceptor stethoInterceptor = getStethoInterceptor();
        if (stethoInterceptor != null) {
            builder.addNetworkInterceptor(stethoInterceptor);
        }
        return builder.build();
    }


    private Interceptor getStethoInterceptor() {
        try {
            Class<?> cls = Class.forName("com.facebook.stetho.okhttp3.StethoInterceptor");
            return (Interceptor) cls.newInstance();
        } catch (ClassNotFoundException ignored) {
            ;// ignored
        } catch (InstantiationException ignored) {
            ;// ignored
        } catch (IllegalAccessException ignored) {
            ;// ignored
        }
        return null;
    }
}

到此一个基本的网络请求的封装类就写完了,下面我们看看它是怎么在具体的接口中使用的;
以LoginActivity.java 为例;
LoginActivity.java 继承BaseActivity.java ;在父类中 初始化ManagerAction;
部分代码块如下:

    LoginAction loginAction = dataManger.getLoginAction();
                        if (!NetWorkUtils.isNetworkAvailable(LoginActivity.this)) {
                            ToastUtil.showToastOnce(LoginActivity.this, getString(R.string.error_network));
                        }
                        loginAction.login(beanLogin, new LoginAction.LoginDataListener() {
                            @Override
                            public void loginData(UserLogin mUserLogin) {
                                if (mUserLogin != null) {
                                    pm.put("token", mUserLogin.getToken());
                                    pm.put("icon", mUserLogin.getUser().getPhoto());
                                    pm.put("userName", mTvUserName.getText().toString());
                                    pm.put("password", mTvPass.getText().toString());
                                    pm.put("customename", mUserLogin.getUser().getRealName());
                                    pm.put("UserId",mUserLogin.getUser().getId());

                                    ToastUtil.showToastDefault(LoginActivity.this, LoginActivity.this.getString(R.string.pg_loginSuccess));
                                    IntentUtils.getIntents().Intent(LoginActivity.this, MainActivity.class);
                                    finish();

                                } else {
//                                    ToastUtil.showToastDefault(LoginActivity.this, "登录失败");
                                }
                            }
                        });

后记

这种模式有个弊端,就是针对每一接口都是去写一个action ,然后在ManagerAction 类中注册管理,如果app API 接口多,则要写很多Action ,从app 设计角度讲,没有做到代码的重用,显得整个项目结构冗余;在下一篇中,我会针对这种情况给出另一种实现方案;不过还是用OkHttp2+retrofit2实现代码逻辑;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值