Android开发经验谈Android开发Android开发

RxJava+Retrofit+ViewModel+LiveDa

2018-09-19  本文已影响93人  大虾啊啊啊

前言

我们可以在github上看到当今比较流行的架构方式有:todo-mvp,todo-mvp-clean,todo-mvvm,todo-mvp-rxjava等等(可以参考:https://github.com/googlesamples/android-architecture),而当今比较流行的技术莫过于:
1.响应式编程+异步任务
RxJava,RxAndroid系列
2.网络框架
Retrofit,Okhttp
3.Android Jetpack系列
LiveData ,ViewModel,Room等 (可以在Android官网看到https://developer.android.google.cn/jetpack/

因此我做了一个demo对RxJava+Retrofit+ViewModel+LiveData的封装;
源码传送门:https://github.com/daxiaaaaaaaaaaaaa/SmartArchitecture

1.RxJava+Retrofit网络框架的封装

package com.architecturedemo.http;


import com.architecturedemo.base.BaseDto;
import com.architecturedemo.dto.LoginDto;
import com.architecturedemo.utils.HttpUtil;
import com.mujin.keji.architecturedemo.vo.LoginVo;


import io.reactivex.Flowable;

public class Api {

    /**
     * 登录接口
     *
     * @param vo
     * @return
     */

    public static Flowable<BaseDto<LoginDto>> login(LoginVo vo) {
        return RequetRetrofit.getInstance().login(HttpUtil.convertVo2Params(vo));
    }

}

package com.architecturedemo.http;


import com.architecturedemo.base.BaseDto;
import com.architecturedemo.dto.LoginDto;

import java.util.Map;


import io.reactivex.Flowable;
import retrofit2.http.FieldMap;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.POST;

/**
 * api接口
 *
 * @author weishixiong
 * @Time 2018-04-2
 */

public interface ApiService {


    /**
     * 登录
     * post
     * 表单提交
     *
     * @param map
     * @return
     */
    @FormUrlEncoded
    @POST("login")
    Flowable<BaseDto<LoginDto>> login(@FieldMap Map<String, String> map);

}


package com.architecturedemo.http;

import android.util.Log;

import com.architecturedemo.CcsApplication;
import com.architecturedemo.Constant;
import com.architecturedemo.interceptor.AddCookiesInterceptor;
import com.architecturedemo.interceptor.ReceivedCookiesInterceptor;
import com.facebook.stetho.okhttp3.StethoInterceptor;
import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;

import com.mujin.keji.architecturedemo.ssl.SafeHostnameVerifier;
import com.mujin.keji.architecturedemo.ssl.SafeTrustManager;


import java.util.concurrent.TimeUnit;

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

/**
 * 普通的网络请求用到的Retrofit
 */

public class RequetRetrofit {
    private static final String TAG = "RequetRetrofit";
     /**
     * 创建okhttp相关对象
     */
    private static OkHttpClient okHttpClient;
    /**
     * 创建Retrofit相关对象
     */
    private static Retrofit retrofit;

    public static ApiService getInstance() {
        if (okHttpClient == null) {
            /**
             * 创建okhttp相关对象
             */
            okHttpClient = new OkHttpClient.Builder()

                    .addInterceptor(new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
                        @Override
                        public void log(String message) {   //访问网络请求,和服务端响应请求时。将数据拦截并输出
                            Log.e(TAG, "log: " + message);
                        }
                    }).setLevel(HttpLoggingInterceptor.Level.BODY))     //Log等级
                    .connectTimeout(Constant.Server.TIME_OUT, TimeUnit.SECONDS)       //超时时间
                    .readTimeout(Constant.Server.TIME_OUT, TimeUnit.SECONDS)
                    .writeTimeout(Constant.Server.TIME_OUT, TimeUnit.SECONDS)
                    .addNetworkInterceptor(new StethoInterceptor())
                    .addInterceptor(new AddCookiesInterceptor()) //这部分
                    .addInterceptor(new ReceivedCookiesInterceptor()) //这部分
                    .hostnameVerifier(new SafeHostnameVerifier())
                    .sslSocketFactory(CcsApplication.getSslSocket(),new SafeTrustManager())
                    //
                    .build();
        }

        if (retrofit == null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl(Constant.Server.ROOT_URL)         //BaseUrl
                    .client(okHttpClient)                       //请求的网络框架
                    .addConverterFactory(GsonConverterFactory.create())     //解析数据格式
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 使用RxJava作为回调适配器
                    .build();
        }
        return retrofit.create(ApiService.class);
    }



}

2.自定义拦截器 实现登录校验,判断sessionId是否过期

package com.architecturedemo.interceptor;

import com.alibaba.fastjson.JSONObject;
import com.architecturedemo.Constant;
import com.architecturedemo.utils.SPUtil;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import okhttp3.Interceptor;
import okhttp3.Response;

/**
 * 首次请求的处理
 * @author : weishixiong
 * @create : 18/05/03
 */
public class ReceivedCookiesInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {

        Response originalResponse = chain.proceed(chain.request());
        if (!originalResponse.headers("Set-Cookie").isEmpty()) {
            List<String> cookies = new ArrayList<>();
            for (String header : originalResponse.headers("Set-Cookie")) {
                cookies.add(header);
            }
            String cookieStr = JSONObject.toJSONString(cookies);
            SPUtil.putData(Constant.SP.SP, Constant.SP.SESSION_ID, cookieStr);
        }

        return originalResponse;
    }
}


package com.architecturedemo.interceptor;

import android.util.Log;

import com.alibaba.fastjson.JSONObject;
import com.architecturedemo.Constant;
import com.architecturedemo.utils.SPUtil;


import java.io.IOException;
import java.util.List;

import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;

/**
 * 非首次请求的处理
 * @author : weishixiong
 * @create : 18/05/03
 */
public class AddCookiesInterceptor implements Interceptor {

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request.Builder builder = chain.request().newBuilder();
        String cookieStr = SPUtil.getData(Constant.SP.SP, Constant.SP.SESSION_ID, String.class, null);
        List<String> cookies = JSONObject.parseArray(cookieStr, String.class);
        if (cookies != null) {
            for (String cookie : cookies) {
                builder.addHeader("Cookie", cookie);
                Log.v("OkHttp", "Adding Header: " + cookie); // This is done so I know which headers are being added; this interceptor is used after the normal logging of OkHttp
            }
        }
        return chain.proceed(builder.build());
    }
}


3.RxJava Subscriber的封装

package com.architecturedemo.base;

import android.arch.lifecycle.MutableLiveData;
import android.os.Build;
import android.support.annotation.RequiresApi;


import com.architecturedemo.Constant;
import com.architecturedemo.exception.ApiException;
import com.architecturedemo.exception.ExceptionEngine;
import com.architecturedemo.exception.ServerException;

import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
/**
 * 自定义请服务器被观察者
 *
 * @author weishixiong
 * @Time 2018-04-12
 */
public class BaseHttpSubscriber<T> implements Subscriber<BaseDto<T>> {

    //异常类
    private ApiException ex;

    public BaseHttpSubscriber() {
        data = new MutableLiveData();

    }

    private MutableLiveData<BaseDto<T>> data;

    public MutableLiveData<BaseDto<T>> get() {
        return data;
    }

    public void set(BaseDto<T> t) {
        this.data.setValue(t);
    }

    public void onFinish(BaseDto<T> t) {
        set(t);
    }

    @Override
    public void onSubscribe(Subscription s) {
        // 观察者接收事件 = 1个
        s.request(1);
    }

    @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
    @Override
    public void onNext(BaseDto<T> t) {
        if (t.getCode() == Constant.Server.SUCCESS_CODE) {
            onFinish(t);
        }  else {
            ex = ExceptionEngine.handleException(new ServerException(t.getCode(), t.getMsg()));
            getErrorDto(ex);
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
    @Override
    public void onError(Throwable t) {
        ex = ExceptionEngine.handleException(t);
        getErrorDto(ex);
    }

    /**
     * 初始化错误的dto
     *
     * @param ex
     */
    private void getErrorDto(ApiException ex) {
        BaseDto dto = new BaseDto();
        dto.setCode(ex.getCode());
        dto.setMsg(ex.getMsg());
        onFinish((BaseDto<T>) dto);
    }

    @Override
    public void onComplete() {
    }
}

4.ViewModel+LiveData对数据的封装

package com.architecturedemo.viewmodel;

import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.ViewModel;

import com.architecturedemo.Constant;
import com.architecturedemo.base.BaseDto;
import com.architecturedemo.dto.LoginDto;
import com.architecturedemo.repository.ILoginRepository;
import com.architecturedemo.repository.LoginRepository;
import com.architecturedemo.utils.SPUtil;
import com.mujin.keji.architecturedemo.vo.LoginVo;


/**
 * 登录viewmodel
 *
 * @author weishixiong
 * @Time 2018-04-2
 */
public class LoginViewModel extends ViewModel {
    private LiveData<BaseDto<LoginDto>> loginDtoLiveData;
    private ILoginRepository loginRepository;
    public LiveData<BaseDto<LoginDto>> getLoginDtoLiveData() {
     return loginDtoLiveData;
     }
     /**
     * 登录
     * @param username
     * @param password
     */
    public void  login(String username,String password){
        SPUtil.clearData(Constant.SP.SP);
        loginRepository = new LoginRepository();
        LoginVo vo = new LoginVo();
        vo.setPassword(password);
        vo.setUsername(username);
        this.loginDtoLiveData = loginRepository.login(vo);
    }

}

因为代码比较多就不一一贴出来了,有兴趣的同学可以下载demo看看

上一篇 下一篇

猜你喜欢

热点阅读