com.malin.rxjava.activity.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.malin.rxjava.activity.MainActivity.java

Source

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 malin
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package com.malin.rxjava.activity;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.jakewharton.rxbinding.view.RxView;
import com.jakewharton.rxbinding.widget.RxTextView;
import com.jakewharton.rxbinding.widget.TextViewTextChangeEvent;
import com.malin.rxjava.R;
import com.malin.rxjava.application.RxJavaApplication;
import com.malin.rxjava.constant.Constant;
import com.malin.rxjava.factory.DataFactory;
import com.malin.rxjava.factory.ImageNameFactory;
import com.malin.rxjava.githubapi.GitHubApi;
import com.malin.rxjava.model.Contributor;
import com.malin.rxjava.model.Course;
import com.malin.rxjava.model.Student;
import com.malin.rxjava.model.User;
import com.malin.rxjava.service.RetrofitService;
import com.malin.rxjava.utils.ClickUtils;
import com.malin.rxjava.utils.DeviceInfo;
import com.malin.rxjava.utils.ImageUtils;
import com.malin.rxjava.utils.RecycleBitmap;
import com.malin.rxjava.utils.RxUtils;
import com.malin.rxjava.utils.ToastUtil;
import com.orhanobut.logger.LogLevel;
import com.orhanobut.logger.Logger;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.TimeUnit;

import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import rx.Observable;
import rx.Observer;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action0;
import rx.functions.Action1;
import rx.functions.Func1;
import rx.schedulers.Schedulers;
import rx.subscriptions.CompositeSubscription;

/**
 * ??:?
 * :malin.myemail@gmail.com
 * :15-11-10.
 * :
 */
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private static final String TAG_FOR_LOGGER = "MainActivity_I_LOVE_RXJAVA";
    private static final String ERROR = "??";
    private static final String JPG = ".jpg";
    private int mCounter;//
    private ImageView mImageView;
    private Bitmap mManyBitmapSuperposition = null;
    private Canvas mCanvas = null;
    private ProgressBar mProgressBar;
    private EditText mSearchEditText;
    private TextView mResultTextView;
    private Context mContext;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initializeLogAndDeviceInfo();
        initView();
        initData();
        testFuncation(9);//RxJava
    }

    /**
     * ?Logger???
     */
    private void initializeLogAndDeviceInfo() {
        Logger.init(TAG_FOR_LOGGER).logLevel(LogLevel.FULL);//Use LogLevel.NONE for the release versions.
        DeviceInfo.getInstance().initializeScreenInfo(this);
    }

    /**
     * ?
     */
    private void initView() {
        mContext = this;
        mImageView = (ImageView) findViewById(R.id.iv_image);
        mResultTextView = (TextView) findViewById(R.id.tv_result);
        mSearchEditText = (EditText) findViewById(R.id.ed_search);
        mProgressBar = (ProgressBar) findViewById(R.id.progressbar);
    }

    private void initData() {
        mContext = this;
    }

    /**
     * ??,??
     */
    private void getException() {
        int errorCode = Integer.valueOf(ERROR);
    }

    //-----------------------------------------------0:RxJava-----------------------------------------------------------
    //
    //1:,?:???
    //2::?
    //3:
    private void method0() {

        //1:,?
        //:RxJava  Observable.create() ? Observable ?
        Observable<String> observable = Observable.create(new Observable.OnSubscribe<String>() {
            @Override
            public void call(Subscriber<? super String> subscriber) {
                subscriber.onNext("Hello");
                subscriber.onNext("World");
                subscriber.onNext("!");
                subscriber.onCompleted();
                subscriber.onError(new Throwable());
                Logger.d("-observable->call()->onCompleted()??");
            }
        });

        /**
         * ? OnSubscribe ?
         * OnSubscribe  Observable 
         * Observable OnSubscribe  call() ????
         * ??subscriber  onNext()  onCompleted()
         * ???
         */
        //2:
        Observer<String> observer = new Observer<String>() {
            @Override
            public void onCompleted() {
                Logger.d("-observer:onCompleted()");
            }

            @Override
            public void onError(Throwable e) {
                Logger.d("-observer:onError" + e.getMessage());
            }

            @Override
            public void onNext(String s) {
                Logger.d("-observer:onNext():" + s);
                // getException();//??,onError()....
            }
        };

        //3:--
        observable.subscribe(observer);
    }

    //---------------------------------------1:? Observable.just(T...)--------------------------------------------------------------

    // create()  RxJava ? RxJava ????
    // just(T...): ?????.

    //:,RxJava?:just(T...):

    /**
     * :
     * {@link #method0()}
     */
    private void method1() {

        //
        //1::
        //2::
        //3:-

        //1::
        //just(T...): ?????
        Observable<String> observable = Observable.just("Hello", "World", "!");
        // ?
        // onNext("Hello");
        // onNext("World");
        // onNext("!");
        // onCompleted();

        //2::
        Observer<String> observer = new Observer<String>() {
            @Override
            public void onCompleted() {
                Logger.d("-observer:onCompleted()");
            }

            @Override
            public void onError(Throwable e) {
                Logger.d("-observer:onError()");
            }

            @Override
            public void onNext(String s) {
                Logger.d("-observer:onNext():" + s);
                //getException();//??,onError()....
            }
        };

        //3::
        observable.subscribe(observer);
    }

    //---------------------------------------2:? Observable.from(T[]) / from(Iterable<? extends T>--------------------------------------------------------------

    /**
     * :: RxJava?:just(String[] array)  Iterable ??????
     * {@link #method1()}
     */
    private void method2() {

        //
        //1:
        //2:
        //3:-

        String[] array = new String[] { "Hello", "World", "!" };
        //1::
        //just(String[] array)  Iterable ??????
        Observable observable = Observable.from(array);
        // ?
        // onNext("Hello");
        // onNext("World");
        // onNext("!");
        // onCompleted();

        //2:
        Observer observer = new Observer() {
            @Override
            public void onCompleted() {
                Logger.d("-observer:onCompleted()");
            }

            @Override
            public void onError(Throwable e) {
                Logger.d("-observer:onError()");
            }

            @Override
            public void onNext(Object o) {
                String str = (String) o;
                Logger.d("-observer:onNext():" + str);
                // getException();//??,onError()....
            }
        };

        //3:: 
        observable.subscribe(observer);

    }

    //---------------------------------------3: subscribe()??--------------------------------------------------------------

    /**
     * 
     * {@link #method2()}
     * subscribe??
     * subscribe(final Action1<? super T> onNext)
     */
    private void method3() {

        String[] array = new String[] { "Hello", "World", "!" };
        //1:
        Observable observable = Observable.from(array);

        //2:
        Action1 onNextAction = new Action1() {
            @Override
            public void call(Object o) {
                String str = (String) o;
                Logger.d(":call(Object o):" + str);
            }
        };

        //3:-
        //subscribe(final Action1<? super T> onNext)
        // Subscriber  onNextAction ? onNext()
        observable.subscribe(onNextAction);
    }

    /**
     * 
     * subscribe??
     * {@link #method3()}
     * subscribe(final Action1<? super T> onNext, final Action1<Throwable> onError)
     */
    private void method4() {

        //1:
        Observable observable = Observable.from(new String[] { "Hello", "World", "!" });

        //2:
        Action1 onNextAction = new Action1() {
            @Override
            public void call(Object o) {
                String str = (String) o;
                Logger.d(":onNextAction:call(Object o):o:" + str);
            }
        };

        Action1<Throwable> onErrorAction = new Action1<Throwable>() {
            @Override
            public void call(Throwable throwable) {
                Logger.d(":onErrorAction:call(Throwable throwable):" + throwable.getMessage());
            }
        };

        //3:
        //subscribe(final Action1<? super T> onNext, final Action1<Throwable> onError)
        //  Subscriber  onNextAction  onErrorAction ? onNext()  onError()
        observable.subscribe(onNextAction, onErrorAction);

    }

    /**
     * subscribe??
     * subscribe(final Action1<? super T> onNext, final Action1<Throwable> onError, final Action0 onComplete)
     */
    private void method5() {
        //1:
        Observable observable = Observable.from(new String[] { "Hello", "World", "!" });

        //2:
        Action1 onNextAction = new Action1() {
            @Override
            public void call(Object o) {
                String str = (String) o;
                Logger.d(":onNextAction:call():s:" + str);
            }
        };

        Action1<Throwable> onErrorAction = new Action1<Throwable>() {
            @Override
            public void call(Throwable throwable) {
                Logger.d(":onErrorAction:call(Throwable throwable):" + throwable.getMessage());
            }
        };

        Action0 onCompletedAction = new Action0() {
            @Override
            public void call() {
                Logger.d(":onCompletedAction:call()");
            }
        };

        //3::

        //subscribe(final Action1<? super T> onNext, final Action1<Throwable> onError, final Action0 onComplete)
        //  Subscriber  onNextAction? onErrorAction  onCompletedAction ? onNext()? onError()  onCompleted()
        observable.subscribe(onNextAction, onErrorAction, onCompletedAction);

    }

    //---------------------------------------4: Action0Action1 --------------------------------------------------------------
    /**
     * ?Action0Action1,???;
     * ??:
     *
     * MaLin:,Action0Action1,???
     *
     * :,?:
     * Action0  RxJava ?? call()?
     *  onCompleted() ? Action0 ??
     *  onCompleted() ?? subscribe() ?
     * ?? onCompleted() ? subscribe()??
     *
     * Action1 ??? call(T param)?
     *  Action0 ?? onNext(T obj)  onError(Throwable error) ??
     *  Action1 ? onNext(obj)  onError(error) ? subscribe() ?
     *  Action0  Action1  API  RxJava ?? ActionX ?? ( Action2, Action3) 
     * ???
     */

    //---------------------------------------5: ?!??-------------------------------------------------------------

    //1.[logger](https://github.com/orhanobut/logger) | ?,,Android
    //2.[pidcat](https://github.com/JakeWharton/pidcat)|JakeWharton?,,|?

    /**
     * com.github.orhanobut:logger ??
     *  ????????????????????????????????????????????????????????????????????????????????????????
     D   Thread: main
     D  
     D   MainActivity$11.onNext  (MainActivity.java:338)
     D      MainActivity$11.onNext  (MainActivity.java:354)
     D  
     D    onNext()
     D  ????????????????????????????????????????????????????????????????????????????????????????
     D  ????????????????????????????????????????????????????????????????????????????????????????
     D   Thread: main
     D  
     D   SafeSubscriber.onCompleted  (SafeSubscriber.java:83)
     D      MainActivity$11.onCompleted  (MainActivity.java:341)
     D  
     D    onCompleted()
     D  ????????????????????????????????????????????????????????????????????????????????????????
     */

    //---------------------------------------6 -Scheduler-------------------------------------------------------------

    /**
     * 
     * ????
     * ? IO ??????????
     */
    private void method6() {

        final int drawableRes = R.mipmap.malin;
        Observable.create(new Observable.OnSubscribe<Drawable>() { //1:
            @Override
            public void call(Subscriber<? super Drawable> subscriber) {
                Logger.d("");
                Drawable drawable = ContextCompat.getDrawable(RxJavaApplication.getApplication(), drawableRes);
                subscriber.onNext(drawable);
                subscriber.onCompleted();
            }
        }).subscribeOn(Schedulers.io())// subscribe() ? IO 
                // doOnSubscribe() ? observeOn() ? observeOn() 
                .doOnSubscribe(new Action0() {
                    @Override
                    public void call() {
                        if (mProgressBar != null) {
                            mProgressBar.setVisibility(View.VISIBLE);//ProgressBar--?
                        }
                    }
                }).observeOn(AndroidSchedulers.mainThread())// Subscriber ???
                .subscribe(new Subscriber<Drawable>() { //3: //2:
                    @Override
                    public void onCompleted() {
                        if (mProgressBar != null) {
                            mProgressBar.setVisibility(View.GONE);
                        }
                        Logger.d(" onCompleted()");
                        Toast.makeText(MainActivity.this, " onCompleted()", Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onError(Throwable e) {
                        if (mProgressBar != null) {
                            mProgressBar.setVisibility(View.GONE);
                        }
                        Logger.d(" onError()");
                        Toast.makeText(MainActivity.this, " onError() " + e.getMessage(),
                                Toast.LENGTH_SHORT).show();

                    }

                    @Override
                    public void onNext(Drawable drawable) {
                        Toast.makeText(MainActivity.this, " onNext()", Toast.LENGTH_SHORT).show();
                        Logger.d(" onNext()");
                        if (mImageView == null || drawable == null)
                            return;
                        mImageView.setImageDrawable(drawable);
                    }
                });

    }

    //---------------------------------------7: ?? map()-------------------------------------------------------------
    private void method7() {
        final int drawableRes = R.mipmap.malin;

        //1:
        Observable.just(drawableRes)// int
                .map(new Func1<Integer, Drawable>() {

                    @Override
                    public Drawable call(Integer integer) {// ? String
                        Logger.d("integer:" + integer);
                        return ContextCompat.getDrawable(RxJavaApplication.getApplication(), integer);
                    }
                }).subscribeOn(Schedulers.io())// subscribe() ? IO 
                //doOnSubscribe() ? observeOn() ? observeOn() 
                .doOnSubscribe(new Action0() {
                    @Override
                    public void call() {
                        if (mProgressBar != null) {
                            mProgressBar.setVisibility(View.VISIBLE);//ProgressBar--?
                        }
                    }
                }).observeOn(AndroidSchedulers.mainThread())// Subscriber ???
                .subscribe(new Subscriber<Drawable>() { //3: //2:
                    @Override
                    public void onCompleted() {
                        if (mProgressBar != null) {
                            mProgressBar.setVisibility(View.GONE);
                        }
                        Logger.d(":onCompleted()");
                    }

                    @Override
                    public void onError(Throwable e) {
                        if (mProgressBar != null) {
                            mProgressBar.setVisibility(View.GONE);
                        }
                        Toast.makeText(MainActivity.this, "" + e.getMessage(), Toast.LENGTH_SHORT).show();
                        Logger.d(":onError(Throwable e):" + e.getMessage());
                    }

                    @Override
                    public void onNext(Drawable drawable) {
                        if (mImageView == null || drawable == null)
                            return;
                        mImageView.setImageDrawable(drawable);
                        Logger.d(":onNext(Drawable drawable):" + drawable.toString());
                    }
                });
    }

    //---------------------------------------8:  ?-------------------------------------------------------------

    //
    private void method8() {
        ArrayList<Student> students = DataFactory.getData();
        int size = students.size();
        for (int i = 0; i < size; i++) {
            Logger.d("??:" + students.get(i).name);
            int sizeCourses = students.get(i).courses.size();
            for (int j = 0; j < sizeCourses; j++) {
                Logger.d(":" + students.get(i).courses.get(j).name);
            }
        }
    }

    /**
     * ?:???:?()??
     * RxJava:
     * {@link #method8()}
     */
    private void method9() {
        //just(T...): ?????,??
        Observable.from(DataFactory.getData()).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<Student>() {
                    @Override
                    public void call(Student student) {
                        Logger.d(":" + student.name);
                    }
                });
    }

    /**
     * ?:??:?(??)??
     * RxJava
     * {@link #method9()}
     */
    private void method10() {

        //1:

        //2:??

        //3:

        //4:

        //5:

        //6:

        Observable.from(DataFactory.getData())

                .map(new Func1<Student, String>() {
                    @Override
                    public String call(Student student) {
                        return student.name;
                    }
                }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<String>() {
                    @Override
                    public void onCompleted() {
                        Logger.d(":onCompleted()");
                    }

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

                    @Override
                    public void onNext(String s) {
                        Logger.d(":onNext(String s) " + s);
                    }
                });

    }

    /**
     * ?:??:?(??)??,method9()
     * RxJava
     * ??
     * {@link #method10()}
     */
    private void method11() {
        Observable.from(DataFactory.getData()).map(new Func1<Student, String>() {
            @Override
            public String call(Student student) {
                return student.name;
            }
        }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<String>() {
            @Override
            public void call(String s) {
                Logger.d(":" + s);
            }
        });

    }

    //---------------------------------------9: flatmap()-------------------------------------------------------------

    /**
     * ?:?
     * RxJava
     * ?
     * {@link #method11()}
     */
    private void method12() {

        //1:

        //2:

        //3:

        Observable.from(DataFactory.getData()).subscribe(new Subscriber<Student>() {
            @Override
            public void onCompleted() {
                Logger.d(":onCompleted()");
            }

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

            @Override
            public void onNext(Student student) {
                ArrayList<Course> courses = student.courses;
                for (Course course : courses) {
                    Logger.d(":" + course.name);
                }
            }
        });

    }

    /**
     * ?:?,method12
     * RxJava
     * {@link #method12()}
     * Student->ArrayList<Course>
     */
    private void method13() {

        Observable.from(DataFactory.getData())

                .map(new Func1<Student, ArrayList<Course>>() {
                    @Override
                    public ArrayList<Course> call(Student student) {
                        return student.courses;
                    }
                }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<ArrayList<Course>>() {
                    @Override
                    public void call(ArrayList<Course> courses) {
                        for (int i = 0; i < courses.size(); i++) {
                            Logger.d(":" + courses.get(i).name);
                        }
                    }
                });
    }

    //---------------------------------------10: flatMap()-------------------------------------------------------------

    /**
     * ?:?,method13
     * RxJava
     * {@link #method13()}
     * Student -> ArrayList<Course> -> Observable<Course> ->
     */
    private void method14() {

        //1:

        //2:??

        //3:

        //4:

        //5:

        //6:

        // Student->Course
        Observable.from(DataFactory.getData()).flatMap(new Func1<Student, Observable<Course>>() {
            @Override
            public Observable<Course> call(Student student) {
                return Observable.from(student.courses);
            }
        }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<Course>() {
            @Override
            public void call(Course course) {
                Logger.d(":" + course.name);
            }
        });
    }

    //---------------------------------------10: RxBinding-------------------------------------------------------------

    /**
     * ?,.
     */
    private void method15() {

        mImageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        if (ClickUtils.isFastDoubleClick()) {
                            ToastUtil.getInstance().showToast(MainActivity.this, "");
                            return;
                        }
                        ToastUtil.getInstance().showToast(MainActivity.this, "??click");
                    }
                });
            }
        });

    }

    /**
     * RxBinding
     * RxBinding  Jake Wharton ??? Android ? RxJava  Binding API
     *  Binding OnClickListener ? TextWatcher  API
     * ?? RxBinding ???
     * throttleFirst() 
     */
    private void method16() {
        RxView.clicks(mImageView).throttleFirst(500, TimeUnit.MILLISECONDS)//500ms,?,500ms,500ms???
                .subscribeOn(AndroidSchedulers.mainThread()).observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<Void>() {
                    @Override
                    public void call(Void aVoid) {
                        Toast.makeText(MainActivity.this, "click", Toast.LENGTH_SHORT).show();
                    }
                });
    }

    /**
     * RxBinding
     */
    private void method17() {
        RxView.longClicks(mImageView).throttleFirst(500, TimeUnit.MILLISECONDS).subscribe(new Action1<Void>() {
            @Override
            public void call(Void aVoid) {
                Toast.makeText(MainActivity.this, "long click", Toast.LENGTH_SHORT).show();
            }
        });
    }

    /**
     * EditText,?500ms,??
     */
    private void method18() {
        mSearchEditText.setVisibility(View.VISIBLE);
        RxTextView.textChangeEvents(mSearchEditText).debounce(500, TimeUnit.MILLISECONDS)
                .observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<TextViewTextChangeEvent>() {
                    @Override
                    public void onCompleted() {
                    }

                    @Override
                    public void onError(Throwable e) {
                    }

                    @Override
                    public void onNext(TextViewTextChangeEvent textViewTextChangeEvent) {
                        String changedMessage = textViewTextChangeEvent.text().toString();
                        Logger.d(TAG, changedMessage);
                        if (!TextUtils.isEmpty(changedMessage)) {
                            ToastUtil.getInstance().showToast(MainActivity.this, changedMessage);
                        }
                    }
                });
    }

    /**
     * ?Defer?Just
     */
    //?? Range???nm?nm
    //::1,2,3,4,5
    // ????Subscriber
    private void method19() {
        Observable.range(1, 5).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<Integer>() {
                    @Override
                    public void call(Integer integer) {
                        Logger.d(integer.toString() + "");
                    }
                });
    }

    /**
     * Retrofit,?androidmalinGitHub?
     */
    private void method21() {

        mProgressBar.setVisibility(View.VISIBLE);
        mImageView.setVisibility(View.GONE);
        mResultTextView.setVisibility(View.VISIBLE);
        mResultTextView.setText("");
        Call call = RetrofitService.getInstance().createService(GitHubApi.class).getUser("androidmalin");

        //asynchronous
        call.enqueue(new Callback<User>() {
            @Override
            public void onResponse(Call<User> call, Response<User> response) {
                User user = (User) response.body();

                if (user == null) {
                    //404 or the response cannot be converted to User.
                    ResponseBody responseBody = response.errorBody();
                    if (responseBody != null) {
                        try {
                            Logger.d("responseBody = " + responseBody.string());
                            mResultTextView.setText("responseBody = " + responseBody.string());
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    } else {
                        Logger.d("responseBody = null");
                        mResultTextView.setText("responseBody = null");
                    }
                } else {
                    //200
                    String message = "Github Name :" + user.name + "\nWebsite :" + user.blog + "\nCompany Name :"
                            + user.company;
                    ToastUtil.getInstance().showToast(MainActivity.this, message);
                    Logger.d(message);
                    mResultTextView.setText(message);
                }
                mProgressBar.setVisibility(View.GONE);
            }

            @Override
            public void onFailure(Call<User> call, Throwable t) {
                Logger.d("t = " + t.getMessage());
                mProgressBar.setVisibility(View.GONE);
            }
        });
    }

    /**
     * Retrofit,?RxJava ?androidmalinGitHub?
     */
    private void method22() {
        //TODO:1:,??
        //TODO:2:
        //TODO:3:,  

        Observable<User> observable = RetrofitService.getInstance().createService(GitHubApi.class)
                .getUserObservable("androidmalin");
        observable.subscribeOn(Schedulers.io()).doOnSubscribe(new Action0() {
            @Override
            public void call() {
                mProgressBar.setVisibility(View.VISIBLE);
                mResultTextView.setText("");
                mImageView.setVisibility(View.GONE);
                mResultTextView.setVisibility(View.VISIBLE);
            }
        }).observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<User>() {
            @Override
            public void onCompleted() {
                Logger.d("onCompleted()");
                mProgressBar.setVisibility(View.INVISIBLE);
                Toast.makeText(MainActivity.this, "onCompleted", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onError(Throwable e) {
                Logger.d("onError()=>" + e.getMessage());
            }

            @Override
            public void onNext(User user) {
                Logger.d("onNext()");
                String message = "Github Name :" + user.name + "\nWebsite :" + user.blog + "\nCompany Name :"
                        + user.company;
                Toast.makeText(MainActivity.this, "onNext", Toast.LENGTH_SHORT).show();
                Logger.d(message);
                mResultTextView.setText(user.toString());
            }
        });
    }

    private ArrayAdapter<String> mAdapter;
    private CompositeSubscription mSubscription = new CompositeSubscription();
    private ListView mResultListView;

    /**
     * Retrofit,?RxJava ?square?retrofit
     */
    private void method23() {

        mImageView.setVisibility(View.GONE);
        mResultTextView.setVisibility(View.GONE);
        mImageView.setVisibility(View.GONE);

        mResultListView = (ListView) findViewById(R.id.lv_list);
        mAdapter = new ArrayAdapter<String>(MainActivity.this, R.layout.item_log, R.id.item_log,
                new ArrayList<String>());
        mResultListView.setAdapter(mAdapter);

        mSubscription.add(RetrofitService.getInstance().createService(GitHubApi.class)
                .getContributorsObservable("square", "retrofit").subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread()).doOnSubscribe(new Action0() {
                    @Override
                    public void call() {
                        mProgressBar.setVisibility(View.VISIBLE);
                    }
                }).subscribe(new Observer<List<Contributor>>() {
                    @Override
                    public void onCompleted() {
                        Logger.d("Retrofit call 1 completed");
                        mProgressBar.setVisibility(View.GONE);
                        mResultListView.setVisibility(View.VISIBLE);
                        ToastUtil.getInstance().showToast(MainActivity.this, "onCompleted");
                    }

                    @Override
                    public void onError(Throwable e) {
                        mProgressBar.setVisibility(View.GONE);
                        Logger.e(e.getMessage() + " woops we got an error while getting the list of contributors");
                        ToastUtil.getInstance().showToast(MainActivity.this, "onError");
                    }

                    @Override
                    public void onNext(List<Contributor> contributors) {
                        ToastUtil.getInstance().showToast(MainActivity.this, "onNext");
                        for (Contributor c : contributors) {
                            mAdapter.add(String.format("%s has made %d contributions to %s", c.login,
                                    c.contributions, "retrofit"));

                            Logger.d(String.format("%s has made %d contributions to %s", c.login, c.contributions,
                                    "retrofit"));
                        }
                    }
                }));
    }

    private static final int COUNT = 10;
    private static final int TIME_ALL = 5000;
    private ArrayList<Long> timeList = new ArrayList<>();

    private void method20() {

        final int COUNT = 5;
        final int TIME_ALL = 3000;
        final ArrayList<Long> timeList = new ArrayList<>();
        final ArrayList<Long> allList = new ArrayList<>();

        RxView.clicks(findViewById(R.id.iv_image)).map(new Func1<Void, Long>() {
            @Override
            public Long call(Void aVoid) {
                return System.currentTimeMillis();
            }
        }).map(new Func1<Long, Boolean>() {
            @Override
            public Boolean call(Long nowTime) {
                allList.add(nowTime);
                timeList.add(nowTime);

                boolean isOver = false;
                Log.d(TAG, "timeList.size():" + timeList.size());
                if (timeList.size() >= COUNT) {

                    if (nowTime - timeList.get(0) < TIME_ALL) {
                        isOver = true;
                    } else {
                        isOver = false;
                    }
                    timeList.clear();
                }
                return isOver;
            }
        }).subscribe(new Action1<Boolean>() {
            @Override
            public void call(Boolean aBoolean) {
                if (aBoolean) {
                    Toast.makeText(MainActivity.this, "3" + allList.size(), Toast.LENGTH_SHORT)
                            .show();
                    allList.clear();
                } else {
                    // Toast.makeText(MainActivity.this, "ok "+timeList.size(), Toast.LENGTH_SHORT).show();
                }
            }
        });
    }

    public static String timeLongToString(long data) {
        Date date = new Date(data);
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
        return formatter.format(date);
    }

    private void log(final String str) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Log.d(TAG, str);
            }
        });
    }

    /**
     * ?
     *
     * @param number
     */
    private void testFuncation(int number) {
        switch (number) {
        case 0: {
            method0();
            break;
        }

        case 1: {
            method1();
            break;
        }

        case 2: {
            method2();
            break;
        }

        case 3: {
            method3();
            break;
        }

        case 4: {
            method4();
            break;
        }

        case 5: {
            method5();
            break;
        }

        case 6: {
            method6();
            break;
        }

        case 7: {
            method7();
            break;
        }

        case 8: {
            method8();
            break;
        }

        case 9: {
            method9();
            break;
        }

        case 10: {
            method10();
            break;
        }

        case 11: {
            method11();
            break;
        }

        case 12: {
            method12();
            break;
        }

        case 13: {
            method13();
            break;
        }

        case 14: {
            method14();
            break;
        }

        case 15: {
            method15();
            break;
        }
        case 16: {
            method16();
            break;
        }

        case 17: {
            method17();
            break;
        }

        case 18: {
            method18();
            break;
        }

        case 19: {
            method19();
            break;
        }

        case 20: {
            method20();
            break;
        }

        case 21: {
            method21();
            break;
        }

        case 22: {
            method22();
            break;
        }

        case 23: {
            method23();
            break;
        }
        default: {

            break;
        }
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        mSubscription = RxUtils.getNewCompositeSubIfUnsubscribed(mSubscription);
    }

    @Override
    public void onPause() {
        super.onPause();

        RxUtils.unsubscribeIfNotNull(mSubscription);
    }

    private boolean mGoToRecycleImageView = false;

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //rl_root_layout id
        unBingListener(findViewById(R.id.rl_root_layout));
        unBindDrawables(findViewById(R.id.rl_root_layout));
        recycleImageView();
    }

    private void recycleImageView() {
        //ImageView??
        if (mGoToRecycleImageView) {
            Logger.d("onDestroy()> RecycleBitmap.recycleImageView(mImageView)");
            RecycleBitmap.recycleImageView(mImageView);
            mImageView.setImageBitmap(null);
        }

        if (mManyBitmapSuperposition != null && !mManyBitmapSuperposition.isRecycled()) {
            mManyBitmapSuperposition.recycle();
            mManyBitmapSuperposition = null;
        }

        //@link http://blog.csdn.net/yanzi1225627/article/details/8236309
        if (mCanvas != null) {
            //?
            Paint paint = new Paint();
            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
            mCanvas.drawPaint(paint);
            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
            mCanvas = null;
        }

    }

    /**
     * ???Activity onDestoryviewrootview
     * ?view?DrawingCache??
     * Activity???????
     *
     * @param view:the root view of the layout
     * @description Unbind the rootView
     * @author malin.myemail@gmail.com
     * @link http://stackoverflow.com/questions/9461364/exception-in-unbinddrawables
     * http://mp.weixin.qq.com/s?__biz=MzAwNDY1ODY2OQ==&mid=400656149&idx=1&sn=122b4f4965fafebf78ec0b4fce2ef62a&3rd=MzA3MDU4NTYzMw==&scene=6#rd
     * @since 2015.12.16
     */
    private void unBindDrawables(View view) {
        if (view != null) {
            try {
                Drawable drawable = view.getBackground();
                if (drawable != null) {
                    drawable.setCallback(null);
                } else {
                }
                if (view instanceof ViewGroup && !(view instanceof AdapterView)) {
                    ViewGroup viewGroup = (ViewGroup) view;
                    int viewGroupChildCount = viewGroup.getChildCount();
                    for (int j = 0; j < viewGroupChildCount; j++) {
                        unBindDrawables(viewGroup.getChildAt(j));
                    }
                    viewGroup.removeAllViews();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

    /**
     * Remove an onclick listener
     *
     * @param view
     * @author malin.myemail@gmail.com
     * @website https://github.com/androidmalin
     * @data 2016/01/22
     */
    private void unBingListener(View view) {
        if (view != null) {
            try {
                if (view.hasOnClickListeners()) {
                    view.setOnClickListener(null);
                }
                if (view instanceof ViewGroup && !(view instanceof AdapterView)) {
                    ViewGroup viewGroup = (ViewGroup) view;
                    int viewGroupChildCount = viewGroup.getChildCount();
                    for (int i = 0; i < viewGroupChildCount; i++) {
                        unBingListener(viewGroup.getChildAt(i));
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

    //--------------------------------------- -----------------------------------------------------------

    /**
     * :?assetsjpg,ImageView,,?--- ----
     * ?RxJava-- --
     */
    //?:?6?
    //1:???assets??
    //2:????assets??
    //3:?JPG?
    //4:??bitmap
    //5:Bitmap
    //6:??UI,ImageView???Bitmap,??ProgressBar
    private void miZhiSuoJinAndNestedLoopAndCallbackHell() {
        new Thread(new Runnable() {
            @Override
            public void run() {

                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mProgressBar.setVisibility(View.VISIBLE);
                    }
                });
                //1:???assets??
                ArrayList<String> assetsFolderNameList = ImageNameFactory.getAssetImageFolderName();

                for (String folderName : assetsFolderNameList) {

                    //2:????assets??
                    ArrayList<String> imagePathList = ImageUtils.getAssetsImageNamePathList(getApplicationContext(),
                            folderName);

                    for (final String imagePathName : imagePathList) {
                        //3:?JPG?
                        if (imagePathName.endsWith(JPG)) {

                            //4:??bitmap
                            final Bitmap bitmap = ImageUtils.getImageBitmapFromAssetsFolderThroughImagePathName(
                                    getApplicationContext(), imagePathName, Constant.IMAGE_WITH,
                                    Constant.IMAGE_HEIGHT);
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    //Logger.d(mCounter + ":" + imagePathName);

                                    //5:Bitmap
                                    createSingleImageFromMultipleImages(bitmap, mCounter);
                                    mCounter++;

                                }
                            });
                        }
                    }
                }

                //6:??UI,ImageView???Bitmap,??ProgressBar
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mImageView.setImageBitmap(mManyBitmapSuperposition);
                        mProgressBar.setVisibility(View.GONE);
                    }
                });

            }
        }).start();
    }

    /**
     * ,??:?
     * CanvasBitmap?
     *
     * @param bitmap:?Bitamp
     * @param mCounter:0
     */
    //?:
    //1:???Bitmap
    //2:BitmapBitmap,Bitmap?Canvas??.
    //3:???(64px*64px)
    //4:??Bitmap??,???,???,??
    //5:Bitmap??
    private void createSingleImageFromMultipleImages(Bitmap bitmap, int mCounter) {
        if (mCounter == 0) {
            //1:???Bitmap
            mManyBitmapSuperposition = Bitmap.createBitmap(DeviceInfo.screenWidthForPortrait,
                    DeviceInfo.screenHeightForPortrait, bitmap.getConfig());

            //2:BitmapBitmap
            mCanvas = new Canvas(mManyBitmapSuperposition);
        }
        if (mCanvas != null) {
            int left;//??
            int top;//??

            //3:???(64px*64px)
            int imageWidth = Constant.IMAGE_WITH;
            int imageHeight = Constant.IMAGE_HEIGHT;
            int number = DeviceInfo.screenHeightForPortrait / imageHeight;//??,?

            //4:??Bitmap??,???,???,??
            if (mCounter >= (mCounter / number) * number && mCounter < (((mCounter / number) + 1) * number)) {//[0,number)
                left = (mCounter / number) * imageWidth;
                top = (mCounter % number) * imageHeight;
                // Log.d(TAG,""+mCounter+" left="+left+" top="+top);

                //5:Bitmap??
                mCanvas.drawBitmap(bitmap, left, top, null);
            }
        }
    }

    /**
     * ?
     */
    private void showMath() {
        String TAG = "Math";
        for (int i = 0; i < 100; i++) {
            int ss = i / 10;
            int ww = i % 10;
            Log.d(TAG, i + "/10 ==" + ss);
            Log.d(TAG, i + "%10 ==" + ww);
        }
    }

    //-----------------------------------RxJava--?--??? -----------------------------------------------------------

    private void rxJavaSolveMiZhiSuoJinAndNestedLoopAndCallbackHell() {
        //1::

        //2:??

        //3:?IO

        //4:?

        //5:

        //6::
        mGoToRecycleImageView = false;
        Observable.from(ImageNameFactory.getAssetImageFolderName())
                //assets??,assets
                .flatMap(new Func1<String, Observable<String>>() {
                    @Override
                    public Observable<String> call(String folderName) {
                        return Observable
                                .from(ImageUtils.getAssetsImageNamePathList(getApplicationContext(), folderName));
                    }
                })
                //,jpg
                .filter(new Func1<String, Boolean>() {
                    @Override
                    public Boolean call(String imagePathNameAll) {
                        return imagePathNameAll.endsWith(JPG);
                    }
                })
                //?Bitmap
                .map(new Func1<String, Bitmap>() {
                    @Override
                    public Bitmap call(String imagePathName) {
                        return ImageUtils.getImageBitmapFromAssetsFolderThroughImagePathName(
                                getApplicationContext(), imagePathName, Constant.IMAGE_WITH, Constant.IMAGE_HEIGHT);
                    }
                }).map(new Func1<Bitmap, Void>() {
                    @Override
                    public Void call(Bitmap bitmap) {
                        createSingleImageFromMultipleImages(bitmap, mCounter);
                        mCounter++;
                        return null;
                    }
                }).subscribeOn(Schedulers.io())//?IO
                .doOnSubscribe(new Action0() {
                    @Override
                    public void call() {
                        mProgressBar.setVisibility(View.VISIBLE);
                    }
                }).observeOn(AndroidSchedulers.mainThread())//?
                .subscribe(new Subscriber<Void>() {
                    @Override
                    public void onCompleted() {
                        mImageView.setImageBitmap(mManyBitmapSuperposition);
                        mProgressBar.setVisibility(View.GONE);
                    }

                    @Override
                    public void onError(Throwable e) {
                        //Toast.makeText(MainActivity.this, ""+e.getMessage(), Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onNext(Void aVoid) {

                    }
                });
    }
}