嗬啊啊,是还是不是有一种碟中谍、局中局的感到…当然,为了减小层级,我们得以把分页的有关新闻涉及resultCode这么些层级来,那些供给大家跟服务端协定好一个条条框框。

5.1处理onNext

我们希望那里能够让Activity或许Fragment本人处理onNext之后的逻辑,很当然的大家想到了用接口。难点或许泛型的标题,那当中大家必须钦点显著的项目。所以接口照旧供给泛型。

大家先来定义叁个接口,命名SubscriberOnNextListener

public interface SubscriberOnNextListener<T> {
    void onNext(T t);
}

代码非常粗大略。再来看一下ProgressSubscriber现在的代码

public class ProgressSubscriber<T> extends Subscriber<T> {

    private SubscriberOnNextListener mSubscriberOnNextListener;
    private Context context;

    public ProgressSubscriber(SubscriberOnNextListener mSubscriberOnNextListener, Context context) {
        this.mSubscriberOnNextListener = mSubscriberOnNextListener;
        this.context = context;
    }

    @Override
    public void onStart() {
    }

    @Override
    public void onCompleted() {
        Toast.makeText(context, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onError(Throwable e) {
        Toast.makeText(context, "error:" + e.getMessage(), Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onNext(T t) {
        mSubscriberOnNextListener.onNext(t);
    }
}

自身清楚传Context不佳,可是为了演示而已,大家能够协调包裹一下Toast。

MainActivity使用是如此的:

先来定义三个SubscriberOnNextListener对象,能够在onCreate里面成立那些目的

private SubscriberOnNextListener getTopMovieOnNext;

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

    getTopMovieOnNext = new SubscriberOnNextListener<List<Subject>>() {
        @Override
        public void onNext(List<Subject> subjects) {
            resultTV.setText(subjects.toString());
        }
    };
}

getMovie情势这么写:

private void getMovie(){
 HttpMethods.getInstance().getTopMovie(
  new ProgressSubscriber(getTopMovieOnNext, MainActivity.this), 
  0, 10);
}

这么Activity或Fragment就只须要关爱得到结果过后的逻辑了,其余的完全不用操心。

如需查看项目代码 –> 代码地址:

https://github.com/tough1985/RxjavaRetrofitDemo

选择Tag -> step6

private void getMovie() {
        String baseUrl = "https://api.douban.com/v2/movie/";
        /** 创建Retrofit对象,数据转换使用Gson **/
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        /** 通过MoviceService得到Call,然后加入请求队列并,并在Callback接口方法中处理返回结果 **/
        MovieService movieService = retrofit.create(MovieService.class);
        Call<MovieEntity> call = movieService.getTopMovie(0, 10);
        call.enqueue(new Callback<MovieEntity>() {
            @Override
            public void onResponse(Call<MovieEntity> call, Response<MovieEntity> response) {
                resultTV.setText(response.body().toString());
            }

            @Override
            public void onFailure(Call<MovieEntity> call, Throwable t) {
                resultTV.setText(t.getMessage());
            }
        });
    }

1.2 只用Retrofit

我们准备在getMovie格局中展开网络请求,大家先来探望只使用Retrofit是怎么着开始展览的。

我们运用豆瓣电影的Top250做测试连接,指标地址为

https://api.douban.com/v2/movie/top250?start=0&count=10

至于重返的数量格式,大家温馨走访下链接就看出了,太长就不放进来了。

首先我们要依据重回的结果封装多少个Entity,暂命名为MovieEntity,代码就不贴了。

接下去大家要开创一个接口取名为MovieService,代码如下:

public interface MovieService {
    @GET("top250")
    Call<MovieEntity> getTopMovie(@Query("start") int start, @Query("count") int count);
}

回到MainActivity当中,大家来写getMovie方法的代码

//进行网络请求
private void getMovie(){
    String baseUrl = "https://api.douban.com/v2/movie/";

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(baseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    MovieService movieService = retrofit.create(MovieService.class);
    Call<MovieEntity> call = movieService.getTopMovie(0, 10);
    call.enqueue(new Callback<MovieEntity>() {
        @Override
        public void onResponse(Call<MovieEntity> call, Response<MovieEntity> response) {
            resultTV.setText(response.body().toString());
        }

        @Override
        public void onFailure(Call<MovieEntity> call, Throwable t) {
            resultTV.setText(t.getMessage());
        }
    });
}

上述为没有经过包装的、原生态的Retrofit写互连网请求的代码。
大家得以打包制造Retrofit和service部分的代码,然后Activity用创制三个Callback作为参数给Call,那样Activity中只关注请求的结果,而且Call有cancel方法可以撤除1个呼吁,好像没PAJEROxjava什么事了,俺觉着能够写到那就下班了~

接下去我们要面对的标题是这么的
假设笔者的Http重回数据是二个统一的格式,例如

{
 "resultCode": 0,
 "resultMessage": "成功",
 "data": {}
}

我们怎么着对回到结果开始展览1个联合的拍卖吧?

其余,笔者的ProgressDialog的show方法应该在哪调用吗?看样子只可以在getMovie()那些措施里面调用了,换个地点发出请求就要在相应的Listener里面写叁次show()的代码,其实挺干扰。

同时荒唐请求我也想集中处理掉不要贴重复的代码。

咱俩先来看结合了Havalxjava之后,事情有没有转移的也许。当然便是是并非途胜xjava,依然能够做过多的卷入,只是比较麻烦。

如需查看项目代码 –> 代码地址:

https://github.com/tough1985/RxjavaRetrofitDemo

选择Tag -> step1

先是,本篇是基于这个的下结论、思考和进展,那篇小编按部就班,徐徐道来,读起来感到很棒。

4.怎么撤除一个Http请求 — 观望者之间的对决,Observer VS Subscriber

是的,以上办法便得以形成请求,不过看起来不美,大家得以由此包装请求方法,在Activity或Fragment中只保留更新UI相关的逻辑。OK,单纯的包装比较简单,我们联合参与纳瓦拉xjava来探视。

1.4 将呼吁进程实行李包裹装

开创多少个对象HttpMethods

public class HttpMethods {

    public static final String BASE_URL = "https://api.douban.com/v2/movie/";

    private static final int DEFAULT_TIMEOUT = 5;

    private Retrofit retrofit;
    private MovieService movieService;

    //构造方法私有
    private HttpMethods() {
        //手动创建一个OkHttpClient并设置超时时间
        OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
        httpClientBuilder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);

        retrofit = new Retrofit.Builder()
                .client(httpClientBuilder.build())
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(BASE_URL)
                .build();

        movieService = retrofit.create(MovieService.class);
    }

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

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

    /**
     * 用于获取豆瓣电影Top250的数据
     * @param subscriber 由调用者传过来的观察者对象
     * @param start 起始位置
     * @param count 获取长度
     */
    public void getTopMovie(Subscriber<MovieEntity> subscriber, int start, int count){
        movieService.getTopMovie(start, count)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(subscriber);
    }
}

用3个单例来封装该指标,在构造方法中开创Retrofit和呼应的瑟维斯。
如若须求拜访分化的营地址,那么您恐怕要求创设多个Retrofit对象,大概索性依据分裂的军基址封装分歧的HttpMethod类。

大家回头再来看MainActivity中的getMovie方法:

private void getMovie(){
     subscriber = new Subscriber<MovieEntity>() {
         @Override
         public void onCompleted() {
             Toast.makeText(MainActivity.this, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();
         }

         @Override
         public void onError(Throwable e) {
             resultTV.setText(e.getMessage());
         }

         @Override
         public void onNext(MovieEntity movieEntity) {
             resultTV.setText(movieEntity.toString());
         }
     };
     HttpMethods.getInstance().getTopMovie(subscriber, 0, 10);
}

里面subscriber是MainActivity的分子变量。

如需查看项目代码 –> 代码地址:

https://github.com/tough1985/RxjavaRetrofitDemo

选择Tag -> step3

public class HttpResult<T> {
    private int resultCode;
    private String resultMsg;
    private T data;
}

转自:http://gank.io/post/56e80c2c677659311bed9841?from=timeline&isappinstalled=0&nsukey=g1D1Y6PMp3BW%2B0%2F%2Butx4StSJxcUCTm4%2BN8T7LnPNCCeQEY1lzm6oKvXdbrlAD4E9T%2FB1quV75jJB7H9zjcRxTQ%3D%3D

故此,协定好3个标准、好用的数据结构,是何其的酸爽。

 

observable<HttpResult<List<Movie>>>

2.同样格式的Http请求数据该怎么封装

其次某些和第叁某个小编参考了天涯论坛上的1个问答: CR-VxJava+Retrofit,在联网再次来到后怎么先进行合并的判定? 可是没有完全的言传身教,所以在那写2个整机的演示出来。

其一段落我们来聊一下略带Http服务重回1个固定格式的数量的难点。 例如:

{
 "resultCode": 0,
 "resultMessage": "成功",
 "data": {}
}

多数的Http服务恐怕都以这么设置,resultCode和resultMessage的内容绝对相比较稳定,而data的剧情变化莫测,72变都不自然够变的,有可能是个User对象,也有只怕是个订单对象,还有可能是个订单列表。
依照大家前面包车型地铁用法,使用Gson转型要求大家在创建subscriber对象是钦命再次来到值类型,若是我们对差异的重返值进行李包裹装的话,那恐怕就要有广大个Entity了,望着鲜明是很清楚的构造,却因为data的不鲜明性无奈了起来。

豆蔻年华,不必烦恼,来来来~ 老衲赐你宝典葵花,老衲正是练了那个才出家。。。

我们得以创立1个HttpResult类

public class HttpResult<T> {
    private int resultCode;
    private String resultMessage;

    private T data;
}

如若data是二个User对象的话。那么在定义Service方法的再次来到值就能够写为

Observable<HttpResult<User>>

这样一来HttpResult就也便是1个包裹类,将结果包装了四起,可是在应用的时候要付出多少个领会的项目。

在下边包车型地铁言传身教中,笔者也创立了3个HttpResult类,用来模拟这几个情势,将个中的Subject单独封装了四起。

public class HttpResult<T> {

    //用来模仿resultCode和resultMessage
    private int count;
    private int start;
    private int total;
    private String title;

    //用来模仿Data
    private T subjects;
}

那般泛型的时候将要写为:

Observable<HttpResult<List<Subject>>>

如需查看项目代码 –> 代码地址:

https://github.com/tough1985/RxjavaRetrofitDemo

选择Tag -> step4

a、大家事先定义的Service再次回到值就由Call变为Observable了。

3.同一格式的Http请求数据统一实行预处理

既是大家有了同样的回到格式,那么我们只怕就须求在获得多少之后进展三个联合的预处理。

当接过到了二个Http请求结果今后,由于重返的构造统一为

{
 "resultCode": 0,
 "resultMessage": "成功",
 "data": {}
}

我们想要对resultCoderesultMessage先做3个判断,因为假使resultCode == 0代表success,那么resultCode != 0data一般都以null

Activity或Fragment对resultCoderesultMessage主导没有兴趣,他们只对呼吁状态data数量感兴趣。

根据那种考虑,大家在resultCode != 0的时候,抛出个自定义的ApiException。那样就会进去到subscriber的onError中,大家得以在onError中处理错误音讯。

除此以外,请求成功时,须求将data数据转换为对象数据类型传递给subscriber,因为,Activity和Fragment只想获得和她们真正相关的多寡。

运用Observable的map方法能够成功这一功力。

HttpMethods中成立二个里头类HttpResultFunc,代码如下:

/**
 * 用来统一处理Http的resultCode,并将HttpResult的Data部分剥离出来返回给subscriber
 *
 * @param <T> Subscriber真正需要的数据类型,也就是Data部分的数据类型
 */
private class HttpResultFunc<T> implements Func1<HttpResult<T>, T>{

    @Override
    public T call(HttpResult<T> httpResult) {
        if (httpResult.getResultCode() != 0) {
            throw new ApiException(httpResult.getResultCode());
        }
        return httpResult.getData();
    }
}

接下来我们的getTopMovie方法改为:

public void getTopMovie(Subscriber<List<Subject>> subscriber, int start, int count){

    movieService.getTopMovie(start, count)
            .map(new HttpResultFunc<List<Subject>>())
            .subscribeOn(Schedulers.io())
            .unsubscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(subscriber);
}

是因为HttpResult中的泛型T正是大家期待传递给subscriber的数据类型,而数据能够通过httpResult的getData方法获得,那样我们就处理了泛型难点,错误处理难题,还有将呼吁数据部分剥离出去给subscriber

那般我们只须求关爱Data数据的项目,而不必在关切整个进度了。

亟待专注一点,便是在定义Service的时候,泛型是

HttpResult<User>
//or
HttpResult<List<Subject>>

而在定义Subscriber的时候泛型是 java User //or List<Subject>

要不你会拿走二个转型错误。

如需查看项目代码 –> 代码地址:

https://github.com/tough1985/RxjavaRetrofitDemo

选择Tag -> step5

代码中本身是用豆类数据模拟了HttpResult中的resultCode和resultMessage,与文书档案中的代码略有出入。

b、然后成立接口Movie瑟维斯:

4.2 为啥会涉嫌Oberver

事关Observer的历程是如此的。由于Subscriber一旦调用了unsubscribe方法之后,就向来不用了。且当事件传递到onError或然onCompleted之后,也会活动的解绑。那样出现的二个标题便是每回发送请求都要创设新的Subscriber对象。

如此大家就把注意力放到了Observer,Observer自己是三个接口,他的表征是不管你怎么用,都不会解绑,为何吧?因为他从没解绑的法门。所以就达到了复用的效益,一初始自作者一直喜欢的用Observer。事实上,若是你用的是Observer,在调用Observable对象的subscribe方法的时候,会自动的将Observer对象转换到Subscriber对象。

上面是源码:

public final Subscription subscribe(final Observer<? super T> observer) {
    if (observer instanceof Subscriber) {
        return subscribe((Subscriber<? super T>)observer);
    }
    return subscribe(new Subscriber<T>() {

        @Override
        public void onCompleted() {
            observer.onCompleted();
        }

        @Override
        public void onError(Throwable e) {
            observer.onError(e);
        }

        @Override
        public void onNext(T t) {
            observer.onNext(t);
        }

    });
}

新生发觉了难题,

难点1 无法撤销,因为Observer没有unsubscribe方法 难点2 没有onStart方法
这一个一会聊

那多个难点是很痛楚的。所以,为了前面更好的高潮,大家依然选用用Subscriber。

从上边我们理解Retrofit会把重临的json对象映射为大家须求的java对象,大家的施用中必定会用到广大网络接口,大家前些天是呼吁的影视列表,我们还会呈请电影详情,歌手详情等等,那我们就供给定义MovieDetail、Actor等等Entity。难题是我们的服务普通会给我们回来3个稳住样式的数目,形如:

5.二个内需ProgressDialog的Subscriber该片段样子

咱俩盼望有二个Subscriber在我们每趟发送请求的时候能够弹出四个ProgressDialog,然后在伏乞接受的时候让那些ProgressDialog消失,同时在大家打消以此ProgressDialog的还要能够撤除当前的请求,而小编辈只必要处理内部的数目就能够了。

我们先来创设四个类,就叫ProgressSubscriber,让她继续Subscriber

Subscriber给大家提供了onStart、onNext、onError、onCompleted多个点子。

当中只有onNext方法再次来到了数码,那大家自然期待能够在onNext里面处理数据相关的逻辑。

onStart措施我们用来运营八个ProgressDialog。 onError方法大家集中处理错误,同时也停下ProgressDialog onComplated措施里面截至ProgressDialog

个中大家需求缓解三个难点

难点1 onNext的拍卖 问题2 cancel掉三个ProgressDialog的时候打消请求

咱俩先来缓解难题1

考虑到一般列表的数码都会有分页音信,大家还是可以够持续封装:

5.2处理ProgressDialog

作者们盼望当cancel掉ProgressDialog的时候,能够撤废订阅,也就撤废了近期的Http请求。
所以大家先来创制个接口来拍卖那件事情。

public interface ProgressCancelListener {
    void onCancelProgress();
}

下一场大家用ProgressSubscriber来落成这一个接口,这样ProgressSubscriber就有了一个onCancelProgress方法,在那其间打消订阅。

@Override
public void onCancelProgress() {
    if (!this.isUnsubscribed()) {
        this.unsubscribe();
    }
}

然后作者用了三个Handler来封装了ProgressDialog。

public class ProgressDialogHandler extends Handler {

    public static final int SHOW_PROGRESS_DIALOG = 1;
    public static final int DISMISS_PROGRESS_DIALOG = 2;

    private ProgressDialog pd;

    private Context context;
    private boolean cancelable;
    private ProgressCancelListener mProgressCancelListener;

    public ProgressDialogHandler(Context context, ProgressCancelListener mProgressCancelListener,
                                 boolean cancelable) {
        super();
        this.context = context;
        this.mProgressCancelListener = mProgressCancelListener;
        this.cancelable = cancelable;
    }

    private void initProgressDialog(){
        if (pd == null) {
            pd = new ProgressDialog(context);

            pd.setCancelable(cancelable);

            if (cancelable) {
                pd.setOnCancelListener(new DialogInterface.OnCancelListener() {
                    @Override
                    public void onCancel(DialogInterface dialogInterface) {
                        mProgressCancelListener.onCancelProgress();
                    }
                });
            }

            if (!pd.isShowing()) {
                pd.show();
            }
        }
    }

    private void dismissProgressDialog(){
        if (pd != null) {
            pd.dismiss();
            pd = null;
        }
    }

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case SHOW_PROGRESS_DIALOG:
                initProgressDialog();

那么电影列表,就必要如此写了:

1.3 添加Rxjava

Retrofit本人对Tiggoxjava提供了支撑。

添加Retrofit对途睿欧xjava的支撑必要在Gradle文本中添加

compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'

自然大家曾经添加过了。

接下来在创制Retrofit的长河中添加如下代码:

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(baseUrl)
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .build();

那样一来大家定义的service重返值就不在是3个Call了,而是一个Observable

重新定义MovieService

public interface MovieService {
    @GET("top250")
    Observable<MovieEntity> getTopMovie(@Query("start") int start, @Query("count") int count);
}

getMovie艺术改为:

//进行网络请求
private void getMovie(){
    String baseUrl = "https://api.douban.com/v2/movie/";

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(baseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
            .build();

    MovieService movieService = retrofit.create(MovieService.class);

    movieService.getTopMovie(0, 10)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Subscriber<MovieEntity>() {
                @Override
                public void onCompleted() {
                    Toast.makeText(MainActivity.this, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onError(Throwable e) {
                    resultTV.setText(e.getMessage());
                }

                @Override
                public void onNext(MovieEntity movieEntity) {
                    resultTV.setText(movieEntity.toString());
                }
            });
}

那样基本上就成功了Retrofit和PRADOxjava的结缘,可是我晓得你们当然不会满足的。

接下去大家把成立Retrofit的经过封装一下,然后希望Activity成立Subscriber指标传进来。

如需查看项目代码 –> 代码地址:

https://github.com/tough1985/RxjavaRetrofitDemo

选择Tag -> step2

而且大家普通会先去看清resultCode,以便能够统一处理错误音讯。至于data中的结构,则是转变的,它能够是影视列表Movies,也足以是明星新闻Actor,那么此时大家就会想起使用泛型来进展包装:

1.1 基本页面

先扔出build.gradle文本的情节

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.2.0'
    compile 'io.reactivex:rxjava:1.1.0'
    compile 'io.reactivex:rxandroid:1.1.0'
    compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
    compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
    compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'
    compile 'com.google.code.gson:gson:2.6.2'
    compile 'com.jakewharton:butterknife:7.0.1'
}

也正是说本文是基于帕JeroxJava1.1.0和Retrofit 2.0.0-beta4来拓展的。
添加rxandroid是因为rxjava中的线程难题。

上边先搭建三个主导的页面,页面极粗略,先来看文件目录结构图片 1

activity_main.xml的代码如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".activity.MainActivity">

    <Button
        android:id="@+id/click_me_BN"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:padding="5dp"
        android:text="点我"
        android:textSize="16sp"/>
    <TextView
        android:id="@+id/result_TV"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@id/click_me_BN"
        android:text="Hello World!"
        android:textSize="16sp"/>
</RelativeLayout>

MainActivity.java的代码如下:

package com.queen.rxjavaretrofitdemo.activity;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.Button;
import android.widget.TextView;

import com.queen.rxjavaretrofitdemo.R;

import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;

public class MainActivity extends AppCompatActivity {

    @Bind(R.id.click_me_BN)
    Button clickMeBN;
    @Bind(R.id.result_TV)
    TextView resultTV;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
    }

    @OnClick(R.id.click_me_BN)
    public void onClick() {
        getMovie();
    }

    //进行网络请求
    private void getMovie(){

    }
}

注意不要遗忘加网络权限

<uses-permission android:name="android.permission.INTERNET"/>
observable<HttpResult<Actor>>

前言

福特ExplorerxJava和Retrofit也火了一段时间了,可是近日一直在上学ReactNative和Node相关的架子,向来尚马时间商讨那几个新东西,近期有个连串准备写,打算先用Android写3个德姆o出来,却发现Android的世界产生了不安的转移,EventBus和OKHttp啥的都不翼而飞了,SportagexJava和Retrofit是什么鬼?

好呢,到Github上耐着个性看过了OdysseyxJava和Retrofit的介绍和多少个德姆o,原来Android的大神Jake
Wharton为Retrofit这些体系贡献了那样多的代码,没有道理不用了。

假如您对本田CR-VxJava目生请先看给 Android 开发者的 宝马X3xJava
详解
那篇小说。

纵然您对Retrofit不熟谙就先看Retrofit官网

当然也有很多卡宴xJava与Retrofit的稿子,不过我以为很多豪门都很纠结的功用都没有被总结出来,所以才有了此篇小说。

欢迎咱们拍砖。

接下去进入正文,小编是从下边多少个角度去思想冠道xJava与Retrofit结合的。

  1. RxJava如何与Retrofit结合
  2. 平等格式的Http请求数据该怎么封装
  3. 如出一辙格式的Http请求数据统一进行预处理
  4. 如何撤废贰个Http请求 — 观察者之间的对决,Oberver VS Subscriber
  5. 贰个内需ProgressDialog的Subscriber该部分样子
observable<HttpResult<HttpResList<List<Movie>>>>

1.RxJava如何与Retrofit结合

b、把请求的进度封装到HttpMethods类里面,

4.1 撤销四个Http请求

这一部分我们来聊一下关于撤除Http请求的工作,已经Oberver和Subscriber那多少个体位我们哪个更便于给大家G点。

比方没有选用路虎极光xjava,那么Service重返的是1个Call,而那一个Call对象有2个cancel方法能够用来撤销Http请求。那么用了RAV4xjava之后,如何来废除几个请求呢?因为再次回到值是2个Observable。大家能做的就好像唯有排除对Observable对象的订阅,其余的什么也做不了。

万幸Retrofit已经帮我们考虑到了那或多或少。
答案在福睿斯xJavaCallAdapterFactory这几个类的源码中可以找到

static final class CallOnSubscribe<T> implements Observable.OnSubscribe<Response<T>> {
  private final Call<T> originalCall;

  CallOnSubscribe(Call<T> originalCall) {
    this.originalCall = originalCall;
  }

  @Override public void call(final Subscriber<? super Response<T>> subscriber) {
    // Since Call is a one-shot type, clone it for each new subscriber.
    final Call<T> call = originalCall.clone();

    // Attempt to cancel the call if it is still in-flight on unsubscription.
    subscriber.add(Subscriptions.create(new Action0() {
      @Override public void call() {
        call.cancel();
      }
    }));

    try {
      Response<T> response = call.execute();
      if (!subscriber.isUnsubscribed()) {
        subscriber.onNext(response);
      }
    } catch (Throwable t) {
      Exceptions.throwIfFatal(t);
      if (!subscriber.isUnsubscribed()) {
        subscriber.onError(t);
      }
      return;
    }

    if (!subscriber.isUnsubscribed()) {
      subscriber.onCompleted();
    }
  }
}

我们看看call方法中,给subscriber添加了二个Subscription对象,Subscription对象很简短,主要正是裁撤订阅用的,假如你查看Subscriptions.create的源码,发现是这般的

public static Subscription create(final Action0 unsubscribe) {
  return BooleanSubscription.create(unsubscribe);
}

使用了一个BooleanSubscription类来创设3个Subscription,假如您点进去看BooleanSubscription.create方法漫天就清楚了,当接触绑定的时候,subscriber会调用Subscription的unsubscribe方法,然后触发创建Subscription时候的传递进入的Action0的call方法。劲客xJavaCall艾达pterFactory帮大家给subscriber添加的是call.cancel(),

小结起来正是,大家在Activity大概Fragment中创建subscriber对象,想要打消请求的时候调用subscriber的unsubscribe方法就足以了。

抱歉这一节有太多的SubscriberSubscription以及ObserverObservable,老衲当时看的时候也是不清楚吐了多少次了,习惯了就好了。

即使data是影视列表,那么大家得以如此写:

{
 "resultCode": 1,
 "resultMsg": "成功",
 "data": {}
}

** 壹 、使用Retrofit来进展互联网请求 **

   private void getMovie() {
        subscriber = new Subscriber<MovieEntity>() {
            @Override
            public void onCompleted() {
                Toast.makeText(MainActivity.this, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onError(Throwable e) {
                resultTV.setText(e.getMessage());
            }

            @Override
            public void onNext(MovieEntity movieEntity) {
                /** 这里得到的请求结果直接是我们想要的java对象 **/
                resultTV.setText(movieEntity.toString());
            }
        };
        HttpMethods.getInstance().getTopMovie(subscriber, 0, 10);
    }

借使data是Actor对象的话,那么定义Service方法再次来到值就能够写成:

a、网络接口使用豆瓣电影的top250,大家依照它回到的json格式封装为四个MovieEntity。

public class HttpMethods {
    public static final String BASE_URL = "https://api.douban.com/v2/movie/";
    private static final int DEFAULT_TIMEOUT = 5;

    private Retrofit retrofit;
    private MovieService movieService;

    //构造方法私有
    private HttpMethods() {
        //手动创建一个OkHttpClient并设置超时时间
        OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
        httpClientBuilder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);

        retrofit = new Retrofit.Builder()
                .client(httpClientBuilder.build())
                .addConverterFactory(GsonConverterFactory.create())
                //此处添加RxJavaCallAdapterFactory,把请求结果直接映射为
                //MovieService接口方法返回的具体类型MovieEntity
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(BASE_URL)
                .build();

        movieService = retrofit.create(MovieService.class);
    }

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

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

    /**
     * 用于获取豆瓣电影Top250的数据
     * @param subscriber  由调用者传过来的观察者对象
     * @param start 起始位置
     * @param count 获取长度
     */
    public void getTopMovie(Subscriber<MovieEntity> subscriber, int start, int count){
        movieService.getTopMovie(start, count)
                //指定subscribe()发生在io调度器(读写文件、读写数据库、网络信息交互等)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                //指定subscriber的回调发生在主线程
                .observeOn(AndroidSchedulers.mainThread())
                //实现订阅关系
                .subscribe(subscriber);
    }
}

事实上,笔者间接有个怀疑,为啥要用帕杰罗xjava呢?没来看代码简洁、好用啊,是呀,Why?请移步
煮 Retrofit 论 RxJava(二)

那就是说封装为泛型后的代码跟上边包车型客车相距十分的小,只是把Observable相关的参数或重返类型由MovieEntity改为HttpResult<List<Movie>>(注意,咱们所采用的测试接口跟大家上述钻探的组织有出入),全体就不再贴出代码。

c、那么getMovie()方法直接调用封装过的getTopMovie()即可。从中,大家看看选用中华Vxjava带来两点变化:3个是将请求封装进Observable;其余是因此兑现Subscriber中的三个接口方法来打招呼请求状态(即UI更新)。

转发请标明出处:http://www.jianshu.com/p/86cf7de684b3

** 贰 、添加本田UR-Vxjava并对请求进度实行封装 **

https://api.douban.com/v2/movie/top250?start=0&count=10
public interface MovieService {
    /** 返回的Observable正是被观察者,我们用来通知观察者对象(这里我们通知UI更新) **/
    @GET("top250")
    Observable<MovieEntity> getTopMovie(@Query("start") int start, @Query("count") int count);
}
/** 支持分页的json结构 **/
{
 "start": 0,
 "count": 20,
 "total": 250
 "list": []
}
/** 封装后带分页的泛型对象 **/
public class HttpResList<T> {
    private int start;
    private int count;
    private int total;
    private T list;
}

c、接着,在界面中应用Retrofit进行互连网请求:

public interface MovieService {
    /** 以Get方法访问接口,参数start和count分别是对接口地址的传参 **/
    @GET("top250")
    Call<MovieEntity> getTopMovie(@Query("start") int start, @Query("count") int count);
}

相关文章