Describe how Retrofit and RxJava are used. When I first discovered Retrofit and RxJava, I had no idea what it was. Then read a lot of tutorials found really good difficult to understand, most of them are to write out the example, but also did not explain what the specific meaning is, for the novice contact, the cost of learning is too high, so here to give you a popular explanation.

# 2. Instructions for use

#### (a) Gradle dependency packages

compile 'com. Squareup. Retrofit2: retrofit: 2.0.2'// Basic dependencies. To use the web request framework, add compile to this dependency'com. Squareup. Okhttp3: logging - interceptor: 3.4.1 track'// compile the interceptor'com. Squareup. Okhttp3: okhttp: 3.2.0'//Retrofit uses okHTTP for its underlying network access, so this is also compile that must be added'com. Squareup. Okio: okio: 1.8.0 comes with'// Compile this is the dependency library used by okhttp'com. Google. Code. Gson: gson: 2.6.2'//Retrofit libraries used for serialization and deserialization (compile'com. Squareup. Retrofit2: converter - gson: 2.0.2'// Corresponding to gson, the (replaceable) compile used to initialize Retrofit'com. Squareup. Retrofit2: adapter - rxjava: 2.0.2'
compile 'the IO. Reactivex: rxandroid: 1.1.0'// Compile is a responsive Rx support library for the REST framework'com. Squareup. Retrofit2: adapter - rxjava: 2.1.0'
Copy the code

#### (2) Explanatory notes

# # # # RxJava syntax

Subscribers (subscribers) Observables Are not subscribed by the subthreads in which schedulers and mainthreads are switched. Subscribers (subscribers) are subscribed by the subthreads in which schedulers.newThread() is executed. Schedulers.mainthread () runs on the mainThread, and IO (),computation(), and immediate() map are used to manipulate observable and ultimate subscriber to change the type of events that an observable issues. Int, String, map, map, map, map, map, map, map, map, map, map Display the elements of the array in order filter to get values greater or less than a certain number take to get the first values Takelast to get the last values Deitinct processes a value only once

# # # # RxJava practice

package wlj.com.rxandroid; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import rx.Observable; import rx.Subscriber; import rx.functions.Action1; import rx.functions.Func1; import rx.schedulers.Schedulers; Public class MainActivity extends appActivity {/** * public class MainActivity extends appActivity {  private String TAG ="MainActivity";
    String[] names = {"111"."222"."333"};
    String[][] arrs = {{"11"."12"}, {"21"."22"}, {"31"."32"}};
    String[] nums = {"1"."2"."3"."3"."4"."6"};

    /**
     * @param savedInstanceState
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); // ObservableCreate(); // ObservableSimple(); // ObservableJust(); // ObservableRange(); // ObservableThread(); // ObservableMap(); // ObservableFrom(); // ObservableFlatMap(); // ObservableFilter(); // ObservableTake(); ObservableTest(); } /** * rxAndroid exercises * requirements: * 1 gives an array of any number of strings * 2 to duplicate the number * 3 gets a number greater than 1 * 4 keeps only the first three digits * 5 runs in the child thread * 6 for output */ private voidObservableTest() {
        Observable.from(nums)
                .map(new Func1<String, Integer>() {
                    @Override
                    public Integer call(String s) {
                        return Integer.parseInt(s);
                    }
                })
                .distinct()
                .filter(new Func1<Integer, Boolean>() {
                    @Override
                    public Boolean call(Integer integer) {
                        return integer > 1;
                    }
                })
                .take(3)
                .observeOn(Schedulers.newThread())
                .subscribe(new Action1<Integer>() {
                    @Override
                    public void call(Integer integer) {
                        Log.d(TAG, "The current number is:" + integer); }}); } /** * take the first few elements */ private voidObservableTake() {
        Observable.just(1, 2, 2, 2, 5, 4).take(4).subscribe(new Action1<Integer>() {
            @Override
            public void call(Integer integer) {
                Log.d(TAG, "The current number is:" + integer); }}); } /** * filter we do not want the value */ private voidObservableFilter() {
        Observable
                .just(0, 1, 2, 3, 3, 4, 6, 7, 100)
                .filter(new Func1<Integer, Boolean>() {
                    @Override
                    public Boolean call(Integer integer) {
                        return integer > 5;
                    }
                })
                .subscribe(new Action1<Integer>() {
                    @Override
                    public void call(Integer integer) {
                        Log.d(TAG, "The current number is:" + integer);
                    }
                });
    }

    /**
     * 遍历双列的集合数组方式
     */
    private void ObservableFlatMap() { Action1<String> action1 = new Action1<String>() { @Override public void call(String s) { Log.d(TAG, s); }}; Observable .from(arrs) .flatMap(new Func1<String[], Observable<String>>() { @Override public Observable<String> call(String[] strings) {returnObservable.from(strings); } }) .subscribe(action1); } /** * references */ private voidObservableFrom() {
        Observable
                .from(names)
                .map(new Func1<String, String>() {
                    @Override
                    public String call(String s) {
                        return "I am:"+ s; } }) .subscribe(new Action1<String>() { @Override public void call(String s) { Log.d(TAG, s); }}); } private voidObservableMap() { Action1<String> action1 = new Action1<String>() { @Override public void call(String s) { Log.d(TAG, s); Log.d(TAG, Thread.currentThread().getName()); }}; Observable .just(0, 1, 2, 3, 4) .map(new Func1<Integer, String>() { @Override public String call(Integerinteger) {
                        returninteger.toString(); } }) .observeOn(Schedulers.newThread()) .subscribe(action1); } /** ** * private void */ private void */ private void */ private void */ObservableThread() {
        Observable<String> observable = Observable.create(new Observable.OnSubscribe<String>() {
            @Override
            public void call(Subscriber<? super String> subscriber) {
                Log.d(TAG, "You've been called:" + Thread.currentThread().getName());
                subscriber.onNext("You've been called one."); }}); Action1 action1 = newAction1() {
            @Override
            public void call(Object o) {
                Log.d(TAG, "What did the master command?"+ Thread.currentThread().getName()); }}; observable .observeOn(Schedulers.newThread()) .subscribe(action1); } private voidObservableRange() {
        Observable.range(0, 10).subscribe(new Action1<Integer>() {
            @Override
            public void call(Integer integer) {
                Log.d(TAG, "call :" + integer); }}); } private voidObservableJust() {
        Observable.just(0, 1, 2).subscribe(new Action1<Integer>() {
            @Override
            public void call(Integer integer) {
                Log.d(TAG, "call : " + integer); }}); } /** ** private void */ private voidObservableSimple() {
        Observable<String> mObservable = Observable.just("Good afternoon, master."); mObservable.subscribe(new Action1<String>() { @Override public void call(String s) { Log.d(TAG, s); }}); } /** ** private void */ private voidObservableCreate() {// Create an observer final Subscriber<String> mSubscriber = new Subscriber<String>() {@override public voidonCompleted() { } @Override public void onError(Throwable throwable) { } @Override public void onNext(String s) { Log.d(TAG, s); }}; // Create Observable<String> mObservable = observable. create(new observable. OnSubscribe<String>() {@override public void  call(Subscriber<? super String> subscriber) { mSubscriber.onNext("Good afternoon"); }}); // The observer is bound to the observer mobservable.subscribe (mSubscriber); }}Copy the code

# # # # Retrofit configuration

@query: Used by the Get method to pass parameters

@field: used to pass parameters with the Post method

@body: Used by Post passing entity classes

@Headers(“apikey:fcedb879f9347de2bd186ef714342231”)

@get: need to pass in his

HttpServise

public interface HttpService {

@FormUrlEncoded
@POST("PostPhp.php")
Observable<Object> getMessage(@Field("userName") String userName);

}
Copy the code

Api classes

public class Api {
    private static final String BASEURL = "http://192.168.254.158/FirstTest/src/"; Private static final int DEFAULT_TIMEOUT = 10; Private static Api Api; private final Retrofit retrofit; publicApi() { // Gson gson = new GsonBuilder() // .setLenient() // .create(); retrofit = new Retrofit.Builder() .baseUrl(BASEURL) .client(initHttpClient()) AddCallAdapterFactory (RxJavaCallAdapterFactory. CreateWithScheduler (Schedulers. IO ())) / / asynchronous I/o requests AddConverterFactory (GsonConverterFactory. The create ()) / / /. / transition layer addConverterFactory (GsonConverterFactory. Create (gson)) / / conversion layer  .build(); } public static ApigetInstance() {
        if (api == null) {
            api = new Api();
        }
        returnapi; } /** * Description: Initializes OkHttpClient * author: Jun-wei * email :[email protected] * Created time: 2016/11/17 11:09 */ private OkHttpClientinitHttpClient() { OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); httpClient.addInterceptor(getApplicationInterceptor()); / / add application blocker httpClient. RetryOnConnectionFailure (false); / / error reconnection, failure retry httpClient connectTimeout (DEFAULT_TIMEOUT, TimeUnit. SECONDS); // Connection timeout httpClient.writeTimeout(DEFAULT_TIMEOUT, timeunit.seconds); // Write timeout httpClient.readTimeout(DEFAULT_TIMEOUT, timeunit.seconds); / / read timeout httpClient. AddNetworkInterceptor (getNetWorkInterceptor ()); // Network interceptorreturnhttpClient.build(); } /** * Description: Memory is not enough, you can use the following code to free memory * 2016/12/15 11:58 */ private void closeMemory(OkHttpClient okHttpClient) { okHttpClient.dispatcher().executorService().shutdown(); . / / clear and close the thread pool okHttpClient connectionPool () evictAll (); // Clear and close the connection pool try {okHttpClient.cache().close(); } catch (IOException e) {e.printStackTrace(); }} /** * Description: Return application Interceptor * author: Bu Jun-wom * Email :[email protected] * Created time: 2016/12/15 11:53 */ private InterceptorgetApplicationInterceptor() {
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        returninterceptor; } /** * Descriptors: Return network Interceptor * by :[email protected] * Created by: 2016/12/15 14:14 */ private InterceptorgetNetWorkInterceptor() {
        Interceptor authorizationInterceptor = new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {

                Request request = chain.request();
                long t1 = System.nanoTime();
                Log.d(TAG, String.format("Sending request %s on %s%n%s", request.url(),
                        chain.connection(), request.headers()));

                Response response = chain.proceed(request);
                long t2 = System.nanoTime();
                Log.d(TAG, String.format("Received response for %s in %.1fms%n%s",
                        response.request().url(), (t2 - t1) / 1e6d, response.headers()));

                returnresponse; }};returnauthorizationInterceptor; } /** * Description: Return object * Author: Bu Jun-wan * Email :[email protected] * Created at: 2016/8/23 10:29 */ public <T> T getRetrofit(Class<T> httpServiceClass) {returnretrofit.create(httpServiceClass); }}Copy the code


You can copy the GsonConverterFactory code, rewrite its code, and rewrite its Response and Request classes! [](http://upload-images.jianshu.io/upload_images/2650372-b5f4aaebacc12b56.png? ImageMogr2 /auto-orient/strip% 7cImageView2/2 /w/1240) override the Convert method to parse the ResponseBody first, which returns T, You can update it to return String, whatever it is. The value.string() method gets the Json String returned by the server.Copy the code

@Override public T convert(ResponseBody value) throws IOException { JsonReader jsonReader = gson.newJsonReader(value.charStream()); try { return adapter.read(jsonReader); } finally { value.close(); }}

</br> Api utility classCopy the code

public class ApiUtils {

/** * Description: Call Oauth * author: Bu Junwen * Email :[email protected] * Creation time: 2016/12/15 19:34 */ public static <T extends BaseModel, K extends Object> void postOauthRequest(T data, final Class<K> targer, final OnCommondRequestListener onCommondRequestListener) { postCommond(data, targer, onCommondRequestListener, Api.RETROFIT_TYPE_OAUTH); } /** * Description: call Cpf * author: Bu Jun-wan * Email :[email protected] * Created at: 2016/12/15 19:34 */ public static <T extends BaseModel, K extends Object> void postCpfRequest(T data, final Class<K> targer, final OnCommondRequestListener onCommondRequestListener) { postCommond(data, targer, onCommondRequestListener, Api.RETROFIT_TYPE_CPF); } /** * Description: Execute the general Post method, the first parameter is the data, the second is the corresponding interface * 2016/12/15 15:08 */ public static <T extends BaseModel, K extends Object> void postCommond(T data, final Class<K> targer, final OnCommondRequestListener onCommondRequestListener, int type) { if (data == null) { return; } String info = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create().toJson(data); Klog. e(" send JSON: "+ info); / / the Header assembly String Header = getHearder (info, data getHTTP_SERVER (), data. IsRequestEncryptionInterface ()? true : false, type); / / assembly RequestBody RequestBody RequestBody = getRequestBody (info, data isRequestEncryptionInterface ()? true : false); // The request requires a Heaeder and RequestBody Api.getInstance().getretrofit (httpService.class, type).ehomecommondPost (header, requestBody) .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<Object>()  { @Override public void onCompleted() { } @Override public void onError(Throwable e) { onCommondRequestListener.onRequestFail(e.getMessage()); } @override public void next (Object o) {klog.e (" return "+ o.tostring ()); String content = StringUtils.contentDecryption(o.toString(), false); K k = null; If (content.startswith ("{")) {// object k = new Gson().fromjson (content, targer); } else if (content.startswith ("[")) {try {JSONArray JSONArray = new JSONArray(content);  List<K> list = new ArrayList<K>(); for (int i = 0; i < jsonArray.length();  i++) { list.add(new Gson().fromJson(jsonArray.get(i).toString(), targer)); } k = (K) list;  } catch (JSONException e) { e.printStackTrace(); } } else { onCommondRequestListener.onRequestFail(content); KLog. E (" error: "+ content); return;} onCommondRequestListener. OnRequestSuccess (k);}}); } /** * Description: Return Header * Author: Bu Jun-wan * Email :[email protected] * Created at: 2016/12/15 15:17 */ public static String getHearder(String info, String ehomeAcLoginGet, boolean b, int type) { if (type == Api.RETROFIT_TYPE_CPF) { return StringUtils.headerInfo(info, ehomeAcLoginGet, b);  } else if (type == Api.RETROFIT_TYPE_OAUTH) { return StringUtils.headerInfo4Update(info, ehomeAcLoginGet, b); } return null;} /** * Description: Return RequestBody * 2016/12/15 15:19 */ public static RequestBody getRequestBody(String info, boolean b) { String content = StringUtils.contentEncryption(info, b);  return RequestBody.create(MediaType.parse("application/octet-stream"), content.getBytes()); }Copy the code

}


</br>
## 3. Abnormal problem solving
</br>
Copy the code

/ / the problem when using Post requests will appear under Caused by: Java. Lang. IllegalArgumentException: @Field parameters can only be used with form encoding

Solution: Add @formurlencoded! [](http://upload-images.jianshu.io/upload_images/2650372-554e18c4714dc1ba.png? imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) </br>Copy the code

// The problem is that the server sent the Json string incorrectly. OnErrorUse jsonReader. setLenient(true) to accept malformed JSON at line 1 column 1 path $

Solution: 1 Modify the Json string sent by the server and let it normalize. 2 Modify the following codeCopy the code

Gson gson = new GsonBuilder() .setLenient() .create(); AddConverterFactory (GsonConverterFactory. Create (gson)) / / conversion layer

Copy the code