In this tutorial, we’ll be implementing Retrofit calls using RxJava in android app. We’ll be creating an application that populates a RecyclerView using Retrofit and RxJava. We’ll be using a CryptoCurrency API.
在本教程中,我们将在Android应用中使用RxJava实现Retrofit调用。 我们将创建一个使用Retrofit和RxJava填充RecyclerView的应用程序。 我们将使用CryptoCurrency API。
We’ll be using Java 8 in our Android Application to unleash lambda expressions.
我们将在Android应用程序中使用Java 8释放lambda表达式。
Retrofit is a REST client that uses OkHttp as the HttpClient and JSON Parsers to parse the response.
We’ll use gson as the JSON Parser here.
This is how a Retrofit instance is created:
Retrofit是一个REST客户端,它使用OkHttp作为HttpClient和JSON解析器来解析响应。
在这里,我们将gson用作JSON解析器。
这是创建Retrofit实例的方式:
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
Gson gson = new GsonBuilder()
.setLenient()
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
HttpLoggingInterceptor is used to log the data during the network call.
HttpLoggingInterceptor用于在网络调用期间记录数据。
RxJava is a library that is used for asynchronous and reactive programming in the form of streams.
We use different threads in RxJava. A background thread for the network call and the main thread for updating the UI.
Schedulers in RxJava is responsible for performing operations using different threads.
RxAndroid is an extension of RxJava and it contains the Android threads to be used in the Android Environment.
RxJava是一个用于以流形式进行异步和React式编程的库。
我们在RxJava中使用不同的线程。 网络调用的后台线程和用于更新UI的主线程。
RxJava中的调度程序负责使用不同的线程执行操作。
RxAndroid是RxJava的扩展,它包含要在Android环境中使用的Android线程。
To use RxJava in retrofit environment we need to do just two major changes:
要在改造环境中使用RxJava,我们只需做两个主要更改:
Observable
type in the interface instead of Call
在界面中使用Observable
类型代替Call
To do multiple calls or transform the response, we use RxJava operators.
Let’s see how it’s done through our sample application below.
为了进行多次调用或转换响应,我们使用RxJava运算符 。
让我们看看下面的示例应用程序是如何完成的。
Add the following dependencies in our build.gradle file:
在我们的build.gradle文件中添加以下依赖项:
implementation 'com.android.support:cardview-v7:27.1.0'
implementation 'com.android.support:design:27.1.0'
implementation('com.squareup.retrofit2:retrofit:2.3.0')
{
exclude module: 'okhttp'
}
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
implementation 'io.reactivex.rxjava2:rxjava:2.1.9'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
implementation 'com.squareup.okhttp3:logging-interceptor:3.9.1'
The code for the layout activity_main.xml is given below.
下面给出了布局activity_main.xml的代码。
The code for the CryptocurrencyService.java
class is given below.
下面给出了CryptocurrencyService.java
类的代码。
package com.journaldev.rxjavaretrofit;
import com.journaldev.rxjavaretrofit.pojo.Crypto;
import io.reactivex.Observable;
import retrofit2.http.GET;
import retrofit2.http.Path;
public interface CryptocurrencyService {
String BASE_URL = "https://api.cryptonator.com/api/full/";
@GET("{coin}-usd")
Observable getCoinData(@Path("coin") String coin);
}
@Path passes in the path we specify into the curly braces.
Note: The @Path parameter name must match with the one in the @GET.
@Path将我们指定的路径传递到花括号中。
注意 :@Path参数名称必须与@GET中的名称匹配。
The POJO class Crypto.java
is given below:
POJO类Crypto.java
给出如下:
package com.journaldev.rxjavaretrofit.pojo;
import com.google.gson.annotations.SerializedName;
import java.util.List;
public class Crypto {
@SerializedName("ticker")
public Ticker ticker;
@SerializedName("timestamp")
public Integer timestamp;
@SerializedName("success")
public Boolean success;
@SerializedName("error")
public String error;
public class Market {
@SerializedName("market")
public String market;
@SerializedName("price")
public String price;
@SerializedName("volume")
public Float volume;
public String coinName;
}
public class Ticker {
@SerializedName("base")
public String base;
@SerializedName("target")
public String target;
@SerializedName("price")
public String price;
@SerializedName("volume")
public String volume;
@SerializedName("change")
public String change;
@SerializedName("markets")
public List markets = null;
}
}
coinName
is a field we’ve set. Using the magic of RxJava we’ll set a value on this field to transform the response.
coinName
是我们设置的字段。 使用RxJava的魔力,我们将在该字段上设置一个值以转换响应。
CryptocurrencyService cryptocurrencyService = retrofit.create(CryptocurrencyService.class);
Observable cryptoObservable = cryptocurrencyService.getCoinData("btc");
cryptoObservable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map(result -> result.ticker)
.subscribe(this::handleResults, this::handleError);
subscribeOn()
creates a Scheduler thread over which we do the network call.
We can pass any of the following Schedulers in it.
subscribeOn()
创建一个Scheduler线程,通过该线程进行网络调用。
我们可以在其中传递以下任何调度程序。
AndroidSchedulers.mainThread()
is a part of RxAndroid and is used to observe the data on the main thread only.
AndroidSchedulers.mainThread()
是RxAndroid的一部分,仅用于观察主线程上的数据。
subscribe method is what triggers the retrofit call and gets the data in the method handleResults
which we’ll see shortly.
subscription方法是触发改造调用并在handleResults
方法中获取数据的方法,我们将很快看到。
We use the RxJava operator merge
to do two retrofit calls one after the other.
我们使用RxJava运算符merge
一次接连进行两次改造。
Observable> btcObservable = cryptocurrencyService.getCoinData("btc");
Observable> ethObservable = cryptocurrencyService.getCoinData("eth");
Observable.merge(btcObservable, ethObservable)
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::handleResults, this::handleError);
To transform the POJO response we can do the following:
要转换POJO响应,我们可以执行以下操作:
Observable> btcObservable = cryptocurrencyService.getCoinData("btc")
.map(result -> Observable.fromIterable(result.ticker.markets))
.flatMap(x -> x).filter(y -> {
y.coinName = "btc";
return true;
}).toList().toObservable();
Observable> ethObservable = cryptocurrencyService.getCoinData("eth")
.map(result -> Observable.fromIterable(result.ticker.markets))
.flatMap(x -> x).filter(y -> {
y.coinName = "eth";
return true;
}).toList().toObservable();
Observable.merge(btcObservable, ethObservable)
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::handleResults, this::handleError);
We use Observable.fromIterable
to convert the the map result into Observable streams.
flatMap
works on the elements one by one. Thus converting the ArrayList to single singular elements.
In the filter
method we change the response.
toList()
is used to convert the results of flatMap back into a List.
toObservable()
wraps them as Observable streams.
我们使用Observable.fromIterable
将地图结果转换为Observable流。
flatMap
逐一处理元素。 因此将ArrayList转换为单个奇异元素。
在filter
方法中,我们更改响应。
toList()
用于将flatMap的结果转换回List。
toObservable()
将它们包装为Observable流。
The code for the MainActivity.java class is given below:
MainActivity.java类的代码如下:
package com.journaldev.rxjavaretrofit;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.widget.Toast;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.journaldev.rxjavaretrofit.pojo.Crypto;
import java.util.List;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import static com.journaldev.rxjavaretrofit.CryptocurrencyService.BASE_URL;
public class MainActivity extends AppCompatActivity {
RecyclerView recyclerView;
Retrofit retrofit;
RecyclerViewAdapter recyclerViewAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerViewAdapter = new RecyclerViewAdapter();
recyclerView.setAdapter(recyclerViewAdapter);
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
Gson gson = new GsonBuilder()
.setLenient()
.create();
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
callEndpoints();
}
private void callEndpoints() {
CryptocurrencyService cryptocurrencyService = retrofit.create(CryptocurrencyService.class);
//Single call
/*Observable cryptoObservable = cryptocurrencyService.getCoinData("btc");
cryptoObservable.subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread()).map(result -> result.ticker).subscribe(this::handleResults, this::handleError);*/
Observable> btcObservable = cryptocurrencyService.getCoinData("btc")
.map(result -> Observable.fromIterable(result.ticker.markets))
.flatMap(x -> x).filter(y -> {
y.coinName = "btc";
return true;
}).toList().toObservable();
Observable> ethObservable = cryptocurrencyService.getCoinData("eth")
.map(result -> Observable.fromIterable(result.ticker.markets))
.flatMap(x -> x).filter(y -> {
y.coinName = "eth";
return true;
}).toList().toObservable();
Observable.merge(btcObservable, ethObservable)
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::handleResults, this::handleError);
}
private void handleResults(List marketList) {
if (marketList != null && marketList.size() != 0) {
recyclerViewAdapter.setData(marketList);
} else {
Toast.makeText(this, "NO RESULTS FOUND",
Toast.LENGTH_LONG).show();
}
}
private void handleError(Throwable t) {
Toast.makeText(this, "ERROR IN FETCHING API RESPONSE. Try again",
Toast.LENGTH_LONG).show();
}
}
handleResults
and handleError
are invoked using the Java 8 invocation ::
In the handlResults we set the converted response on the ReyclerViewAdapter.
handleError() is invoked if the response has an error.
handleResults
和handleError
使用Java 8调用::
在handlResults中,我们在ReyclerViewAdapter上设置转换后的响应。
如果响应有错误,则调用handleError()。
The code for the recyclerview_item_layout layout is given below.
下面给出了recyclerview_item_layout布局的代码。
The code for the RecyclerViewAdapter.java class is given below:
下面给出了RecyclerViewAdapter.java类的代码:
package com.journaldev.rxjavaretrofit;
import android.graphics.Color;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.journaldev.rxjavaretrofit.pojo.Crypto;
import java.util.ArrayList;
import java.util.List;
public class RecyclerViewAdapter extends RecyclerView.Adapter {
private List marketList;
public RecyclerViewAdapter() {
marketList = new ArrayList<>();
}
@Override
public RecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_item_layout, parent, false);
RecyclerViewAdapter.ViewHolder viewHolder = new RecyclerViewAdapter.ViewHolder(view);
return viewHolder;
}
@Override
public void onBindViewHolder(RecyclerViewAdapter.ViewHolder holder, int position) {
Crypto.Market market = marketList.get(position);
holder.txtCoin.setText(market.coinName);
holder.txtMarket.setText(market.market);
holder.txtPrice.setText("$" + String.format("%.2f", Double.parseDouble(market.price)));
if (market.coinName.equalsIgnoreCase("eth")) {
holder.cardView.setCardBackgroundColor(Color.GRAY);
} else {
holder.cardView.setCardBackgroundColor(Color.GREEN);
}
}
@Override
public int getItemCount() {
return marketList.size();
}
public void setData(List data) {
this.marketList.addAll(data);
notifyDataSetChanged();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView txtCoin;
public TextView txtMarket;
public TextView txtPrice;
public CardView cardView;
public ViewHolder(View view) {
super(view);
txtCoin = view.findViewById(R.id.txtCoin);
txtMarket = view.findViewById(R.id.txtMarket);
txtPrice = view.findViewById(R.id.txtPrice);
cardView = view.findViewById(R.id.cardView);
}
}
}
The output of the above application in action is given below:
上面应用程序的输出如下:
The above output merges the results of the Bitcoin and Ethereum market prices done through retrofit.
以上输出合并了通过改造完成的比特币和以太坊市场价格的结果。
This brings an end to this tutorial. You can download the Android RxJavaRetrofit Project from the link below.
本教程到此结束。 您可以从下面的链接下载Android RxJavaRetrofit项目。
翻译自: https://www.journaldev.com/20433/android-rxjava-retrofit