1. 程式人生 > >安卓Back鍵的處理·基本+高階篇

安卓Back鍵的處理·基本+高階篇

基本用法

根據文件,安卓back鍵的處理主要就是一個事件監聽:http://reactnative.cn/post/480

BackAndroid.addEventListener('hardwareBackPress', this.onBackPressed);
BackAndroid.removeEventListener('hardwareBackPress', this.onBackPressed);

starter-kit裡,我們在App這一級別,實現了按back鍵回退導航棧的功能:

class App extends React.Component {
  componentWillMount() {
    if (Platform.OS === 'android') {
      BackAndroid.addEventListener('hardwareBackPress', this.onBackAndroid);
    }
  }
  componentWillUnmount() {
    if (Platform.OS === 'android') {
      BackAndroid.removeEventListener('hardwareBackPress', this.onBackAndroid);
    }
  }
  onBackAndroid = () => {
    const nav = this.navigator;
    const routers = nav.getCurrentRoutes();
    if (routers.length > 1) {
      nav.pop();
      return true;
    }
    return false;
  };
  ……
}

注意這裡為了方便後續removeEventListener,採用了用繫結this的函式屬性的方法來建立回撥函式,而非箭頭函式或者bind(this),這一點參考之前的博文

程式碼中,當componentWillMount的時候掛接事件。對於應用根元件來說,這個生命週期就基本和我們應用的生命週期一致了。當back鍵被按下的時候,首先檢查當前的導航棧,如果多餘一個頁面,則退回頂部的頁面。

說明:BackAndroid在iOS平臺下是一個空實現,所以理論上不做這個Platform.OS === 'android'判斷也是安全的。

使用預設行為/退出應用

back鍵的預設行為就是退出應用了。我們通常需要判斷某些條件,並最後決定是否要退出應用。上文中的例子就使用了第一種呼叫預設行為的方法:

如果所有事件監聽函式中,沒有任何一個返回真值,就會預設呼叫預設行為

如果你只掛接了一個監聽函式,那麼你的返回值就決定了是否要呼叫預設行為:true為不呼叫,false為呼叫

在上文程式碼中,我們如果導航棧多於一個頁面,就不呼叫預設行為,而如果只有一個頁面,則呼叫預設介面。

例子:“再按一次退出應用”

常有這種需求:按下back鍵以後,彈出一個toast,然後在一定時間內再按一次,才退出應用。這個程式碼就可以這樣寫:

  onBackAndroid = () => {
    if (this.lastBackPressed && this.lastBackPressed + 2000 >= Date.now()) {
      //最近2秒內按過back鍵,可以退出應用。
      return false;
    }
    this.lastBackPressed = Date.now();
    ToastAndroid.show('再按一次退出應用');
    return true;
  };

還有一種情況,我們在監聽函式中不能決定是否要呼叫預設行為,要等待一個非同步操作之後才呼叫預設行為,此時可以通過第二種辦法:

使用BackAndroid.exitApp()來退出應用。

例子:在退出應用之前儲存資料

寫法1:

  onBackAndroid = () =>{
    saveData().then(()=>{
      BackAndroid.exitApp();
    });
    return true;
  }

在監聽函式中,我們開始非同步事件,並直接return true。此時預設行為不會被呼叫。當儲存完畢後,我們呼叫exitApp(),觸發預設行為,退出應用。

寫法2:

  onBackAndroid = async () =>{
    await saveData();
    BackAndroid.exitApp();
  }

這裡我們用了async函式,async 函式總是返回一個Promise,Promise作為一個物件,也被認為是一個“真值”,所以這種情況下預設行為總是不會被呼叫。當儲存完畢後,我們呼叫exitApp(),觸發預設行為,退出應用。

根據當前介面決定作何動作

有時候我們有這樣的需求:當用戶處於某些介面下時,back鍵要做特殊的動作,如:提示使用者是否要儲存資料,或者解鎖介面禁止back鍵返回等等。此時,最佳實踐是在route或route中對應的Component上儲存關於如何處理back鍵的資訊:

  onBackAndroid = () => {
    const nav = this.navigator;
    const routers = nav.getCurrentRoutes();
    if (routers.length > 1) {
      const top = routers[routers.length - 1];
      if (top.ignoreBack || top.component.ignoreBack){
        // 路由或元件上決定這個介面忽略back鍵
        return true;
      }
      const handleBack = top.handleBack || top.component.handleBack;
      if (handleBack) {
        // 路由或元件上決定這個介面自行處理back鍵
        return handleBack();
      }
      // 預設行為: 退出當前介面。
      nav.pop();
      return true;
    }
    return false;
  };