Android

RxJava2+ Retrofit2 簡介

Ellis Wang 2019/08/12 10:00:03
2379

前言:

Retrofit:

一種 HTTP 請求的框架,使用 REST API 設計,由 RESTful Client  Server 發出請求。

 

 

RxJava:

其特色是可以輕鬆的切換thread,並和LiveData一樣以observer pattern處理事件。

 

 

本文會使用goole map api RxJava2+ Retrofit2範例。

 

 

 

Retrofit

 

 

簡介:

Retrofit是專為API連線而生的第三方套件,與API連線的效率非常高,最特別的是其規範的REST框架讓程式高度解耦,好寫易維護,被譽為API連線的教科書。另外它跟OkHttp同為Square公司出品,兩者可以完美整合發揮更多功能。

 

請求方法註解

 

註解

說明

@GET

get請求

@POST

post請求

@PUT

put請求

@DELETE

delete請求

@PATCH

patch請求,是對put請求的補充,用於更新部分資源

@HEAD

head請求

@OPTIONS

option請求

@HTTP

通用註解,可替換以上所有的註解,擁有三個屬性:methodpathhasbody

 

 

 

請求參數註解

註解

說明

@Body

多用於post請求發送非表單數據,比如以方式傳遞json格式數據

@Filed

多用於post請求中表單字段,FiledFiledMap需要FormUrlEncode結合使用

@FiledMap

Filed作用一致,用於不確定表單參數

@Part

用於表單字段,partpartMapMultipart註解結合使用,適合文件上傳

@PartMap

用於表單字段,默認接受的類型是map<String,RequestBody>,可用於實現多文件上傳

@Path

用於url中的占位符

@Query

用於Get中指定參數

@QueryMap

Query使用類似

@Url

指定請求路徑

 

 

RxJava

 

簡介:

主要特性

 

被觀察者(Observable) 產生事件

觀察者(Observer) 接收事件

訂閱(Subscribe) 連結ObservableObserver

 

線程變換

 

Schedulers.immediate()

當前線程

AndroidSchedulers.mainThread()

主線程

Schedulers.newThread()

新線程

schedulers.io()

IO操作線程,用於進行網路請求、讀寫文件等IO操作

Schedulers.computation()

CPU計算操作線程

 

使用:

     (範例以google place detail api做範例)

 

       使用前請添加依賴庫和權限請求

 

        Gradle:

 

//retrofit2
    implementation 'com.squareup.retrofit2:retrofit:2.3.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
    implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
//rxjava
    implementation 'io.reactivex.rxjava2:rxjava:2.0.5'
    implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'

 

         manifests:

 

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

 

      建立Retrofit client

 

public class APIServiceClient {
    private static APIClient apiClient;
    private static String BASE_URL = "https://maps.googleapis.com/maps/api/";

    public static APIClient getInstance() {
        if (apiClient == null) {
            synchronized (APIServiceClient.class) {
                if (apiClient == null) {
                    new APIServiceClient();
                }
            }
        }
        return apiClient;
    }

    private APIServiceClient() {
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .addInterceptor(new LoggingInterceptor())
                .connectTimeout(10, TimeUnit.SECONDS)
                .build();
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .client(okHttpClient)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
        apiClient = retrofit.create(APIClient.class);
    }
}

 

      建立傳遞參數接口

 

public interface APIClient {

  @GET("place/details/json?")
    Observable<MapPlaceData> observablePlaceDetail(@Query("placeid") String place_id,
                                                   @Query("fields") String fields,
                                                   @Query("key") String api_key,
                                                   @Query("language") String language);
@GET("directions/json?")
    Observable<Object> observableDirections(@Query("origin") String origin_place,
                                            @Query("destination") String destination_place_id,
                                            @Query("mode") String mode,
                                            @Query("key") String api_key,
                                            @Query("language") String language,
                                            @Query("sensor") boolean sensor);

    @GET("directions/json?")
    Observable<Object> observablePublicTransportationDirections(@Query("origin") String origin_place,
                                                                @Query("destination") String destination_place_id,
                                                                @Query("mode") String mode,
                                                                @Query("transit_mode") String transit_mode,
                                                                @Query("key") String api_key,
                                                                @Query("language") String language,
                                                                @Query("sensor") boolean sensor);

    @GET("place/nearbysearch/json?")
    Observable<Object> observableNearBySearch(@Query("location") String location_place,
                                              @Query("radius") String radius,
                                              @Query("types") String type,
                                              @Query("key") String api_key);

    @GET("place/autocomplete/json?")
    Observable<Object> observableAutoComplete(@Query("input") String input,
                                              @Query("key") String api_key,
                                              @Query("language") String language);

}

 

      建立數據返回的Model

 

 

public class MapPlaceData {
    @SerializedName("result")
    private Result result;
    @SerializedName("results")
    private List<Result> results;

    public List<Result> getResults() {
        return results;
    }

    public void setResults(List<Result> results) {
        this.results = results;
    }

    public Result getResult() {
        return result;
    }

    public void setResult(Result result) {
        this.result = result;
    }

    public class Result {
        @SerializedName("formatted_phone_number")
        private String formatted_phone_number;

        @SerializedName("id")
        private String id;
        @SerializedName("formatted_address")
        private String formatted_address;
        @SerializedName("name")
        private String name;
        @SerializedName("place_id")
        private String place_id;
        @SerializedName("rating")
        private String rating;
        @SerializedName("international_phone_number")
        private String international_phone_number;
        @SerializedName("website")
        private String website;
        @SerializedName("icon")
        private String icon;
        @SerializedName("types")
        private List<String> types;
        @SerializedName("opening_hours")
        private OpeningHours opening_hours;
        @SerializedName("geometry")
        private Geometry geometry;

        public Geometry getGeometry() {
            return geometry;
        }

        public void setGeometry(Geometry geometry) {
            this.geometry = geometry;
        }

        public List<String> getTypes() {
            return types;
        }

        public void setTypes(List<String> types) {
            this.types = types;
        }

        public String getIcon() {
            return TextUtils.isEmpty(icon) ? "" : icon;
        }

        public void setIcon(String icon) {
            this.icon = icon;
        }

        public String getWebsite() {
            return TextUtils.isEmpty(website) ? "" : website;
        }

        public void setWebsite(String website) {
            this.website = website;
        }

        public String getInternational_phone_number() {
            return TextUtils.isEmpty(international_phone_number) ? "" : international_phone_number;
        }

        public void setInternational_phone_number(String international_phone_number) {
            this.international_phone_number = international_phone_number;
        }

        public String getFormatted_address() {
            return TextUtils.isEmpty(formatted_address) ? "" : formatted_address;
        }

        public void setFormatted_address(String formatted_address) {
            this.formatted_address = formatted_address;
        }

        public String getFormatted_phone_number() {
            return TextUtils.isEmpty(formatted_phone_number) ? "" : formatted_phone_number;
        }

        public void setFormatted_phone_number(String formatted_phone_number) {
            this.formatted_phone_number = formatted_phone_number;
        }

        public String getId() {
            return TextUtils.isEmpty(id) ? "" : id;
        }

        public void setId(String id) {
            this.id = id;
        }


        public String getName() {
            return TextUtils.isEmpty(name) ? "" : name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getPlace_id() {
            return TextUtils.isEmpty(place_id) ? "" : place_id;
        }

        public void setPlace_id(String place_id) {
            this.place_id = place_id;
        }

        public String getRating() {
            return TextUtils.isEmpty(rating) ? "" : rating;
        }

        public void setRating(String rating) {
            this.rating = rating;
        }

        public OpeningHours getOpening_hours() {
            return opening_hours;
        }

        public void setOpening_hours(OpeningHours opening_hours) {
            this.opening_hours = opening_hours;
        }

        public class Geometry{
            @SerializedName("location")
            private Location location;

            public Location getLocation() {
                return location;
            }

            public void setLocation(Location location) {
                this.location = location;
            }
        }

        public class Location{
            @SerializedName("lat")
            private String lat;
            @SerializedName("lng")
            private String lng;

            public String getLat() {
                return lat;
            }

            public void setLat(String lat) {
                this.lat = lat;
            }

            public String getLng() {
                return lng;
            }

            public void setLng(String lng) {
                this.lng = lng;
            }
        }
        public class OpeningHours {
            @SerializedName("open_now")
            private boolean open_now;


            public boolean isOpen_now() {
                return open_now;
            }

            public void setOpen_now(boolean open_now) {
                this.open_now = open_now;
            }
        }
    }
}

 

      開始使用RxJava2+ Retrofit2求取google map place detail api

 

APIServiceClient.getInstance()
                .observablePlaceDetail(place_id, "name,rating,formatted_phone_number,international_phone_number," +
                        "website,formatted_address,icon,type,opening_hours", api_key, "zh-TW")
                .subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<MapPlaceData>() {
                    private Disposable disposable;

                    @Override
                    public void onSubscribe(Disposable d) {
                        Log.d("getPlaceDetail", "onSubscribe...");
                        disposable = d;
                        mView.showProgressDialog();
                    }

                    @Override
                    public void onNext(MapPlaceData mapPlaceData) {
                        Log.d("TAG", "onNext: " + new Gson().toJson(mapPlaceData));
                        mView.placeDetailData(new Gson().toJson(mapPlaceData));

                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.d("TAG", "onError: " + e.getMessage());
                    }

                    @Override
                    public void onComplete() {
                        Log.d("TAG", "onComplete: Over!");
                        mView.disMissProgressDialog();
                        disposable.dispose();

                    }
                });

 

 

demo 示意。call back data model請自行再parser 顯示在UI上

 

Ellis Wang