天天看點

Android Mvp+Rxjava+Retrofit實戰Android Mvp+Rxjava+Retrofit實戰

Android Mvp+Rxjava+Retrofit實戰

目錄結構

Android Mvp+Rxjava+Retrofit實戰Android Mvp+Rxjava+Retrofit實戰

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<BaseHttpResult<List<String>>> 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 <T> Subscription sendHttpWithMap(Observable observable, HttpSubscriber<T>
            listener) {
        return observable.compose(this.<T>applySchedulers())
                .subscribe(listener);
    }

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

    /**
     * 用來統一處理Http請求到的資料,并将資料解析成對應的Model傳回
     *
     * @param <T> Subscriber真正需要的資料類型
     */
    private class HttpFunc<T> implements Func1<BaseHttpResult<T>, T> {

        @Override
        public T call(BaseHttpResult<T> 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<T> {
    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;
    }
}
           

HttpSubscriber

Rxjava的回調

public abstract class HttpSubscriber<T> extends Subscriber<T> {

    /**
     * 請求标示
     */
    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<V extends MvpView> {

    void subscribe();

    void unsubscribe();

}
           

BasePresenter

對Presenter公共部分進行初始化

public abstract class BasePresenter

使用示例

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<MainContract.IMainView, List<String>> {
    public MainPre(MainContract.IMainView view) {
        super(view);
    }

    @Override
    public void onSuccess(List<String> 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