Appstate 不断在 Android 中的 React Native 中获得变化
Posted
技术标签:
【中文标题】Appstate 不断在 Android 中的 React Native 中获得变化【英文标题】:Appstate keep on getting change in React native in Android 【发布时间】:2020-03-08 23:22:45 【问题描述】:我正在开发 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
它继续,永不停止。
如何处理?有什么建议吗?
【问题讨论】:
你使用的是什么版本的 React Native?最新的文档说明如下。 [facebook.github.io/react-native/docs/appstate#change] "通过监听更改事件类型并提供处理程序 TODO 为 AppState 更改添加处理程序:既然 AppState 是 NativeEventEmitter 的子类,我们可以弃用 addEventListener 和 removeEventListener 并直接使用 addListener 和 listener.remove()。不过,这将是一个重大变化,因为方法和事件名称都不同(当前要求 addListener 事件是全局唯一的)。" 你好,你的问题解决了吗,我也遇到同样的问题,不知道是什么问题!!! @Yasir,不是我没有解决 我遇到了同样的问题,有人解决了吗? 【参考方案1】:我遇到了同样的问题。不要使用 AppState。有问题。
问题在于 RN 对“背景”的定义。 react-native 使用 android 的活动(UI 线程的持有者和您的 UI 所在的位置)onPause 回调作为发送“背景”信号的触发器。但是,onPause 每次出现在您的活动视图层次结构前面时都会调用,例如对话框(例如权限框)、其他活动(例如文件选择器)等;对于 android react-native,“背景”意味着“被外部 UI 元素/android 任务遮蔽”而不是“暂停并发送到后台执行其他操作”,从而导致您看到的循环。最短的解决方案是在 ReactActivity 中覆盖 onPause,并添加控制条件以确保 super.onPause 仅在您实际进入后台时调用,例如检查您的任务堆栈,或者如果正在调用权限对话框,因此您避免这种循环/错误调用。第二种选择是提供您自己的应用生命周期事件,并提供明确的触发条件。
【讨论】:
不错!你能给我一些想法如何解决它吗?如何提供自己的应用生命周期事件? 你需要检查你的应用的任务堆。通常,您将在顶部进行一项活动。如果您的活动被另一个隐藏,但在您的应用程序中,或由您的应用程序调用,您的任务堆中将有两个进程。所以你知道你不在后台。如果您有任何 DialogFragments 处于活动状态,您也可以进行间谍活动,这也会隐藏应用程序。根据这些指标,您需要通过 DeviceEventEmitter 发送一个事件,指示应用程序的实际状态。这取决于您应用的设计。 @FcoP。任何文档或参考链接都将受到高度赞赏。【参考方案2】:今天我遇到了类似的问题。
我可以使用 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;
【讨论】:
嘿伙计,工作。但是,在您的示例中,ios 返回“更改”,而 android 返回“焦点”(您将它们混淆了;)) 也适用于我,但focus
事件不会发送应用程序状态,因此 getLocationAsync
在此示例中永远不会被触发。我想你也需要一个平台签到这里if (Platform.OS === 'android' || nextAppState === 'active')
【参考方案3】:
您可以使用一个标志来检查应用是应该处理后台还是只是一个权限调用。
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
在请求许可后,您可以将标志设为真
【讨论】:
以上是关于Appstate 不断在 Android 中的 React Native 中获得变化的主要内容,如果未能解决你的问题,请参考以下文章
cshtml 中的 AppState = Context.Application 和 控制器中的 Application 也相等
JMonkeyEngine中是如何使用AppState来管理和实现游戏场景切换的?
TypeError:未定义不是对象(评估“appState.remove”)
ReactNative: 使用AppState的API获取App的状态