RxJava入門--一步步了解Java回調機制

前段時間看了些關于RxJava的文章和代碼,感覺雖然講的很透徹,奈何理解的比較少,只會用一些最基礎的方法。囧

昨天發現了一個RxJava的視頻,好吧,我還是感覺看視頻學的比較快...
下載地址

這篇文章主要是對昨天看的視頻的回顧

不整個圖感覺不像簡書的風格

引子

現在我需要幾個計算器,幫我計算物品的單價,這個肯定很簡單的啦,代碼直接貼出來好了

public class CalcService {

    public int calc(int total, int amount) {
        int result = result = total / amount;
        return result;
    }
}

調用這個計算方法

public class MainActivity extends AppCompatActivity {

    @Bind(R.id.btn1)
    Button btn1;
    private CalcService calc;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        calc = new CalcService();
    }

    @OnClick(R.id.btn1)
    public void onClick() {
        int result = calc.calc(20,5);
        Log.e("result",result+"");
    }
}

現在問題來了

我的計算器有點老化了,計算問題特別慢,得緩兩秒才能得到答案,怎么搞


public class CalcService {

    public int calc(int total, int amount) {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        int result = result = total / amount;
        return result;
    }
}

在實際案例中,計算方法會包含大量的耗時操作,比如網絡請求,數據庫操作等等

現在運行程序發現問題所在了

Ashampoo_S_clip9.gif

這就是android中常見的阻塞線程,而如果不解決這個問題,很可能出現ANR異常

如何解決這個問題呢?

以前的我是這么做的,不是阻塞線程嗎,我放到子線程中執行不就行了?

于是會出現這樣的代碼

public class CalcService {
    int result;

    public int calc(final int total, final int amount) {
        new Thread(){
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                result = total / amount;

            }
        }.start();
        return result;
    }
}

運行之后,又出現問題了,第一次運行的時候值是0,第二次就是正確的值了

這是為什么呢?

這是因為第二次請求是得到上一次的結果

因為這個值是兩秒之后算出來的,但是在算之前就把result的默認值,也就是0,返回出去了

而第二次請求的時候,result已經被賦值為4了,他還是沒有等待2秒之后的值,而是把這個4直接返回出去了

這就是所謂的開啟異步請求獲取數據

如何得到正確的值呢?

這個時候,我們就需要 監聽回調了
改一下代碼

@OnClick(R.id.btn1)
    public void onClick() {
        calc.calc(20,5,this);

    }
    public void onSuccess(int result){
        Log.e("result",result+"");
    }

這里的區別就是傳的值發生改變了,計算器不給力,那我把自己傳過去,你算完了告訴我,省的我還得等著,啥時候完了告訴我一聲就行了

public class CalcService {
    int result;

    public void calc(final int total, final int amount, final MainActivity activity) {
        new Thread(){
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                result = total / amount;
                activity.onSuccess(result);

            }
        }.start();
    }
}

這里回調onSuccess(result) 方法,將result數據傳回去就行了

那有了onSuccess()方法,如果出現問題了,比如除數是0,是不是需要一個onFail()方法呢?
那如果調用calc()方法的不是MainActivity,而是別的地方,這該怎么修改呢?

面向接口編程

public interface OnResultListener{
        void onSuccess(int result);
        void onFail();
}
public void calc(final int total, final int amount, final OnResultListener resultListener) {
        new Thread(){
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                try {
                    result = total / amount;
                    resultListener.onSuccess(result);
                } catch (Exception e) {
                    e.printStackTrace();
                    resultListener.onFail();
                }


            }
        }.start();
    }

這樣只有需要calc()方法的地方,實現OnResultListener接口就可以調用這個方法了

通過監聽回調的形式進行解耦

public class MainActivity extends AppCompatActivity implements CalcService.OnResultListener{

    @Bind(R.id.btn1)
    Button btn1;
    private CalcService calc;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        calc = new CalcService();
    }

    @OnClick(R.id.btn1)
    public void onClick() {
        calc.calc(20,5,this);

    }
    @Override
    public void onSuccess(int result){
        Log.e("result",result+"");
    }

    @Override
    public void onFail() {

    }
}

更進一步

如何向點擊事件一樣,寫一個內部類形式的呢?

其實很簡單,只需要寫一個setOnResultListener(OnResultListener resultListener) 方法即可完美解決

private OnResultListener resultListener;
    public void setOnResultListener(OnResultListener resultListener){
        this.resultListener = resultListener;
    }

    public void calc(final int total, final int amount) {
        new Thread(){
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                try {
                    result = total / amount;
                    if(resultListener!=null){
                        resultListener.onSuccess(result);
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                    resultListener.onFail();
                }


            }
        }.start();
    }

調用起來

@OnClick(R.id.btn1)
    public void onClick() {
        calc.calc(10,2);
        calc.setOnResultListener(new CalcService.OnResultListener() {
            @Override
            public void onSuccess(int result) {
                Log.e("success",result+"");
            }

            @Override
            public void onFail() {

            }
        });

    }

設計模式真的是很神奇,讓代碼的美展現的淋漓盡致

感謝大家喜歡

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容