有時候,不能讓用戶進行回退操作,如何處理?
查看返回鍵觸發了哪些方法。在打開程序后把這個方法禁止了。
問題:程序在后臺駐留,這樣就會出現,其他時候也不能使用回退按鈕。如何處理,在onpase()時方法失效。
方案一:
1 //重載onBackPressed 2 @Override 3 public void onBackPressed() { 4 // TODO Auto-generated method stub 5 //super.onBackPressed(); 6 }
查看Adroid源碼 onBackPressed?()源碼:
1 public void onBackPressed() { 2 finish(); 3 }
重寫這個方法會不會有什么問題呢?他執行一個finish();方法對其本身應該沒什么問題,那么調用出呢?
下面是Activity中調用的兩處:
Adroid源碼調用1:
1 public boolean onKeyDown(int keyCode, KeyEvent event) { 2 //當按鈕等于KEYCODE_BACK時執行下面方法,KEYCODE_BACK這個就是返回鍵 3 if (keyCode == KeyEvent.KEYCODE_BACK) { 4 //檢測版本號 ECLAIR 值為:public static final int ECLAIR = 5; 5 if (getApplicationInfo().targetSdkVersion 6 >= Build.VERSION_CODES.ECLAIR) { 7 //當大于5是執行 8 /**startTracking()解釋:調用onKeyUp()方法。 9 Call this during Callback.onKeyDown to have the system track the key through its final up (possibly including a long press). Note that only one key can be tracked at a time -- if another key down event is received while a previous one is being tracked, tracking is stopped on the previous event. 10 */ 11 event.startTracking(); 12 } else { 13 onBackPressed(); 14 } 15 return true; 16 } 17 }
Adroid源碼調用2:
1 public boolean onKeyUp(int keyCode, KeyEvent event) { 2 if (getApplicationInfo().targetSdkVersion 3 >= Build.VERSION_CODES.ECLAIR) { 4 if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking() 5 && !event.isCanceled()) { 6 onBackPressed(); 7 return true; 8 } 9 } 10 return false; 11 }
到這里可以看出我們在onBackPressed()被調用處,都是在按下返回鍵的情況下,所以可以沖寫onBackPressed方法,因為是被調用的,雖然不會出錯,但是效率應該不高。
要不我們重寫onKeyDown方法這樣可行,直接攔截。
1 @Override 2 public boolean onKeyDown(int keyCode, KeyEvent event) { 3 if(keyCode==KeyEvent.KEYCODE_BACK) { 4 Toast.makeText(getApplicationContext(), "back press", Toast.LENGTH_LONG).show(); 5 return false; // Disable back button.............. 6 }
但是會如果在按鈕處直接攔截,效果應該會高一些,這樣就不會觸發上面這兩個方法了。
于是乎我們繼續向上尋找。
細心的朋友可能發現onBackPressed()調用了finish()方法,所以干脆我們重寫它吧。
方案二:重載finish函數:
查看Android的 finish()源碼:
1 public void finish() { 2 if (mParent == null) { 3 int resultCode; 4 Intent resultData; 5 synchronized (this) { 6 resultCode = mResultCode; 7 resultData = mResultData; 8 } 9 if (Config.LOGV) Log.v(TAG, "Finishing self: token=" + mToken); 10 try { 11 if (ActivityManagerNative.getDefault() 12 .finishActivity(mToken, resultCode, resultData)) { 13 mFinished = true; 14 } 15 } catch (RemoteException e) { 16 // Empty 17 } 18 } else { 19 mParent.finishFromChild(this); 20 } 21 }
查看Android源碼中調用它的方法:
1 /** 2 * This is called when a child activity of this one calls its 3 * {@link #finish} method. The default implementation simply calls 4 * finish() on this activity (the parent), finishing the entire group. 5 * 6 * @param child The activity making the call. 7 * 8 * @see #finish 9 */ 10 public void finishFromChild(Activity child) { 11 finish(); 12 }
從說明中我們知道這個方法是在子Activity結束時調用的這個方法,所以不行,如果我們要重寫,需要進行判斷拿到的鍵值。效率不高。
繼續尋找,看看哪里執行了調用方法按鍵吧。
方案三:重寫keyevent方法 大括號里加上return true 這樣就禁用父類方法達到禁止返回鍵的目的?
方案三:重寫keyevent方法 大括號里加上return true 這樣就禁用父類方法達到禁止返回鍵的目的?
Android源碼中找來找去找到了這個:
1 /** 2 * Called to process key events. You can override this to intercept all 3 * key events before they are dispatched to the window. Be sure to call 4 * this implementation for key events that should be handled normally. 5 * 6 * @param event The key event. 7 * 8 * @return boolean Return true if this event was consumed. 9 */ 10 public boolean dispatchKeyEvent(KeyEvent event) { 11 onUserInteraction(); 12 Window win = getWindow(); 13 if (win.superDispatchKeyEvent(event)) { 14 return true; 15 } 16 View decor = mDecor; 17 if (decor == null) decor = win.getDecorView(); 18 return event.dispatch(this, decor != null 19 ? decor.getKeyDispatcherState() : null, this); 20 }
就是在按鈕觸發的事件,當然是Activity中的。到此我們發現我們找到地方了,按鈕進入后第一個處理的地方,再次我們重寫這個方法就OK了。
1 @Override 2 3 public boolean dispatchKeyEvent(KeyEvent event) { 4 5 if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) 6 { 7 8 return true; 9 10 } 11 12 return super.dispatchKeyEvent(event); 13 14 }
?