Appstate在Android的React Native中不断变化

时间:2019-11-13 07:44:59

标签: android react-native geolocation location addeventlistener

我正在从事React本机项目,在那里我获得了位置权限。此外,我还必须始终跟踪位置权限,就像用户在安装应用程序后是否已授予权限访问权限一样,然后在一段时间后,用户进入设备设置中的应用程序设置并禁用/撤销权限。同样,一旦应用程序从后台运行到前台,我必须基于该权限检查权限,需要显示消息。

因此,我正在使用Appstate。但是,奇怪的是,在Android中,安装该应用程序后,如果用户通过“不再显示”复选框拒绝了该权限,则Appstate会始终以 background active 进行更改。 它保持循环。

componentDidMount = async () => {
    AppState.addEventListener('change', this.handleAppStateChange);
  };

  componentWillUnmount() {
    AppState.removeEventListener('change', this.handleAppStateChange);
    Geolocation.clearWatch(this.watchID);
  }

  handleAppStateChange = async nextAppState => {
    const {appState} = this.state;
    console.log('nextAppState -->', nextAppState);
    console.log('appState -->', appState);
    if (appState === 'active') {
      // do this
      this.showLoader();
      await this.requestAndroidLocationPermission();
    } else if (appState === 'background') {
      // do that
    } else if (appState === 'inactive') {
      // do that other thing
    }

    this.setState({appState: nextAppState});
  };

requestAndroidLocationPermission = async () => {
    try {
      const granted = await PermissionsAndroid.request(
        PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
        {},
      );
      if (granted === PermissionsAndroid.RESULTS.GRANTED) {
        this.getLatitudeLongitude();
      } else if (granted === PermissionsAndroid.RESULTS.NEVER_ASK_AGAIN) {
        this.hideLoader();
        this.setState({
          errorMessage: 'Location permission is denied',
          isLoading: false,
        });
      } else {
        this.hideLoader();
        this.requestAndroidLocationPermission();
      }
    } catch (err) {
      console.warn(err);
    }
  };

被拒绝,并且不再显示

后,它会继续打印(循环)
appState --> active
nextAppState --> background
appState --> active
nextAppState --> background
appState --> active
nextAppState --> background
appState --> active

它持续不断,永远不会停止。

如何处理?有什么建议吗?

3 个答案:

答案 0 :(得分:3)

我有同样的问题。不要使用AppState。有问题。

问题出在RN对“背景”的定义之内。 react-native使用android的活动(UI线程的持有人以及UI所在的位置)onPause回调作为发送“背景”信号的触发器。但是,每当某项东西出现在活动的视图层次结构前面时,就会调用onPause,例如对话框(例如权限框),其他活动(例如文件选择器)等;对于android react-native,“背景”的意思是“被外来UI元素/ android任务遮盖了”,而不是“暂停并发送到背景以执行其他操作”,从而导致了您看到的循环。最短的解决方案是在ReactActivity中重写onPause,并添加控制条件以确保仅在实际进入后台时才调用super.onPause,例如检查任务堆栈或正在调用权限对话框,因此避免这种循环/故障呼叫。第二种选择是改为提供您自己的应用程序生命周期事件,并提供明确的触发条件。

答案 1 :(得分:3)

今天我遇到了类似的问题。

我可以使用android中的“focus”和ios中的“change”来解决它。

我有一个这样的自定义钩子:

import { useEffect } from 'react';
import { AppState, Platform } from 'react-native';


const focusEvent = Platform.OS === 'ios' ? 'focus' : 'change';

const useLocationListener = () => {


  useEffect(() => {
    AppState.addEventListener(focusEvent, handleAppStateChange);

    getLocationAsync();
    return () => {
      AppState.removeEventListener(focusEvent, handleAppStateChange);
    };
  }, []);

  const handleAppStateChange = (nextAppState: string) => {
    if (nextAppState === 'active') {
      getLocationAsync();
    }
  };

  const getLocationAsync = async () => {
    const { canAskAgain, status } = await Permissions.getAsync(
      Permissions.LOCATION
    );

    if (canAskAgain) {
      const response = await Permissions.askAsync(Permissions.LOCATION);
       // handle location 
    } 
       // handle location with "status"
    
  };
};

export default useLocationListener;

答案 2 :(得分:0)

您可以使用一个标志来检查应用程序应处理后台还是仅仅是权限调用。

const shouldHandleBackground = useRef(true)

const handler = (state) => { 
    if (state === 'active' && shouldHandleBackground.current) { 
        doStuff() 
    }
}

// when calling for permisson make the flag false

shouldHandleBackground.current = false
await Android.permission.LocationPermission()
shouldHandleBackground.current = true

在权限请求后,您可以将标志设为true