Back Button React native exit app

I have put android back button exit the app functionality in my react native app in my home screen. But when I press android back button on other screens then also it is getting called.

componentDidMount() {

    if (Platform.OS == "android") {
        BackHandler.addEventListener('hardwareBackPress', this.handleBackButton);                           
  }
    this._setupGoogleSignin();           
    this._getUserDetails();
    const { navigate } = this.props.navigation;
    console.log("object url is", this.state.postsArray[0].url);

}

handleBackButton = () => {               
    Alert.alert(
        'Exit App',
        'Exiting the application?', [{
            text: 'Cancel',
            onPress: () => console.log('Cancel Pressed'),
            style: 'cancel'
        }, {
            text: 'OK',
            onPress: () => BackHandler.exitApp()
        }, ], {
            cancelable: false
        }
     )
     return true;
   }
componentWillUnmount() {
    BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton);
  }

Answers


If your HomeScreen is still mounted when you navigate to other screens or while unmounting the HomeScreen if you don't remove the EventListener it will be still called.

You should clear the EventListener on navigate or unmount,

onButtonPress = () => {
  BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton);
  // then navigate
  navigate('NewScreen');
}

handleBackButton = () => {
 Alert.alert(
     'Exit App',
     'Exiting the application?', [{
         text: 'Cancel',
         onPress: () = > console.log('Cancel Pressed'),
         style: 'cancel'
     }, {
         text: 'OK',
         onPress: () = > BackHandler.exitApp()
     }, ], {
         cancelable: false
     }
  )
  return true;
} 

componentDidMount() {
  BackHandler.addEventListener('hardwareBackPress', this.handleBackButton);
}

componentWillUnmount() {
  BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton);
}

If you don't want the Alert message to appear in other component/screen but only in one specific component/screen, you can follow this.

import { withNavigationFocus } from 'react-navigation';

class TestComponent extends Component {
  componentWillMount() {
    BackHandler.addEventListener('hardwareBackPress', this.handleBackButton);
  }

  componentWillUnmount() {
    BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton);
  }

  handleBackButton = () => {
    if (this.props.isFocused) {
      Alert.alert(
        'Exit App',
        'Exiting the application?',
        [
          {
            text: 'Cancel',
            onPress: () => console.log('Cancel Pressed'),
            style: 'cancel'
          },
          {
            text: 'OK',
            onPress: () => BackHandler.exitApp()
          }
        ],
        {
          cancelable: false
        }
      );
      return true;
    }
  };
} 

export default withNavigationFocus(TestComponent );

The BackHandler that will show an Alert message will only work in TestComponent


We can add subscriptions for didfocus inside our main App Container.We can add our logic to check for button tapped with a static variable.

import {  Alert,  BackHandler,  ToastAndroid } from 'react-native';
import {  StackActions } from 'react-navigation';
import { Toast } from 'native-base';
// common statless class variable.
let backHandlerClickCount = 0;

class App extends React.Component {
    constructor(props) {
      super(props);
      // add listener to didFocus
      this._didFocusSubscription = props.navigation.addListener('didFocus', payload =>
        BackHandler.addEventListener('hardwareBackPress', () => this.onBackButtonPressAndroid(payload)));
    }

    // remove listener on unmount 
    componentWillUnmount() {
      if (this._didFocusSubscription) {
        this._didFocusSubscription.remove();
      }
    }

    onBackButtonPressAndroid = () => {
      const shortToast = message => {
        // ToastAndroid.showWithGravityAndOffset(
        //     message,
        //     ToastAndroid.SHORT,
        //     ToastAndroid.BOTTOM,
        //     25,
        //     50
        // );

        // ios & android
        Toast.show({
            text: message,
            type: 'warning',
            position: 'top',
            duration: 3000,
        });
        }

        const {
          clickedPosition
        } = this.state;
        backHandlerClickCount += 1;
        if ((clickedPosition !== 1)) {
          if ((backHandlerClickCount < 2)) {
            shortToast('Press again to quit the application!');
          } else {
            BackHandler.exitApp();
          }
        }

        // timeout for fade and exit
        setTimeout(() => {
          backHandlerClickCount = 0;
        }, 2000);

        if (((clickedPosition === 1) &&
            (this.props.navigation.isFocused()))) {
          Alert.alert(
            'Exit Application',
            'Do you want to quit application?', [{
              text: 'Cancel',
              onPress: () => console.log('Cancel Pressed'),
              style: 'cancel'
            }, {
              text: 'OK',
              onPress: () => BackHandler.exitApp()
            }], {
              cancelable: false
            }
          );
        } else {
          this.props.navigation.dispatch(StackActions.pop({
            n: 1
          }));
        }
        return true;
      }

    }

Guyz please do understand it might not only be the problem with react native. Be careful while integrating it with firebase. The recent firebase version has the problem of integrating back button in react-native apps!! Please downgrade the firebase version to firebase-version @5.0.3 and then recheck whether it works or not! I had the same issue and was worried for days. I finally downgraded to @5.0.3 version and now the back button works perfectly fine! You may downgrade to lower versions if still facing the problem.


BackHandler.addEventListener('hardwareBackPress', function() {
    Alert.alert(
      'Thoát Khỏi Ứng Dụng',
      'Bạn có muốn thoát không?', [{
          text: 'Cancel',
          onPress: () => console.log('Cancel Pressed'),
          style: 'cancel'
      }, {
          text: 'OK',
          onPress: () => BackHandler.exitApp()
      }, ], {
          cancelable: false
      }
   )
   return true;
})

You can always dynamically modify what the callback function for the BackHandler.addEventListener is based on the current scene (using react-native-router-flux makes this easy).

import { Actions } from 'react-native-router-flux'

handleBackPress = () => {
 switch (Actions.currentScene) {
   case 'home':
     BackHandler.exitApp()
     break

   default: Actions.pop()
 }

 return true
}

The full gist can be found here: https://gist.github.com/omeileo/f05a068557e9f0a2d8a24ecccd2f3177


Need Your Help

How to set HttpResponse timeout for Android in Java

java android timeout httpresponse

I have created the following function for checking the connection status: