Retrofit+RxJava 的封装更新

老套路,先上图(没效果图的博客,我一般都不想看):

Retrofit+RxJava 的封装更新_第1张图片

Demo源码:下载源码

图中的效果很简单,就三个按钮,前面的两个按钮是一个组合,从获取验证码再到注册账号(因为,在测试的时候我的手机号已经注册过了,所以,这时候再注册就会提示手机号已被注册),当然这不是重点,重点是我们的请求方式,这两按钮的请求我用的是post请求,并且参数也按照规则进行了加密,有兴趣的可以自己去下载看看!!

最后一个按钮就是简单的get请求,效果就介绍到这里了,正所谓没有对比就没有伤害,在欣赏新作品之前还是先看看以前我封装的Retrofit吧,连接地址:单纯的get请求 下面看看更新后的封装吧:

首先还是依赖:

compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
compile 'io.reactivex.rxjava2:rxjava:2.1.0'
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
compile 'com.squareup.retrofit2:converter-scalars:+'
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'

仔细对比会知道,前后的依赖并没有发生变化,这里也就不再解释了。

接着再看封装的Retrofit工具类:

public class RetrofitFacety {

    /**
     *
     * @param file 设置数据缓存的路径
     * @param url  接口路劲
     * @param mvpJieKou  回调数据的接口
     */


    //使全局就一个OKHttpClient对象
    public static OkHttpClient okHttpClient = new OkHttpClient.Builder()
//            .cookieJar(new CookiesManager())
            .connectTimeout(20,TimeUnit.SECONDS)
            .readTimeout(20, TimeUnit.SECONDS)
            .writeTimeout(20, TimeUnit.SECONDS)
//            .addInterceptor(new LoggingInterceptor())
            .build();

    //使全局就一个Retrofit对象,设置基础Url
    public static ApiService apiService = new Retrofit.Builder()
            .baseUrl(APIs.debug)
            //使我们能高度自定义转化器
            .addConverterFactory(ScalarsConverterFactory.create())
            .client(okHttpClient)
            //把 以前的 call 转化成 Observable,这是RetrofitRxJava结合使用的关键
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())

            .build().create(ApiService.class);


    /**
     *  retrofitget请求
     * @param url
     * @return
     */
    public static Observable get(String url) {
        return apiService.get(url)
                .doOnNext(new Consumer() {
                    @Override
                    public void accept(@NonNull String s) throws Exception {
                        Log.i("jiba","这是处理缓存本地操作==="+s);
                    }
                })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }

    /**
     * retrofitpost请求
     * @param url
     * @param map
     * @return
     */
   public static Observable post(String url, Map map){
       return apiService.post(url,map)
               .doOnNext(new Consumer() {
                   @Override
                   public void accept(@NonNull String s) throws Exception {
                       Log.i("jiba","===这是个什么");
                   }
               })
               .subscribeOn(Schedulers.io())
               .observeOn(AndroidSchedulers.mainThread());
   }

}

前后对比一下,发现多了一个post的请求方式,这一点很重要,因为真实的项目中几乎全部都是post的请求方式,可以说关于get是绝种了,至于原因与为什么相信就不用我来解释了吧!post请求的好处,百度上搜一搜,那是一大片。。。

在这个类里面会发现用到了很关键的一个类,并且还是反射出来的,叫ApiService,既然有了,那我就去看看他是什么吧?

来,走起:

public interface ApiService {

    /**
     *  retrofitget请求
     * @param url
     * @return
     */
    @GET
    Observable get(@Url String url);


    /**
     * retrofitpost请求
     * @return
     */
    @FormUrlEncoded
    @POST
    Observable post(@Url String url, @FieldMap Map map);

}

还是一样通过比对,才能有进步,发现多了一个@POST 注解的请求,关于retrofit中post请求我也做过很多功课,就在我博客中提到的就已经有三种了,我也一一给大家做过一些介绍,这里我就只给出地址,有兴趣的自己研究吧!retrofit上传头像post方式,retrofit的上传头像+携带参数,这两个地址是我以前用来上传头像的,但万变不离其中,post的请求是不会变的,变的只是我们的使用方式

接下来就是具体的使用方式(我采用的是mvp的代码架构,并且对mvp抽取了基类):

先看model层:

public class MyModel {

    /**
     * model中的get请求方式
     * @param url
     * @param myInterfaces
     */
    public void getModContent(String url, final MyInterfaces myInterfaces){
        RetrofitFacety.get(url)
                .subscribe(new BaseServer() {
                    @Override
                    public void onSuccess(String json) {
                        myInterfaces.chenggong(json);
                    }

                    @Override
                    public void onErroy(String ss) {
                        myInterfaces.shibai(ss);
                    }
                });
    }

    /**
     * model中的post请求
     * @param url
     * @param map
     * @param myInterfaces
     */
    public void postModContent(String url, Map map, final MyInterfaces myInterfaces){

        RetrofitFacety.post(url,map)
                .subscribe(new BaseServer() {
                    @Override
                    public void onSuccess(String json) {
                        myInterfaces.chenggong(json);
                    }

                    @Override
                    public void onErroy(String ss) {
                        myInterfaces.shibai(ss);
                    }
                });
    }
}

这个应该不用多解释的,如果有疑问的话,只能说明你对mvp还不熟悉,model层中涉及到一个类:BaseServer 这个类其实也是对retrofit的封装,只不过他是对结果的封装,看代码:

/**
 * Created by mypc on 2018/1/6.
 *
 * 父类的公有方法的抽取,,抽象的思想
 */

public abstract class BaseServer implements Observer {

    public abstract void onSuccess(String json);
    public abstract void onErroy(String ss);

    @Override
    public void onError(Throwable e) {
        onErroy("请求失败");
        Log.i("jiba","===="+e);
    }

    @Override
    public void onNext(String json) {
        try {
//            Log.i("jiba","onNext==="+json);
            onSuccess(json);
        }catch (Exception e1) {

        }
    }

    @Override
    public void onSubscribe(@NonNull Disposable d) {

    }

    @Override
    public void onComplete() {

    }
}

这个类,采用的是java中抽象的思想!

言归正传,回到我们的使用当中来,present层:

public class MyPresenter<V> {

    private final MyModel myModel;

    public MyPresenter() {
        myModel = new MyModel();
    }
    //将泛型vp进行绑定
     V view;
    public void attch(V view){
        this.view=view;
    }

    /**
     *  present中的get请求
     * @param url
     * @param myInterfaces
     */
    public void getPreContent(String url, final MyInterfaces myInterfaces){
        myModel.getModContent(url, new MyInterfaces() {
            @Override
            public void chenggong(String json) {
                myInterfaces.chenggong(json);
            }

            @Override
            public void shibai(String ss) {
                myInterfaces.shibai(ss);
            }
        });
    }

    /**
     * present中的post请求
     * @param url
     * @param map
     * @param myInterfaces
     */
    public void postPreContent(String url, Map map, final MyInterfaces myInterfaces){
        myModel.postModContent(url, map, new MyInterfaces() {
            @Override
            public void chenggong(String json) {
                myInterfaces.chenggong(json);
            }

            @Override
            public void shibai(String ss) {
                myInterfaces.shibai(ss);
            }
        });
    }


    //将泛型vp进行解绑
    public void setonDestroy(){
        try{
            this.view=null;
        }catch (Exception e){

        }
    }
}
关于present层,有疑惑可能就是他里面的泛型了,对于泛型,我没什么好说的,属于java基础的东西(其实我也不太会,但我多少了解一点),这里提供一个学习泛型的网址给大家: java泛型详解

有了P层,M层肯定还需要一个V层的,所以关于V层的基类我也给大家粘出来了:

public abstract class BaseMVPActivity<V,P extends MyPresenter<V>> extends AppCompatActivity {

    public P myPresenter;
    public abstract P initPresenter();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_base_mvp);
        myPresenter= initPresenter();
        if(Build.VERSION.SDK_INT>=23){
            String[] mPermissionList = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.CALL_PHONE,Manifest.permission.READ_LOGS,Manifest.permission.READ_PHONE_STATE, Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.SET_DEBUG_APP,Manifest.permission.SYSTEM_ALERT_WINDOW,Manifest.permission.GET_ACCOUNTS,Manifest.permission.WRITE_APN_SETTINGS};
            ActivityCompat.requestPermissions(this,mPermissionList,123);
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        myPresenter.attch((V) this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        myPresenter.setonDestroy();
    }

    //封装吐司
    public Toast toast;
    public  void setToast(String ss){
        if(toast==null){
            toast=Toast.makeText(getApplicationContext(),ss,Toast.LENGTH_SHORT);
        }
        toast.setText(ss);
        toast.show();
    }
}

在BaseMvpActivity中,我也还做了另外一件事,就是Toast的封装,用这个吐司,完全不用担心内存泄漏的问题,可以说很完美了,当然了,在这个基类中我们还可以做上埋点(监测用户行为),也可以做上6.0的权限适配,这个6.0权限适配结合上埋点,两者配合使用,那简直就是一大杀招啊!!具体实现思路后期会给大家补上!

最后就到咱们最重要的环节了,MainActivity的按钮点击事件:

public class MainActivity extends BaseMVPActivity> implements View.OnClickListener {

    String iphone = "188****3955";  // 手机号换成自己的
    String type = "register";  // 发送验证码类型:register -- 注册 、 login -- 验证码登陆 、 forget -- 忘记密码
    private Button but1;
    private EditText yanzhengma;
    private Button but2;
    private TextView tishi;
    private Button but3;
    private TextView shuju;
    private PublicKey publicKey; // 将公司给的密钥通过base64转成公钥对象

    @Override
    public MyPresenter initPresenter() {
        if (myPresenter == null)
            myPresenter = new MyPresenter<>();
        return myPresenter;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();

        //RSA公钥加密对象
        publicKey = RSAUtil.keyStrToPublicKey1(APIs.PUBLIC_KEY_STR); 
    }

    private void initView() {

        but1 = (Button) findViewById(R.id.but1);
        but1.setOnClickListener(this);
        yanzhengma = (EditText) findViewById(R.id.yanzhengma);
        yanzhengma.setOnClickListener(this);
        but2 = (Button) findViewById(R.id.but2);
        but2.setOnClickListener(this);
        tishi = (TextView) findViewById(R.id.tishi);
        tishi.setOnClickListener(this);
        but3 = (Button) findViewById(R.id.but3);
        but3.setOnClickListener(this);
        shuju = (TextView) findViewById(R.id.shuju);
        shuju.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.but1:

                getYanZhengMa();
                break;

            case R.id.but2:
                submit();

                break;
            case R.id.but3:
                myPresenter.getPreContent(APIs.SHANGPIN, new MyInterfaces() {
                    @Override
                    public void chenggong(String json) {
                        shuju.setText(json);
                    }

                    @Override
                    public void shibai(String ss) {
                        LogUtil.e("jiba","MainActivity 获取商品数据 有误==="+ss);
                    }
                });

                break;
        }
    }

    /**
     *  iphone string Y     要注册的手机号
        type   string Y     发送验证码类型:register -- 注册 、 login -- 验证码登陆 、 forget -- 忘记密码
     */
    private void getYanZhengMa() {
       // 对数据参数进行公钥加密  iphone 参数需要加密
        String publicEncryptedResult = RSAUtil.encryptDataByPublicKey(iphone.getBytes(), publicKey); 
        LogUtil.i("jiba", "=====" + publicEncryptedResult);
        
        HashMap map = new HashMap<>();
        map.put("iphone",publicEncryptedResult);
        map.put("type",type);
        myPresenter.postPreContent(APIs.YANZHENGMA, map, new MyInterfaces() {
            @Override
            public void chenggong(String json) {
                Gson gson = new Gson();
                YaZhengMaBean yaZhengMaBean = gson.fromJson(json, YaZhengMaBean.class);
                if(yaZhengMaBean.getCode()==1){
                    setToast(yaZhengMaBean.getMsg());
                }else{
                    setToast(yaZhengMaBean.getMsg());
                }
            }

            @Override
            public void shibai(String ss) {
                LogUtil.e("jiba","MainActivity 获取验证码有误==="+ss);
            }
        });
    }


    /**
     *   encryptData   array->json        Y     注册所对应的信息(手机号、密码等)
         act           string         Y     判断所对应的类型:register-- 注册
         code          string->json   Y     验证码
         tel           string->json   Y     手机号
         password      string->json   Y     密码
     */
    private void submit()  {
        String yanzhengmaString = yanzhengma.getText().toString().trim();
        if (TextUtils.isEmpty(yanzhengmaString)) {
            Toast.makeText(this, "验证码不能为空", Toast.LENGTH_SHORT).show();
            return ;
        }
        HashMap map = new HashMap<>();
        map.put("tel",iphone);
        map.put("password","w123456");
        map.put("code",yanzhengmaString);
        JSONObject jsonObject = new JSONObject(map);
        String json = jsonObject.toString();      //  后台接口规则 参数必须转成json,并需要加密
        
        // 将之前集合中的数据清空,从而复用map集合,这样可以达到内存优化的作用
        map.clear();
        // 对数据参数进行公钥加密
        String encryptData = RSAUtil.encryptDataByPublicKey(json.getBytes(), publicKey);
        map.put("encryptData",encryptData);
        
        map.put("act",type);
        
        myPresenter.postPreContent(APIs.ZHUCE, map, new MyInterfaces() {
            @Override
            public void chenggong(String json) {

                Gson gson = new Gson();
                YaZhengMaBean yaZhengMaBean = gson.fromJson(json, YaZhengMaBean.class);
                if(yaZhengMaBean.getCode()==1){
                    tishi.setText(yaZhengMaBean.getMsg());
                }else{
                    tishi.setText(yaZhengMaBean.getMsg());
                }
            }

            @Override
            public void shibai(String ss) {
                LogUtil.e("jiba","MainActivity 注册有误==="+ss);
            }
        });

    }
}

到这儿,我们的封装使用就结束了,希望能对大家有点帮助吧!!

差点忘记给大家附上APIs的接口了:

public class APIs {

    // 公司公钥
    public static final String PUBLIC_KEY_STR = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDF3wFJC/f/5qHR30BzLpcxdRtq\n" +
            "ahoXu31tbGwg97iRhVfXxLqFp2OZqdJjkYNqCuuIzRlYSJqXURkXD3UxrbiwGAMi\n" +
            "FqPbXW/JEXgWqsqf59tRAWhJ5Ycy0Ln03lyCnVbAtdhzoqe+vfrNTg0R/D3vMMcS\n" +
            "O76rXvvK1zxF19vy9wIDAQAB\n";

    // 公司域名
    public static final String debug="http://www.jingchengcaidian.com/";

    // 获取验证码
    public static final String YANZHENGMA= debug + "app/message/getIphone";

    // 注册账号  http://www.jingchengcaidian.com/app/login/getUserInfo
    public static final String ZHUCE= debug + "app/login/getUserInfo";

    


    // 获取商品数据
    public static final String SHANGPIN="https://www.zhaoapi.cn/product/getProducts?pscid=2&page=1&source=android";



}


你可能感兴趣的:(Retrofit+RxJava 的封装更新)