Android RxJava和改造

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。

  • Making a Retrofit call using RxJava.

    使用RxJava进行翻新调用。
  • Doing Multiple Retrofit Calls Using RxJava

    使用RxJava进行多个改造调用
  • Transforming the Retrofit POJO response using RxJava

    使用RxJava转换Retrofit POJO响应

We’ll be using Java 8 in our Android Application to unleash lambda expressions.

我们将在Android应用程序中使用Java 8释放lambda表达式。

总览 (Overview)

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中的调度程序负责使用不同的线程执行操作。
RxAndroidRxJava的扩展,它包含要在Android环境中使用的Android线程。

To use RxJava in retrofit environment we need to do just two major changes:

要在改造环境中使用RxJava,我们只需做两个主要更改:

  • Add the RxJava in Retrofit Builder.

    在Retrofit Builder中添加RxJava。
  • Use 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运算符 。
让我们看看下面的示例应用程序是如何完成的。

项目结构 (Project Structure)

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'

(Code)

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的魔力,我们将在该字段上设置一个值以转换响应。

使用RxJava创建单个呼叫 (Creating a Single Call Using 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线程,通过该线程进行网络调用。
我们可以在其中传递以下任何调度程序。

  • trampoline(): This runs the tasks on the current thread. So it’ll run your code after the current task on the thread is complete. Useful for queueing operations.

    trampoline():这将在当前线程上运行任务。 因此,它将在线程上的当前任务完成后运行您的代码。 对排队操作很有用。
  • newThread(): Creates and returns a Scheduler that creates a new Thread for each unit of work. This is costly since it creates a separate thread everytime.

    newThread():创建并返回一个Scheduler,该Scheduler为每个工作单元创建一个新的Thread。 这是昂贵的,因为它每次都会创建一个单独的线程。
  • computation(): Creates and returns a Scheduler intended for computational work. This should be used for parallel work since the thread pool is bound. I/O operations shouldn’t be done here.

    Calculation():创建并返回一个用于计算工作的Scheduler。 由于线程池已绑定,因此应将其用于并行工作。 I / O操作不应该在这里完成。
  • io(): Creates and returns a Scheduler intended for IO-bound work. Again it’s bounded like computation. Typically this is used for network calls.

    io():创建并返回用于IO绑定工作的Scheduler。 再次,它的边界像计算一样。 通常,这用于网络呼叫。
subscribeOn() vs observeOn() subscriptionOn()与observeOn()
  • subscribeOn works downstream and upstream. All the tasks above and below it would use the same thread.

    subscriptionOn在下游和上游工作。 它上面和下面的所有任务都将使用同一线程。
  • observeOn works downstream only.

    watchOn仅在下游工作。
  • consecutive subscribeOn methods won’t change the thread. Only the first subscribeOn thread would be used.

    连续的subscriptionOn方法不会更改线程。 仅使用第一个subscriptionOn线程。
  • consecutive observeOn methods will change the thread.

    连续的observeOn方法将更改线程。
  • After an observeOn(), putting a subscribeOn() won’t change the thread. Hence observeOn should generally come after a subscribeOn.

    经过observeOn()之后,放置subscribeOn()不会更改线程。 因此,observeOn通常应在subscribeOn之后。

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方法中获取数据的方法,我们将很快看到。

多个通话 (Multiple Calls)

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);

转变回应 (Transforming the Response)

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流。

MainActivity.java (MainActivity.java)

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.

handleResultshandleError使用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项目。

RxJavaRetrofit RxJava改造

翻译自: https://www.journaldev.com/20433/android-rxjava-retrofit

你可能感兴趣的:(android,java,android,studio,app,安卓)