Android Mvp+RxJava+Retrofit 实战

2,786 阅读4分钟
原文链接: raindrops.club

目录结构

build.gradle

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:24.0.0'
    compile 'com.orhanobut:logger:1.8'
    compile 'io.reactivex:rxjava:1.1.7'
    compile 'io.reactivex:rxandroid:1.2.1'
    compile 'com.squareup.retrofit2:retrofit:2.1.0'
    compile 'com.google.code.gson:gson:2.7'
    compile 'com.squareup.retrofit2:converter-gson:2.1.0'
    compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
}

Rxjava+Retrofit统一Http的封装

HttpService

Retrofit的配置

public interface HttpService {
    /**
     * 测量多点之间的直线距离
     *
     * @param waypoints 需要测距的点的经纬度坐标;需传入两个或更多的点。两个点之间用 “; ”进行分割开,单个点的经纬度用“,”分隔开;例如: waypoints=118
     *                  .77147503233,32.054128923368;116.3521416286, 39.965780080447;116
     *                  .28215586757,39.965780080447
     * @param ak
     * @param output
     * @return
     */
    @FormUrlEncoded
    @POST("distance?")
    Observable>> getDistance(@Field("waypoints") String waypoints,
                                                         @Field("ak") String ak,
                                                         @Field("output") String output);
}

HttpUtil

Retrofit和Rxjava进行结合 封装网络请求类

public class HttpUtil {
    /**
     * 超时时间
     */
    private static final int DEFAULT_TIMEOUT = 10;
    /**
     * retrofit
     */
    private Retrofit retrofit;
    /**
     * 接口请求
     */
    private HttpService httpService;

    public HttpService getHttpService() {
        return httpService;
    }

    private HttpUtil() {
        //创建一个OkHttpClient并设置超时时间
        OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
        httpClientBuilder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
        //添加迭代器
        httpClientBuilder.addInterceptor(new LoggerInterceptor());
        retrofit = new Retrofit.Builder()
                .client(httpClientBuilder.build())
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(StaticCode.BASE_URL)
                .build();
        httpService = retrofit.create(HttpService.class);
    }

    //在访问HttpUtil时创建单例
    private static class SingletonHolder {
        private static final HttpUtil INSTANCE = new HttpUtil();
    }

    //获取单例
    public static HttpUtil getInstance() {
        return SingletonHolder.INSTANCE;
    }

    /**
     * 组装Observable
     *
     * @param observable
     */
    public Observable packageObservable(Observable observable) {
        return observable.subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }

    /**
     * 获取网络数据不转化
     *
     * @param observable
     */
    public Subscription sendHttp(Observable observable, HttpSubscriber listener) {
        return packageObservable(observable)
                .subscribe(listener);
    }

    /**
     * 获取网络数据转化
     *
     * @param observable
     */
    public  Subscription sendHttpWithMap(Observable observable, HttpSubscriber
            listener) {
        return observable.compose(this.applySchedulers())
                .subscribe(listener);
    }

    /**
     * Observable 转化
     *
     * @param 
     * @return
     */
     Observable.Transformer, T> applySchedulers() {
        return new Observable.Transformer, T>() {
            @Override
            public Observable call(Observable> baseHttpResultObservable) {
                return baseHttpResultObservable.map(new HttpFunc())
                        .subscribeOn(Schedulers.io())
                        .unsubscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread());
            }
        };
    }

    /**
     * 用来统一处理Http请求到的数据,并将数据解析成对应的Model返回
     *
     * @param  Subscriber真正需要的数据类型
     */
    private class HttpFunc implements Func1, T> {

        @Override
        public T call(BaseHttpResult baseHttpResult) {
            //获取数据失败则抛出异常 会进入到subscriber的onError中
            if (!baseHttpResult.getStatus().equals(StaticCode.HTTP_RESPONSE_SUCCESS))
                throw new RuntimeException(baseHttpResult.getStatus());

            return baseHttpResult.getResults();
        }
    }
}

LoggerInterceptor

日志打印和请求头的增加

public class LoggerInterceptor implements Interceptor {

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request originalRequest = chain.request().newBuilder().addHeader("version", "1.0")
                .addHeader("clientSort", "android").addHeader("Charset", "UTF-8")
                .build();

        printRequestLog(originalRequest);
        Response response = null;
        try {
            //发送网络请求
            response = chain.proceed(originalRequest);
            printResult(response);
        } catch (SocketTimeoutException e) {
            //此处不抛异常  连接超时会crash 没有找到其他好的方法
            e.printStackTrace();

        }
        return response;
    }

    /**
     * 打印请求日志
     *
     * @param originalRequest
     * @return
     * @throws IOException
     */
    private void printRequestLog(Request originalRequest) throws IOException {
        FormBody.Builder formBuilder = new FormBody.Builder();
        String msg = originalRequest.url() + "\n";
        RequestBody oidBody = originalRequest.body();
        if (oidBody instanceof FormBody) {
            FormBody formBody = (FormBody) oidBody;
            for (int i = 0; i < formBody.size(); i++) {
                String name = URLDecoder.decode(formBody.encodedName(i), "utf-8");
                String value = URLDecoder.decode(formBody.encodedValue(i), "utf-8");
                if (!TextUtils.isEmpty(value)) {
                    formBuilder.add(name, value);
                    msg += name + "  =  " + value + "\n";
                }
            }
        }
        Logger.i(msg);
    }
    /**
     * 打印返回日志
     *
     * @param response
     * @throws IOException
     */
    private void printResult(Response response) throws IOException {
        ResponseBody responseBody = response.body();
        BufferedSource source = responseBody.source();
        source.request(Long.MAX_VALUE); // Buffer the entire body.
        Buffer buffer = source.buffer();
        Charset UTF8 = Charset.forName("UTF-8");
        MediaType contentType = responseBody.contentType();
        if (contentType != null) {
            UTF8 = contentType.charset(UTF8);
        }
        String a = buffer.clone().readString(UTF8);
        Logger.i(a);
    }

}

BaseHttpResult

 public class BaseHttpResult {
    public String status;

    private T results;

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public T getResults() {
        return results;
    }

    public void setResults(T results) {
        this.results = results;
    }
}

Rxjava的回调

public abstract class HttpSubscriber extends Subscriber {

    /**
     * 请求标示
     */
    private int tag;

    public HttpSubscriber(int tag) {
        this.tag = tag;
    }

    @Override
    public void onCompleted() {
        _complete();
    }

    @Override
    public void onError(Throwable e) {
        _complete();
        onError(e.getMessage(), tag);
    }

    @Override
    public void onNext(T t) {
        onSuccess(t, tag);
    }

    public abstract void onSuccess(T t, int tag);

    public abstract void onError(String msg, int tag);

    public abstract void _complete();

}

Mvp的加入

MvpView

public interface MvpView {

    void showLoadingDialog();

    void dismissLoadingDialog();

}

IBasePresenter

public interface IBasePresenter {

    void subscribe();

    void unsubscribe();

}

BasePresenter

对Presenter公共部分进行初始化
public abstract class BasePresenter implements
IBasePresenter {

    protected HttpUtil httpUtil = null;

    protected HttpService httpService = null;

    protected V baseView;
    /**
     * 统一取消网络请求
     */
    private CompositeSubscription compositeSubscription;

    public BasePresenter(V view) {
        this.baseView = view;
        httpUtil = HttpUtil.getInstance();
        httpService = httpUtil.getHttpService();
        compositeSubscription = new CompositeSubscription();
    }

    protected HttpSubscriber getProgressSubscriber(int tag) {
        baseView.showLoadingDialog();
        return new HttpSubscriber(tag) {
            @Override
            public void onSuccess(T t, int tag) {
                BasePresenter.this.onSuccess(t, tag);
            }

            @Override
            public void onError(String msg, int tag) {
                BasePresenter.this.onError(msg, tag);
            }

            @Override
            public void _complete() {
                baseView.dismissLoadingDialog();
            }
        };
    }

    /**
     * 发送网络请求对结果不进行转化
     *
     * @param observable
     * @param tag
     */
    protected void sendHttp(Observable observable, int tag) {
        compositeSubscription.add(httpUtil.sendHttp(observable, getProgressSubscriber(tag)));
    }

    protected void sendHttp(Observable observable) {
        sendHttp(observable, 0);
    }

    /**
     * 发送网络请求对结果进行转化
     *
     * @param observable
     * @param tag
     */
    protected void sendHttpWithMap(Observable observable, int tag) {
        compositeSubscription.add(httpUtil.sendHttpWithMap(observable, getProgressSubscriber
                (tag)));
    }

    protected void sendHttpWithMap(Observable observable) {
        sendHttpWithMap(observable, 0);
    }

    public abstract void onSuccess(T t, int tag);

    public abstract void onError(String msg, int tag);


    /**
     * 取消网络请求
     */
    @Override
    public void unsubscribe() {
        if (compositeSubscription != null && compositeSubscription.hasSubscriptions())
            compositeSubscription.unsubscribe();
    }

    /**
     * 手动添加subscription
     *
     * @param subscription
     */
    public void addSubscription(Subscription subscription) {
        if (compositeSubscription == null) {
            compositeSubscription = new CompositeSubscription();
        }
        compositeSubscription.add(subscription);
    }
}

使用示例

MainActivity

Activity中实现View

public class MainActivity extends AppCompatActivity implements MainContract.IMainView {


    private MainPre mainPre;
    private android.widget.TextView getDistance;
    private android.widget.TextView firstToSecondDistance;
    private android.widget.TextView secondToThreeDistance;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.secondToThreeDistance = (TextView) findViewById(R.id.second_to_three_distance);
        this.firstToSecondDistance = (TextView) findViewById(R.id.first_to_second_distance);
        this.getDistance = (TextView) findViewById(R.id.get_distance);

        mainPre = new MainPre(this);

        getDistance.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mainPre.subscribe();
            }
        });
    }

    @Override
    public void setFirstPointToSecondPointDistance(String distance) {
        firstToSecondDistance.setText(distance);
    }

    @Override
    public void setSecondPointToThreePointDistance(String distance) {
        secondToThreeDistance.setText(distance);
    }

    @Override
    public void showLoadingDialog() {
        //这边可以做Dialog的显示
        Logger.e("请求开始");
    }

    @Override
    public void dismissLoadingDialog() {
        //这边可以做Dialog的隐藏
        Logger.e("请求结束");
    }
}

MainContract

public class MainContract {
    /**
     * Created by huangweizhou on 16/8/10.
     */

    public interface IMainView extends MvpView {
        /**
         * 第一个点和第二个点之间的距离
         *
         * @param distance
         */
        void setFirstPointToSecondPointDistance(String distance);

        /**
         * 第二个点和第三个点之间的距离
         *
         * @param distance
         */

        void setSecondPointToThreePointDistance(String distance);
    }
}

MainPre

presenter中绑定对应的View和解析的类型

public class MainPre extends BasePresenter> {
    public MainPre(MainContract.IMainView view) {
        super(view);
    }

    @Override
    public void onSuccess(List strings, int tag) {
        baseView.setFirstPointToSecondPointDistance(strings.get(0));
        baseView.setSecondPointToThreePointDistance(strings.get(1));
    }

    @Override
    public void onError(String msg, int tag) {
        Logger.e(msg);
    }


    @Override
    public void subscribe() {
        sendHttpWithMap(httpService.getDistance("118.77147503233,32.054128923368;\n" +
                "     116.3521416286,39.965780080447;116.28215586757,39\n" +
                "     .965780080447", "6cyEpstfAo1HSFGPSeshRXa459p3TyT0", "json"));
    }
}

StaticCode

public class StaticCode {

    /**
     * Java地址
     */
    public static final String BASE_URL = "http://api.map.baidu.com/telematics/v3/";

    /**
     * 获取网络数据成功
     */
    public static final String HTTP_RESPONSE_SUCCESS = "Success";

}

源码地址

Mvp-RxJava-Retrofit