Android事件處理模型
事件處理是Android編程中非常重要的一個部分,因為Android應用在運行過程中會產生許多各種各樣的事件(動作),應用必須為這些動作執行對應的響應代碼;將產生的動作和響應聯絡起來的方式就是事件處理機制。Android平台提供了兩種事件處理機制,分別是基於監聽的模式和基於回調的模式。
1. 基於監聽的事件處理模型1.1 組成部分
事件來源:事件發生的地方,比如某個按鈕、文字框等 事件:事件類型,通過Event對象表達 事件監聽器:負責監聽某種的事件類型,並執行相應的操作
基於監聽的事件處理模型首先需要建立一個事件監聽器,該事件監聽器可以監聽某一類型的事件;然後,把事件監聽器註冊到某個組件中;當該組件上發生了可以被該監聽器監聽的動作後,組件會產生一個代表該動作的Event對象,並把Event對象傳遞給監聽器。在Android中,產生Event對象以及Event對象的傳遞不需要程式員介入,系統會自動去處理這一步操作。程式員需要做的就是指定事件來源,並在該事件來源上註冊對應於某個事件類型的事件監聽器,並重寫相應的處理代碼。
xml布局代碼
Java代碼
public class MainActivity extends Activity { private Button mClickBtn; // 建立監聽器,監聽“點擊”事件 final View.OnClickListener listener = new View.OnClickListener() { @Override public void onClick(View v) { L.d("You click btn_click!"); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mClickBtn = (Button) findViewById(R.id.btn_click); // 為mClickBtn組件設定事件類型為‘點擊’的監聽器 mClickBtn.setOnClickListener(listener);}
}
上述代碼在MainActivity中建立了一個監聽器listener,該監聽器負責監聽“點擊”事件,然後在onCreate方法中通過setOnClickListener方法將該監聽器註冊到mClickBtn上。
在上述代碼中,監聽器通過匿名內部類實現,並建立了一個該匿名內部類的對象,然後將該對象註冊到事件來源上,這種方式與直接在設定監聽器的位置建立監聽器(如下所示)相比,好處在於該監聽器對象可以重用。
mClickBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { L.d("You click btn_click!"); }});
注意
一般監聽器都通過內部類實現,因為內部類可以訪問到外部類中包含的組件或欄位,而一般監聽器都會涉及到對外部類中相關組件或欄位的操作。如果通過外部類實現,還需要傳遞本類的引用,而且代碼也不是很直觀。 一般在監聽器中不實現商務邏輯,如果監聽器確實需要處理邏輯,可以把邏輯封裝在外部類的方法中,然後在監聽器中調用該方法(監聽器只負責簡單的資料展示或資料傳遞,邏輯處理通過專門的方法實現,這種編碼方式更符合物件導向的設計原則)
2. 基於回調的事件處理模型
上面所說的基於監聽的處理方式是一種委託的事件處理方式,即將事件處理委託給專門負責處理事件的監聽器;而接下來要討論的基於回調的處理方式則是一種主動式的事件處理方式,即事件由事件來源本身處理。從代碼實現上來說,要添加事件處理的組件需要實現特定的介面,並重寫介面中的某些方法;當對應的事件發生時,系統會回調該組件中被重寫的方法。舉個例子
XML布局代碼
Java代碼
// 自訂MyButton類public class MyButton extends Button { public MyButton(Context context, AttributeSet set) { super(context, set); }// 設定回呼函數 @Override public boolean onKeyDown(int keyCode, KeyEvent event) { super.onKeyDown(keyCode, event); Log.i("MyButton", "MyButton onKeyDown"); return false; }}public class MainActivity extends Activity { private Button mClickBtn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mClickBtn = (Button) findViewById(R.id.btn_click); // 設定監聽器 mClickBtn.setOnKeyListener(new View.OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { Log.i("mClickBtn", "onKeyListener"); return false; } }); }// 設定Activity回呼函數 @Override public boolean onKeyDown(int keyCode, KeyEvent event) { super.onKeyDown(keyCode, event); Log.i("MainActivity", "MainActivity onKeyDown"); return false; }}
運行上述代碼後,在logcat中會列印:
onKeyListener
MyButton onKeyDown
MainActivity onKeyDown
也就是說,事件發生後被調用的先後順序是:監聽器 –> 組件的回呼函數;當組件回呼函數返回的值為false時,事件會繼續向上傳播,所以會繼續調用Acitivity中的回呼函數;如果監聽器中的onKey方法返回true,則不會調用組件的回呼函數。