Andriod回調機制詳解

  作爲一個程序員,在我們的日常開發中總是免不了模塊與模塊之間的調用,一般來說調用方式一般可以分爲三種:

同步調用、異步調用、回調。

  1、同步調用:這種調用方式就是簡單的類A調用類B裏面的方法,並且整個過程是在同一個線程裏面完成的。

  2、異步調用:有時候我們調用的方法太耗時了,這樣就會形成線程阻塞,造成用戶體驗不好。這個時候呢我們就會開啓一個新的線程來執行耗時的方法,這種方式稱爲異步調用。

  3、回調:我們在A類裏面的a()方法調用B類的b()方法,待到b()方法執行完畢後再回過頭來調用A類裏面的c()方法,這樣的方式稱爲回調。在我們的實際開發中一般不會直接在A類中直接寫回調方法,這樣做耦合度太高,不利於後期維護。我們一般會定義一個回調接口,然後進行相關的操作。具體應該怎麼做呢?請往下看:

  首先先定義一個回調接口:

public interface Callback {
	void callbackA(String result);
}

  然後實現該接口:

public class Instance implements Callback{
	@Override
	public void callbackA(String result) {
		System.out.println("請求結果:" + result);
	}
}

然後定義一個被調用的類B:

public class B {

	private Callback mCallback;

	public B(Callback callback) {
		mCallback = callback;
	}

	public void b() {
		try {
			// 模擬耗時操作
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		mCallback.callbackA("請求成功");
	}
}

這裏我們首先在構造器裏面傳入Callback接口的實例,然後在這裏定義一個方法b(),裏面新開了一個線程模擬耗時操作,然後在方法b()中調用回調方法callbackA()。

  最後我們定義調用類A:

public class A {
	public static void main(String[] args) {
		Callback callback = new Instance();
		B b = new B(callback);
		new Thread(new Runnable() {

			@Override
			public void run() {
				b.b();
			}
		}).start();
		System.out.println("這是A類的方法");
	}
}

在這個方法中我們用了Java多態的特性,父類的引用指向子類的實現。然後把對象傳入類B,最後開啓新線程調用b對象的方法b(),因爲b()方法屬於耗時操作,如果不開啓新線程會導致線程阻塞。

效果如下:

  通過例子我們可以看到,既沒有方法阻塞,又得到了我們想要的結果。perfect!

  在我們的實際開發中,一般是採用匿名類的方式來完成的,我們可以把上面的代碼做一下小修改。

  首先改一下A類,改動後如下:

public class A {
	public static void main(String[] args) {
		B b = new B(new Callback() {
			@Override
			public void callbackA(String result) {
				System.out.println("請求結果:" + result);
			}
		});
		new Thread(new Runnable() {
 
			@Override
			public void run() {
				b.b();
			}
		}).start();
		System.out.println("這是A類的方法");
	}
}

然後刪掉Instance這個類就可以啦。

看了上面的代碼是不是有似曾相識的感覺?沒錯,在我們的Android中有很多地方都是用到了這種回調機制。舉個簡單的例子吧,比如我們平時的按鈕的點擊事件就是採用的這種方式:

button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "點擊事件回調", Toast.LENGTH_SHORT).show();
            }
        });

我們可以看下setOnclickListener()方法具體實現:

public void setOnClickListener(@Nullable OnClickListener l) {
        if (!isClickable()) {
            setClickable(true);
        }
        getListenerInfo().mOnClickListener = l;
    }

我們可以看到傳入的OnclickListener對象賦給了getListenerInfo()方法裏的mOnClickListener屬性,接着看下getListenerInfo()方法:

ListenerInfo getListenerInfo() {
        if (mListenerInfo != null) {
            return mListenerInfo;
        }
        mListenerInfo = new ListenerInfo();
        return mListenerInfo;
    }

我們可以看到,這個方法返回的是Listenerinfo對象,然後在這個類裏面找到mOnClickListener屬性,打開後發現這是一個接口:

public interface OnClickListener {
        /**
         * Called when a view has been clicked.
         *
         * @param v The view that was clicked.
         */
        void onClick(View v);
    }

看到這裏是不是感覺跟上面的例子有點像?沒錯,Button點擊事件整體的思想其實就是回調機制,但是需要注意的是:我的例子採用的是異步回調,而Button是同步回調,具體的代碼實現感興趣的可以自己去看下源碼。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章