標(biāo)簽(空格分隔):Android
分發(fā)機(jī)制原理分析請(qǐng)參考博客一博客二博客三
還是不太懂里面的原理分析???
已經(jīng)理解的部分:###
1、Android中用戶(hù)消息主要分為按鍵消息和觸摸消息,他們兩者之間在分發(fā)的過(guò)程中稍有不同,按鍵消息在發(fā)往客戶(hù)端時(shí)先要調(diào)用WMS中的某些函數(shù),如果WMS中并沒(méi)有處理這個(gè)消息,那么才發(fā)往客戶(hù)端的。
按鍵消息直接發(fā)送給當(dāng)前窗口,而觸摸消息則根據(jù)觸摸坐標(biāo)位置來(lái)匹配所有窗口,并判斷坐標(biāo)落到哪個(gè)窗口區(qū)域中,然后把消息發(fā)送給相應(yīng)的窗口。對(duì)于按鍵消息還會(huì)涉及到“生理長(zhǎng)按”的檢測(cè),比如一直按住某個(gè)鍵,那么會(huì)產(chǎn)生一些列的按鍵消息,然而第1個(gè)和第2個(gè)消息之間往往會(huì)間隔較長(zhǎng)的時(shí)間,這種設(shè)計(jì)是人類(lèi)本身的生理特點(diǎn)決定的,因?yàn)閺陌聪碌綇椘鸬倪^(guò)程中,如果CPU處理太快,會(huì)導(dǎo)致產(chǎn)生多次該消息,這往往不是用戶(hù)所期望的,因此Android把這種消息處理延遲加入到了消息處理前端中,應(yīng)用程序不需要關(guān)心第一次的延遲,只需按普通的DOWN消息處理。
當(dāng)按下物理按鍵的菜單鍵、Home鍵、返回鍵時(shí)會(huì)觸發(fā)onKeyDown事件。
執(zhí)行順序是這樣的:
當(dāng)物理按鍵按下時(shí)
首先觸發(fā)dispatchKeyEvent
然后觸發(fā)onUserInteraction
再次onKeyDown
如果按下緊接著松開(kāi),則是倆步
緊跟著觸發(fā)dispatchKeyEvent
然后觸發(fā)onUserInteraction
再次onKeyUp
所以dispatchKeyEvent只是監(jiān)控案件不管是activity還是activitygroup都會(huì)觸發(fā)。
不太肯定關(guān)于dispatchKeyEvent()::::###
注意上面的過(guò)程有事件分發(fā)的機(jī)制,假如是ActivityGroup時(shí),應(yīng)該要在父級(jí)的activity重寫(xiě)dispatchKeyEvent方法返回false(可能是返回true)(此事件是交由下一級(jí)處理),不然子級(jí)的activity是不會(huì)有反應(yīng)的。例如在TabHost的時(shí)候
關(guān)于onKeyDown()、onBackPressed、onKeyUp()、onCreateOptionsMenu、###
可以在這四個(gè)方法中判斷KeyEvent.KEYCODE_BACK、KeyEvent.KEYCODE_MENU、KeyEvent.KEYCODE_SEARCH等,用于處理按下返回鍵、菜單鍵、search鍵。下面我們以onKeyDown()為例。
一般我們直接在activity 中直接重現(xiàn)onKeyDown事件,
有個(gè)返回值問(wèn)題:renturn true,和return false。
暫時(shí)理解的意思是:返回true 是表示處理完這個(gè)按鍵事件,這個(gè)按鍵事件被吃掉。eyEvent事件就不會(huì)傳到Activity中,也即是在Activity中獲取不到這個(gè)KeyEvent事件,也就是在Activity中重寫(xiě)onKeyDown無(wú)效。
返回false 是表示暫時(shí)處理完這個(gè)按鍵事件,但是沒(méi)有處理完全,按鍵事件沒(méi)有被吃掉,Activity還會(huì)響應(yīng)按鍵事件。KeyEvent事件還會(huì)傳到Activity中,即在Activity中可以獲取KeyEvent事件,也就是在Activity中重寫(xiě)onKeyDown有效
如果我們想在View中攔截監(jiān)聽(tīng)onKeyDown事件,setOnKeyListener(new OnKeyListener() ),然后重寫(xiě)onKey()方法,寫(xiě)完自己的處理邏輯后返回true,再次攔截按鍵消息,不再傳遞給activity
好現(xiàn)在說(shuō)說(shuō)一般的情況下不再view攔截按鍵消息時(shí),在activity的處理方式:先說(shuō)一下OnkeyDown方法和OnBackPressed方法的區(qū)別;onKeyDown是兼容Android 1.0到Android 2.1,而OnBackPressed是僅適用于2.0或以上,不需要處理返回值問(wèn)題
public boolean onKeyDown(int keyCode, KeyEvent event)
{
//按下的如果是BACK,同時(shí)沒(méi)有重復(fù)
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0)
{
這里寫(xiě)自己的操作
return true;//表示activity已經(jīng)處理完畢
}
//否則父類(lèi)調(diào)用默認(rèn)的處理方法
return super.onKeyDown(keyCode, event);
}
同時(shí)還有一種情況,就是在以前開(kāi)發(fā)的程序中使用的是onKeyDown方法,但是后續(xù)版本為了兼容OnBackPressed方法。就需要兩者之間進(jìn)行嵌套。具體的方法如下:
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// 是否觸發(fā)按鍵為back鍵
if (keyCode == KeyEvent.KEYCODE_BACK) {
onBackPressed();
return true;
} else {// 如果不是back鍵正常響應(yīng)
return super.onKeyDown(keyCode, event);
}
}
利用時(shí)間差方法完成兩次返回鍵退出,防止誤操作。
// 退出時(shí)間
private long currentBackPressedTime = 0;
// 退出間隔
private static finalint BACK_PRESSED_INTERVAL = 2000;
//重寫(xiě)onBackPressed()方法,繼承自退出的方法
@Override
publicvoid onBackPressed() {
// 判斷時(shí)間間隔
if (System.currentTimeMillis()- currentBackPressedTime > BACK_PRESSED_INTERVAL) {
currentBackPressedTime = System.currentTimeMillis();
Toast.makeText(this, "再按一次返回鍵退出程序", Toast.LENGTH_SHORT).show();
} else {
// 退出
finish();
}
}
onKeyDown()除了監(jiān)控返回鍵之外還可以監(jiān)控菜單鍵,Home鍵,Search鍵。但是監(jiān)控Home鍵比較麻煩,不像一般的監(jiān)控返回鍵與菜單鍵一樣簡(jiǎn)單。
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(keyCode == KeyEvent.KEYCODE_BACK) {
// 監(jiān)控返回鍵
new Builder(TestActivity.this).setTitle("提示")
.setIconAttribute(android.R.attr.alertDialogIcon)
.setMessage("確定要退出嗎?")
.setPositiveButton("確認(rèn)", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
TestActivity.this.finish();
}})
.setNegativeButton("取消", null)
.create().show();
return false;
} else if(keyCode == KeyEvent.KEYCODE_MENU) {
// 監(jiān)控菜單鍵
Toast.makeText(TestActivity.this, "Menu", Toast.LENGTH_SHORT).show();
else if(keyCode == KKeyEvent.KEYCODE_SEARCH) {
// 監(jiān)控Search鍵
Toast.makeText(TestActivity.this, "Menu", Toast.LENGTH_SHORT).show();
return false;
}
return super.onKeyDown(keyCode, event);
}
監(jiān)聽(tīng)Home鍵###
Android對(duì)屏幕下方常用的四個(gè)按鍵消息處理是不一致的:
- 搜索按鍵的消息在onKeyDown或者onKeyUp中接收;
- 菜單按鍵的消息在onCreateOptionsMenu、onKeyDown或onKeyUp方法中接收;
- 返回按鍵的消息可以在onBackPressed、onKeyDown或onKeyUp方法中接收。
- 對(duì)于Home按鍵消息的處理,既不能通過(guò)onKeyDown、onKeyUp接收到,android也沒(méi)有提供專(zhuān)有的方法接收按鍵消息,個(gè)人估計(jì)home按鍵算是一個(gè)app異常信息處理的后門(mén),比如ANR后,按其它按鈕沒(méi)有比按Home按鍵好使,所以android為了能夠提供更好的用戶(hù)體驗(yàn),沒(méi)有提供供用戶(hù)監(jiān)聽(tīng)home按鍵消息的方法。
網(wǎng)上提供了各種各樣監(jiān)聽(tīng)Home按鍵消息的方法,比如說(shuō):重寫(xiě)onAttachedToWindow方法,監(jiān)控Home按鍵。但是效果不太好
@Override
public void onAttachedToWindow() {
this.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD);
super.onAttachedToWindow();
}
可以考慮這種方法:參考博客
在每次點(diǎn)擊Home按鍵時(shí)都會(huì)發(fā)出一個(gè)action為Intent.ACTION_CLOSE_SYSTEM_DIALOGS的廣播,它是關(guān)閉系統(tǒng)Dialog的廣播,我們可以通過(guò)注冊(cè)它來(lái)監(jiān)聽(tīng)Home按鍵消息,我自定義了一個(gè)home按鍵監(jiān)聽(tīng)工具類(lèi),代碼如下,使用說(shuō)明參見(jiàn)類(lèi)名上方的使用說(shuō)明: import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter;
home按鍵監(jiān)聽(tīng)工具類(lèi):
/**
* Home按鍵監(jiān)聽(tīng)類(lèi)
* 使用說(shuō)明:
* 1、初始化HomeListen
* HomeListen homeListen = new HomeListen( this );
* homeListen.setOnHomeBtnPressListener( new setOnHomeBtnPressListener(){
* @Override
* public void onHomeBtnPress( ){
* // 按下Home按鍵回調(diào)
* }
*
* @Override
* public void onHomeBtnLongPress( ){
* // 長(zhǎng)按Home按鍵回調(diào)
* }
* });
*
* 2、在onResume方法中啟動(dòng)HomeListen廣播:
* homeListen.start();
*
* 3、在onPause方法中停止HomeListen廣播:
* homeListen.stop( );
* */
public class HomeListen {
public HomeListen(Context context) {
mContext = context;
mHomeBtnReceiver = new HomeBtnReceiver( );
mHomeBtnIntentFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
}
public void setOnHomeBtnPressListener( OnHomeBtnPressLitener onHomeBtnPressListener ){
mOnHomeBtnPressListener = onHomeBtnPressListener;
}
public void start( ){
mContext.registerReceiver( mHomeBtnReceiver, mHomeBtnIntentFilter );
}
public void stop( ){
mContext.unregisterReceiver( mHomeBtnReceiver );
}
class HomeBtnReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
receive( context, intent );
}
}
private void receive(Context context, Intent intent){
String action = intent.getAction();
if (action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
String reason = intent.getStringExtra( "reason" );
if (reason != null) {
if( null != mOnHomeBtnPressListener ){
if( reason.equals( "homekey" ) ){
// 按Home按鍵
mOnHomeBtnPressListener.onHomeBtnPress( );
}else if( reason.equals( "recentapps" ) ){
// 長(zhǎng)按Home按鍵
mOnHomeBtnPressListener.onHomeBtnLongPress( );
}
}
}
}
}
public interface OnHomeBtnPressLitener{
public void onHomeBtnPress( );
public void onHomeBtnLongPress( );
}
private Context mContext = null;
private IntentFilter mHomeBtnIntentFilter = null;
private OnHomeBtnPressLitener mOnHomeBtnPressListener = null;
private HomeBtnReceiver mHomeBtnReceiver = null;
}
在Activity中做如下調(diào)用即可:
public class HomeListenActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home_listen_layout);
initHomeListen( );
}
@Override
protected void onResume( ) {
super.onResume();
mHomeListen.start( );
}
@Override
protected void onPause() {
super.onPause();
mHomeListen.stop( );
}
private void initHomeListen( ){
mHomeListen = new HomeListen( this );
mHomeListen.setOnHomeBtnPressListener( new OnHomeBtnPressLitener( ) {
@Override
public void onHomeBtnPress() {
showToast( "按下Home按鍵!" );
}
@Override
public void onHomeBtnLongPress() {
showToast( "長(zhǎng)按Home按鍵!" );
}
});
}
private void showToast( String toastInfoStr ){
Toast.makeText( this, toastInfoStr, Toast.LENGTH_LONG ).show( );
}
private HomeListen mHomeListen = null;
}