GithubDemo

#####Introduction GithubDemo showcases the use of Square's Retrofit and RxJava to make asynchronous HTTP Requests in Android Application. The App makes HTTP GET requests to the Github API to retrieve public repo count and blog URL.

The FETCH button kicks off a series of HTTP requests to Github API. The HTTP requests are built via Retrofit. The calls are made asynchronously through RxJava. Notice that the cards are laid out in different order each time the button is pressed. You are seeing async threading at work! Each card is rendered when the result comes back from a GET request.

alt tag

See my blog post for the full story: [http://randomdotnext.com/retrofit-rxjava/]

#####The Setup Let's take care of the depency injection for retrofit and RxJava/RxAndroid:

dependencies {
    compile 'io.reactivex:rxjava:1.0.+'
    compile 'io.reactivex:rxandroid:0.23.+'
    compile 'com.squareup.retrofit:retrofit:1.9.+'
}

Don't forget Android App Permissions in AndroidManifest:

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

#####Retrofit Service/Model Retrofit uses a Java interface as proxy for the REST API calls. All we have to do is to define the @GET method and the url/path. The following code makes a GET request to the Github URL and returns an Observable. The Observable object is used by RxJava to do stream processing (I'll explain this later).

public interface GithubService {
    String SERVICE_ENDPOINT = "https://api.github.com";
    //note: you don't need to define this URL String here

    @GET("/users/{login}")
    Observable<Github> getUser(@Path("login") String login);
}

Hang on! GithubService needs a RestAdapter implementation. In the spirit of good programming practice, I created a generic factory class to do the implementation:

static <T> T createRetrofitService(final Class<T> clazz, final String endPoint) {
    final RestAdapter restAdapter = new RestAdapter.Builder()
            .setEndpoint(endPoint)
            .build();
    T service = restAdapter.create(clazz);

    return service;
}

The Github REST API returns the following JSON. You can try it yourself! curl https://api.github.com/users/linkedin

{
  "login": "linkedin",
  "blog": "http://engineering.linkedin.com",
  "public_repos": 73,
  //...truncated JSON
}

We will define the model in a separate Java file. The field variables in the model are automatically parsed from the JSON response. So you don't need to worry about writing the parsing code. Make sure that the variable names are exactly the same as API definition:

public class Github {
    private String login;
    private String blog;
    private int public_repos;

    public String getLogin() {
        return login;
    }

    public String getBlog() {
        return blog;
    }

    public int getPublicRepos() {
        return public_repos;
    }
}

And you are done! Other than Java's boilerplate stuff (boo), the code is very concise and readable. If you have more than one endpoint you want to access, simply add it to your service interface at little additional cost!

#####RxJava Async Stream The Observable object from our GithubService streams data when it becomes available. We need to have an Subscriber (sometimes called Observer) to watch for the data stream changes. Conceptually, the Subscriber subscribes to an Observable. The following block of code performs the entire process described.

GithubService service = ServiceFactory.createRetrofitService(GithubService.class, GithubService.SERVICE_ENDPOINT);
for(String login : Data.githubList) {
    service.getUser(login)
        .subscribeOn(Schedulers.newThread())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Subscriber<Github>() {
            @Override
            public final void onCompleted() {
                // do nothing
            }

            @Override
            public final void onError(Throwable e) {
                Log.e("GithubDemo", e.getMessage());
            }

            @Override
            public final void onNext(Github response) {
                mCardAdapter.addData(response);
            }
        });
}

That was probably a bit confusing. Let's break the code down line by line.

service.getUser(login)

GithubService Interface has the getUser method which returns an Observable. We are chaining method calls on this Observable to get the REST call response.

.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())

These two lines specify that the REST call will be made in a new thread (YES!). And when the call response returns, it call the onNext, onError, and onComplete methods on the mainThread. The reason we need to call them on the mainThread is that only the mainThread can update the UI. If you have data that do not need to be displayed immediately, you would not need to observe on main thread. The difference between observeOn and subscribeOn is best explained in this stackoverflow.

new Subscriber<Github>() {
    @Override
    public final void onCompleted() {
        // do nothing
    }

    @Override
    public final void onError(Throwable e) {
        Log.e("GithubDemo", e.getMessage());
    }

    @Override
    public final void onNext(Github response) {
        mCardAdapter.addData(response);
    }
}

This Subscriber responds to the Observable's stream. onNext is called when the REST call receives data. In this Github example, there is only 1 item, so it is only called once. When the REST response is a list, the code can be called each time an item is received. onComplete and onError behave exactly as the name implies.

#####We are done Viola! We have just made our non-blocking HTTP calls on Android. Special thanks to the folks at Square and ReactiveX for making our lives easier!


#####Reference: Code on github: [https://goo.gl/DGMF2F]
Square Retrofit Doc: [http://goo.gl/UwksBu]
RxJava Doc: [https://goo.gl/5AqMNi]
Github API: [https://goo.gl/7nsdh0]
CardView/RecycleView UI Reference: [http://goo.gl/stNj2J]


GithubDemo

#####简介 GithubDemo展示了使用Square的改版 RxJava 在Android应用程序中进行异步HTTP请求。该应用程序向 Github API 发出HTTP GET请求,以检索 public repo count 博客网址

FETCH按钮为Github API启动了一系列HTTP请求。 HTTP请求是通过Retrofit构建的。通过RxJava进行异步调用。请注意,每次按下按钮时,卡都将以不同的顺序排列。你在工作中看到异步线程当结果从GET请求返回时,会显示每张卡片。

alt

查看我的博客文章了解完整的故事:[ http://randomdotnext.com/retrofit-rxjava/ ] < / p>

#####安装程序 让我们来看看改装后的注射剂和RxJava / RxAndroid:

dependencies {
    compile 'io.reactivex:rxjava:1.0.+'
    compile 'io.reactivex:rxandroid:0.23.+'
    compile 'com.squareup.retrofit:retrofit:1.9.+'
}

不要忘记AndroidManifest中的Android应用权限:

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

#####改造服务/模型 Retrofit使用Java接口作为REST API调用的代理。我们所要做的就是定义@GET方法和url / path。以下代码向Github URL发出GET请求,并返回一个Observable。 RxJava使用Observable对象进行流处理(稍后我会解释一下)。

public interface GithubService {
    String SERVICE_ENDPOINT = "https://api.github.com";
    //note: you don't need to define this URL String here

<span class="pl-k">@GET</span>(<span class="pl-s"><span class="pl-pds">&#34;</span>/users/{login}<span class="pl-pds">&#34;</span></span>)
<span class="pl-k">Observable&lt;<span class="pl-smi">Github</span>&gt;</span> <span class="pl-en">getUser</span>(<span class="pl-k">@Path</span>(<span class="pl-s"><span class="pl-pds">&#34;</span>login<span class="pl-pds">&#34;</span></span>) <span class="pl-smi">String</span> <span class="pl-v">login</span>);

}

挂断! GithubService需要一个RestAdapter实现。本着良好的编程实践的精神,我创建了一个通用的工厂类来实现:

static <T> T createRetrofitService(final Class<T> clazz, final String endPoint) {
    final RestAdapter restAdapter = new RestAdapter.Builder()
            .setEndpoint(endPoint)
            .build();
    T service = restAdapter.create(clazz);

<span class="pl-k">return</span> service;

}

Github REST API返回以下JSON。你可以自己试试吧! curl https://api.github.com/users/linkedin

{
  "login": "linkedin",
  "blog": "http://engineering.linkedin.com",
  "public_repos": 73,
  //…truncated JSON
}

我们将在单独的Java文件中定义模型。模型中的字段变量将自动从JSON响应中解析出来。所以你不需要担心编写解析代码。请确保变量名与API定义完全相同:

public class Github {
    private String login;
    private String blog;
    private int public_repos;

<span class="pl-k">public</span> <span class="pl-smi">String</span> <span class="pl-en">getLogin</span>() {
    <span class="pl-k">return</span> login;
}

<span class="pl-k">public</span> <span class="pl-smi">String</span> <span class="pl-en">getBlog</span>() {
    <span class="pl-k">return</span> blog;
}

<span class="pl-k">public</span> <span class="pl-k">int</span> <span class="pl-en">getPublicRepos</span>() {
    <span class="pl-k">return</span> public_repos;
}

}

你已经完成了!除了Java的样板(boo)之外,代码非常简洁易读。如果您想要访问多个端点,只需少量额外的费用将其添加到您的服务界面中。

##### RxJava异步流 我们的GithubService中的可观察对象在数据变为可用时将流数据。我们需要一个订阅者(有时称为观察者)观察数据流的更改。在概念上,订阅者订阅了可观察。以下代码块执行所描述的整个过程。

GithubService service = ServiceFactory.createRetrofitService(GithubService.class, GithubService.SERVICE_ENDPOINT);
for(String login : Data.githubList) {
    service.getUser(login)
        .subscribeOn(Schedulers.newThread())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Subscriber<Github>() {
            @Override
            public final void onCompleted() {
                // do nothing
            }

        <span class="pl-k">@Override</span>
        <span class="pl-k">public</span> <span class="pl-k">final</span> <span class="pl-k">void</span> <span class="pl-en">onError</span>(<span class="pl-smi">Throwable</span> <span class="pl-v">e</span>) {
            <span class="pl-smi">Log</span><span class="pl-k">.</span>e(<span class="pl-s"><span class="pl-pds">&#34;</span>GithubDemo<span class="pl-pds">&#34;</span></span>, e<span class="pl-k">.</span>getMessage());
        }

        <span class="pl-k">@Override</span>
        <span class="pl-k">public</span> <span class="pl-k">final</span> <span class="pl-k">void</span> <span class="pl-en">onNext</span>(<span class="pl-smi">Github</span> <span class="pl-v">response</span>) {
            mCardAdapter<span class="pl-k">.</span>addData(response);
        }
    });

}

这可能有点混乱。让我们逐行分解代码。

service.getUser(login)

GithubService Interface具有返回Observable的getUser方法。我们正在链接方法调用此Observable获取REST调用响应。

.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())

这两行指定REST调用将在一个新线程(YES!)中进行。当调用响应返回时,它调用mainThread上的onNext,onError和onComplete方法。我们需要在mainThread上调用它们的原因是只有mainThread可以更新UI。如果您的数据不需要立即显示,则不需要在主线程上观察。在这个 stackoverflow 中最好地解释了ObserOn和subscribeOn之间的区别。 a>。

new Subscriber<Github>() {
    @Override
    public final void onCompleted() {
        // do nothing
    }

<span class="pl-k">@Override</span>
<span class="pl-k">public</span> <span class="pl-k">final</span> <span class="pl-k">void</span> <span class="pl-en">onError</span>(<span class="pl-smi">Throwable</span> <span class="pl-v">e</span>) {
    <span class="pl-smi">Log</span><span class="pl-k">.</span>e(<span class="pl-s"><span class="pl-pds">&#34;</span>GithubDemo<span class="pl-pds">&#34;</span></span>, e<span class="pl-k">.</span>getMessage());
}

<span class="pl-k">@Override</span>
<span class="pl-k">public</span> <span class="pl-k">final</span> <span class="pl-k">void</span> <span class="pl-en">onNext</span>(<span class="pl-smi">Github</span> <span class="pl-v">response</span>) {
    mCardAdapter<span class="pl-k">.</span>addData(response);
}

}

此订阅者响应Observable的流。当REST调用接收数据时调用onNext。在这个Github示例中,只有1个项目,所以它只被调用一次。当REST响应是列表时,每次收到一个项目时都可以调用该代码。 onComplete和onError的行为与名称一致。

#####我们完成了 中提琴!我们刚刚在Android上进行了非阻塞HTTP呼叫。特别感谢Square和ReactiveX的人们使我们的生活更轻松!


#####Reference: Code on github: [
https://goo.gl/DGMF2F]
Square Retrofit Doc: [http://goo.gl/UwksBu]
RxJava Doc: [https://goo.gl/5AqMNi]
Github API: [https://goo.gl/7nsdh0]
CardView/RecycleView UI Reference: [http://goo.gl/stNj2J]




相关问题推荐