简体   繁体   English

Appstate 继续在 Android 中更改 React Native

[英]Appstate keep on getting change in React native in Android

I am working on React native project and there I am taking location permissions.我正在开发 React 本机项目,并且正在获取位置权限。 Also I have to track location permissions always like if user has given permission access after install the application and then after sometime user goes to the app settings in device settings and disable/revoked the permissions.此外,我必须始终跟踪位置权限,例如用户在安装应用程序后授予权限访问权限,然后一段时间后用户转到设备设置中的应用程序设置并禁用/撤销权限。 Again once app comes from background to foreground, I have to check permission based on that, Needs to show the messages.再次,一旦应用程序从后台到前台,我必须基于此检查权限,需要显示消息。

So that, I am using Appstate.所以,我正在使用 Appstate。 But, In Android strangely, After installed the application, If user denied the permission with "Dont show again" checkbox, Then Appstate getting keep on changing with background and active always.但是,奇怪的是,在 Android 中,安装应用程序后,如果用户使用“不再显示”复选框拒绝了该权限,则 Appstate 会随着背景不断变化并始终处于活动状态 It is keep on loop.它保持循环。

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);
    }
  };

It is keep on printing (loop) after denied permission with Don't show again拒绝再次显示的许可后继续打印(循环)

appState --> active
nextAppState --> background
appState --> active
nextAppState --> background
appState --> active
nextAppState --> background
appState --> active

It goes on and never stop.它继续,永不停止。

How to handle this?如何处理? Any suggestions?有什么建议么?

I had the same problem.我有同样的问题。 Do not use AppState.不要使用 AppState。 Is faulty.有故障。

the problem lies within RN's definition of "background".问题在于 RN 对“背景”的定义。 react-native uses android's activity (the holder of the UI thread and where your UI lives) onPause callback as the trigger for sending the "background" signal. react-native 使用 android 的活动(UI 线程的持有者和您的 UI 所在的位置)onPause 回调作为发送“背景”信号的触发器。 But, onPause is called everytime SOMETHING comes in front of your activity's view hierachy, like Dialogs (like the permission box), other activities (like a file picker), etc;但是,onPause 每次出现在您的活动视图层次结构前面时都会调用,例如对话框(例如权限框)、其他活动(例如文件选择器)等; for android react-native, "background" means "shadowed by a foreign UI element/android task" rather than "paused and sent to background to do something else", thus causing the loops you see.对于 android react-native,“背景”表示“被外部 UI 元素/android 任务遮蔽”而不是“暂停并发送到后台执行其他操作”,从而导致您看到的循环。 The shortest solution is to override onPause in your ReactActivity, and add control conditions to make sure super.onPause is only called when you are actually going to background, like checking your task stack, or if the permission dialog is being called, so you avoid this kind of loop/faulty call.最短的解决方案是在 ReactActivity 中覆盖 onPause,并添加控制条件以确保 super.onPause 仅在您实际进入后台时调用,例如检查您的任务堆栈,或者如果正在调用权限对话框,因此您避免这种循环/错误调用。 A second option would be to provide your own app lifecycle event instead, with clear triggering conditions.第二种选择是提供您自己的应用程序生命周期事件,并带有明确的触发条件。

today I had a similar problem.今天我遇到了类似的问题。

I could solve it using "focus" in android and "change" in ios.我可以使用 android 中的“焦点”和 ios 中的“更改”来解决它。

I have a custom hook like this:我有一个这样的自定义钩子:

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;

You can use a flag that check whether app should handle background or it's just a permission call.您可以使用一个标志来检查应用程序是否应该处理后台或者它只是一个权限调用。

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

and after permission request you can make flag true并且在获得许可请求后,您可以使标志为真

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM