First statement, this is my first blog learning Rxjava and Retrofit, is also the first time I write blog, the content can be the wrong place or I understand the wrong place, please more understanding, is so come over, if there is a very welcome to correct the wrong place, I will timely modify so as not to mislead others.

Usage scenarios

Continuous request in many App will often be used, for example by positioning the current positioning of the city weather forecast, we must first through the Android to provide us with Api calls GPS to obtain our current latitude and longitude, then transform longitude and latitude into specific city name, city name again to obtain the weather forecast in the request.

If such a requirement were to be implemented, the code structure would be messy and we would be trapped in endless callback hell, such as this:





QQ screenshots 20170220134407. PNG

This can be very confusing for both developers and maintainers, and we can solve this problem by introducing Rxjava+Retrofit and using chained structures to make the entire code block more readable and less likely to be scolded by anyone who takes over your project after you leave.

Give it a try

preparation

  • Latitude and longitude to city address Api: Since the Api provided by Google Maps is not available in China (or there may be a better way please advise), I found http://api.map.baidu.com/geocoder?location= latitude and longitude & output = output format type & key = the Api user keys to replace, pay attention to this Api to apply the key, This paper will provide a key: 6 eea93095ae93db2c77be9ac910ff311.

  • Weather forecast Api: Here I use heart to know the weather in baidu Api service provided by the interface, which I use the actual weather this service, specific interface Url for http://apis.baidu.com/thinkpage/weather_api_full/currentweather, Note here also need to apply for the key, here you need to apply for yourself.

  • Rxjava+Retrofit: Import from Gradle

      compile 'the IO. Reactivex: rxjava: 1.1.0'
      compile 'the 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'Copy the code

Ready to go

First of all, we need to prepare the entity class returned by the weather service and location service. This entity class needs to trouble you to request it. Here we recommend a small Chrome plug-in Postman (need to be over the wall) this tool can help you debug web pages or send HTTP requests. Generating entity classes automatically should be done without saying much about GsonFormat.

Now that we have the entity class, it’s time to create a Service for each request using Retrofit:

  • Location services:

    public interface LocationService {
      @GET("geocoder")
      Observable<LocationEntity> getLoation(
      @Query("location") String location, 
      @Query("output") String output,
      @Query("key") String key
      );
    }Copy the code
  • Weather service please replace the *** in the code with the APIKey you applied for

    public interface WeatherService {
      @Headers({"apikey:*********"})
      @GET("currentweather")
      Observable<WeatherEntity> getWeather(@Query("location") String city);
    }Copy the code

Next we instantiate the corresponding Retrofit object for each request and add Rxjava support:

public static final String WEATHER_URL = "http://apis.baidu.com/thinkpage/weather_api/";
public static final String LOCATION_URL ="http://api.map.baidu.com/";

Retrofit mRetrofitWeather;
Retrofit mRetrofitLocation;
WeatherService mWeatherService;
LocationService mLocationService;

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRetrofitWeather = new Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(WEATHER_URL)
                .build();
        mWeatherService = mRetrofitWeather.create(WeatherService.class);

        mRetrofitLocation = new Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(LOCATION_URL)
                .build();
        mLocationService = mRetrofitLocation.create(LocationService.class);
  }Copy the code

This is where we get to, using the very rich operators that Rxjava provides for us to do this continuous request. To make it clear that I did the request in the click event

public void getWeather(a){
     mLocationService.getLoation("31.407452, 119.490523,"."json"."6eea93095ae93db2c77be9ac910ff311")
     .flatMap(new Func1<LocationEntity, Observable<WeatherEntity>>() {
           @Override
           public Observable<WeatherEntity> call(LocationEntity locationEntity) {
               return mWeatherService.getWeather(locationEntity.getResult().getAddressComponent().getCity());
           }
     }).map(new Func1<WeatherEntity, String>() {
           @Override
           public String call(WeatherEntity weatherEntity) {
                String text = weatherEntity.getResults().get(0).getLocation().getName() + ":" + weatherEntity.getResults().get(0).getNow().getText()+ "Temperature." + weatherEntity.getResults().get(0).getNow().getTemperature() + "Low";
                return text;
          }
     }).subscribeOn(Schedulers.io())
       .observeOn(AndroidSchedulers.mainThread())
       .subscribe(new Subscriber<SpannableString>() {
           @Override
           public void onCompleted(a) {
                 Log.d(TAG, "onCompleted: " + "Data acquisition completed");
           }

           @Override
           public void onError(Throwable e) {
                 tv.setText(e.toString());
            }


            @Override
            public void onNext(String s) {
                  tv.setText(s);
                  Log.d(TAG,"Current weather:"+s)
             }   
      });
}Copy the code

Through the system Api first we get our current location of the longitude and latitude information, here I wrote a random directly, then we will start the incoming interface parameters are needed to request, the first step we have to get our city by latitude and longitude position, here I use the Map and FlatMap these two operators.

Map

transform the items emitted by an Observable by applying a function to each item

FlatMap

transform the items emitted by an Observable into Observables, then flatten the emissions from those into a single Observable

From the document, we can see that FlatMap can launch an Observable into an Observables object, and then arrange it into an Observable. With this operator, we can pass the obtained location information into the WEATHER service Api. The weather entity obtained by or is launched into Observables. Then we process the Observable object of weather through the Map operator to get the specific information we need, that is, the text in the text. Then we subscribe to this event and obtain the information we need in the onNext method.

This chain structure is relatively expensive to learn, but once you learn to use Rxjava, the benefits are indeed very much, finally thank you for reading.