1 hardwareBackPress
我们用hardwareBackPress来监听手机物理返回键
2 js那边常用写法
BackHandler.addEventListener('hardwareBackPress', this._back);
3 我们看下Android源代码分析是怎么触发到这里来的
1) ReactActivity.java里面的部分代码如下
@Override public void onBackPressed() { if (!mDelegate.onBackPressed()) { super.onBackPressed(); } }
2 ) 进入onBackPressed()函数看看,在ReactActivityDelegate.java文件里面
public boolean onBackPressed() { if (getReactNativeHost().hasInstance()) { getReactNativeHost().getReactInstanceManager().onBackPressed(); return true; } return false; }
3)再次点击onBackPressed函数进去看下
public void onBackPressed() { UiThreadUtil.assertOnUiThread(); ReactContext reactContext = mCurrentReactContext; if (reactContext == null) { // Invoke without round trip to JS. FLog.w(ReactConstants.TAG, "Instance detached from instance manager"); invokeDefaultOnBackPressed(); } else { DeviceEventManagerModule deviceEventManagerModule = reactContext.getNativeModule(DeviceEventManagerModule.class); deviceEventManagerModule.emitHardwareBackPressed(); } }
4) 进到emitHardwareBackPressed函数里面看下
/** * Sends an event to the JS instance that the hardware back has been pressed. */ public void emitHardwareBackPressed() { getReactApplicationContext() .getJSModule(RCTDeviceEventEmitter.class) .emit("hardwareBackPress", null); }
这里发现了Android原生向js发送了消息,所以我们监听hardwareBackPress就有反映
4 测试代码如下
App.js文件如下
import React from 'react'; import { View, Text, Button, NativeModules, BackHandler} from 'react-native'; import { createStackNavigator } from 'react-navigation'; var toast = NativeModules.MyToast; class HomeScreen extends React.Component { constructor(props) { super(props); console.log("HomeScreen constructor start"); } static navigationOptions = { title : 'HomeScreen', } componentDidMount = () => { this.didFocusListener = this.props.navigation.addListener( 'didFocus', (obj) => { console.log("HomeScreen didFocus start"); BackHandler.addEventListener('hardwareBackPress', this._back); } ); this.didBlurListener = this.props.navigation.addListener( 'didBlur', (obj) => {console.log('HomeScreen didBlur start')} ); console.log("HomeScreen componentDidMount start") } componentWillUnmount() { console.log("HomeScreen componentWillUnmount start") this.didFocusListener.remove(); this.didBlurListener.remove(); } render() { var testID = 'chenyu'; return ( <View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}> <Text testID = {testID} onPress = {() => this._goto()}>Home Screen</Text> <Button onPress={() => this.props.navigation.navigate('Details', { itemId:100, otherParam:'chenyu', })} title = "go to Details"/> <Button title="Go back" onPress={() => this.props.navigation.goBack()} /> </View> ); } _show(value) { console.log(value); } _goto = () => { toast.show(); } _back = () => { console.log("home back"); } } class DetailsScreen extends React.Component { constructor(props) { super(props); console.log("DetailsScreen constructor start"); this.didFocusListener = this.props.navigation.addListener( 'didFocus', (obj) => { console.log("DetailsScreen didFocus start"); BackHandler.addEventListener('hardwareBackPress', this._back); } ); this.didBlurListener = this.props.navigation.addListener( 'didBlur', (obj) => {console.log('DetailsScreen didBlur start')} ); } _back = () => { console.log("detail back"); } static navigationOptions = ({navigation}) => { return { title : navigation.getParam('otherParam', 'no-values'), }; }; componentDidMount = () => { console.log("DetailsScreen componentDidMount start") } componentWillUnmount() { console.log("DetailsScreen componentWillUnmount start") this.didFocusListener.remove(); this.didBlurListener.remove(); } render() { const {navigation} = this.props; const itemId = navigation.getParam('itemId', 'no-values'); const otherParam = navigation.getParam('otherParam', 'no-values'); return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Details Screen</Text> <Text>itemId:{JSON.stringify(itemId)}</Text> <Text>otherParam:{JSON.stringify(otherParam)}</Text> <Button title="Go to Details... again" onPress={() => this.props.navigation.push('Details', { itemId: Math.floor(Math.random() * 100), })} /> <Button title="Go to Home" onPress={() => this.props.navigation.navigate('Home')} /> <Button title="Go back" onPress={() => this.props.navigation.goBack()} /> <Button title="Go popToTop" onPress={() => this.props.navigation.popToTop()} /> </View> ); } } const RootStack = createStackNavigator( { Home: HomeScreen, Details: DetailsScreen, }, { initialRouteName: 'Home', } ); export default class App extends React.Component { constructor(props) { super(props); } render() { return <RootStack/>; } }
5 运行结果
点击主界面的GO TO DETAILS,进入详细页面,然后分别按下2次back键,日志如下
10-27 23:39:32.498 917 1031 I ReactNativeJS: detail back 10-27 23:39:32.498 917 1031 I ReactNativeJS: home back 10-27 23:39:32.784 917 1031 I ReactNativeJS: DetailsScreen componentWillUnmount start 10-27 23:39:32.790 917 1031 I ReactNativeJS: HomeScreen didFocus start 10-27 23:39:51.164 917 1031 I ReactNativeJS: detail back 10-27 23:39:51.165 917 1031 I ReactNativeJS: home back 10-27 23:39:51.165 917 1031 I ReactNativeJS: detail back 10-27 23:39:51.165 917 1031 I ReactNativeJS: home back 10-27 23:39:51.165 917 1031 I ReactNativeJS: detail back 10-27 23:39:51.165 917 1031 I ReactNativeJS: home back 10-27 23:39:51.165 917 1031 I ReactNativeJS: home back 10-27 23:39:51.165 917 1031 I ReactNativeJS: detail back 10-27 23:39:51.166 917 1031 I ReactNativeJS: detail back 10-27 23:39:51.166 917 1031 I ReactNativeJS: home back 10-27 23:39:51.166 917 1031 I ReactNativeJS: detail back 10-27 23:39:51.166 917 1031 I ReactNativeJS: home back 10-27 23:39:51.166 917 1031 I ReactNativeJS: home back 10-27 23:39:51.621 917 1031 I ReactNativeJS: HomeScreen componentWillUnmount start
我们点击标题栏的返回按钮,和点击GO BACK,执行this.props.navigation.goBack()方法,都不会触发hardwareBackPress监听所执行的函数