英文:
Flutter Background Service how to judge apps goes back from background to foreground?
问题
I understand that you want a translation of the code-related content. Here's the translation:
我明白您需要代码相关内容的翻译。以下是翻译:
我想要实现的目标:
- 判断应用程序在后台或前台运行,位于后台服务内部;
我尝试过的:
- 使用WidgetBindingObserver检测应用程序的生命周期时,发现无法更改后台服务;
这是我目前用于检测应用程序生命周期的方法:
```dart
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
debugPrint('App State = $state');
DbUserUranus? user = AppData.instance()!.user;
if (user != null) {
if (state == AppLifecycleState.inactive ||
state == AppLifecycleState.paused) {
ChatApp.instance()!
.eventsSender
.sendPresence(PresenceType.Away, user.user_addr);
GlobalSettings.isAppInBackground = true;
debugPrint("--------------- ^^^^^^^^^^ 应用在后台运行!!");
} else if (state == AppLifecycleState.resumed) {
ChatApp.instance()!
.eventsSender
.sendPresence(PresenceType.Available, user.user_addr);
GlobalSettings.isAppInBackground = false;
debugPrint("--------------- ^^^^^^^^^^^ 应用恢复前台!");
}
}
}
问题是,我从主线程更改的值在后台服务线程中不生效。
以下是如何启动后台服务的方法:
if (Platform.isAndroid) {
debugPrint("现在... 启动后台服务!!!");
var channel = const MethodChannel('com.example/background_service');
var callbackHandle =
PluginUtilities.getCallbackHandle(backgroundMain);
channel.invokeMethod('startService', callbackHandle?.toRawHandle());
}
如果有任何建议,将不胜感激!
Please note that I've translated the code and comments, but I haven't addressed any specific questions or issues mentioned in the code. If you have further questions or need assistance with any part of the code, please feel free to ask.
<details>
<summary>英文:</summary>
what I want achieve:
- judge app is in background or foreground inside a Background service;
what I have tried:
- I found is not possible to change background service while using WidgetBindingObserver to detect app's cycle;
this is my currently to detect apps cycle:
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
debugPrint('App State = $state');
DbUserUranus? user = AppData.instance()!.user;
if (user != null) {
if (state == AppLifecycleState.inactive ||
state == AppLifecycleState.paused) {
ChatApp.instance()!
.eventsSender
.sendPresence(PresenceType.Away, user.user_addr);
GlobalSettings.isAppInBackground = true;
debugPrint("----------------- ^^^^^^^^^^ App in background!!");
} else if (state == AppLifecycleState.resumed) {
// MQTTClientWrapper.instance().connect();
ChatApp.instance()!
.eventsSender
.sendPresence(PresenceType.Available, user.user_addr);
GlobalSettings.isAppInBackground = false;
debugPrint("---------------- ^^^^^^^^^^^ App comes back!");
}
}
}
the questions is , the value I changed from main thread, doesn not takes effect in background service thread.
This is How can start a background service:
if (Platform.isAndroid) {
debugPrint("now... to the background service!!!");
var channel = const MethodChannel('com.example/background_service');
// var serviceInst = MQTTService.instance();
// var backgroundMain = serviceInst.startListen();
var callbackHandle =
PluginUtilities.getCallbackHandle(backgroundMain);
channel.invokeMethod('startService', callbackHandle?.toRawHandle());
}
any suggestions would be many thanks to!
</details>
# 答案1
**得分**: 1
I used a Isolate and the flutter_background_service plugin.
You can achieve this with the following:
1. 在你的后台服务中使用一个带有ValueNotifier的接收器,它将接收来自UI的事件。
2. 在你的后台服务中使用一个带有ValueNotifier的布尔值,用于跟踪应用程序的状态。
3. 在你的UI中,将你的小部件扩展为WidgetsBindingObserver类,用于捕获应用程序生命周期事件(恢复,暂停,不活动等)。
4. 在initState方法中注册你的观察器。
5. 覆盖didChangeAppLifecycleState事件,这将在应用程序的生命周期状态发生变化时触发,它具有一个状态参数,你可以使用它来获取应用程序的当前状态。
UI类:
```dart
class _ExampleState extends State<Example> with WidgetsBindingObserver {
SendPort? _sendPort;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
// ...
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
_sendPort ??= IsolateNameServer.lookupPortByName('appState');
switch (state) {
case AppLifecycleState.resumed:
_sendPort?.send(false);
break;
case AppLifecycleState.paused:
_sendPort?.send(true);
break;
default:
break;
}
}
}
服务:
class RideBackgroundService {
static final ValueNotifier<bool> _appPausedState = ValueNotifier<bool>(false);
static final ValueNotifier<ReceivePort?> _stateNotifier =
ValueNotifier<ReceivePort?>(null);
// ...
static void onStart(ServiceInstance service) {
if (_stateNotifier.value == null) {
_stateNotifier.value = ReceivePort('appState');
IsolateNameServer.registerPortWithName(
_stateNotifier.value!.sendPort, 'appState');
_stateNotifier.value?.listen((dynamic value) {
_appPausedState.value = value as bool;
});
}
// ...
}
}
然后,你可以使用_appPausedState.value来查看应用程序的状态。请注意,无法发送实例,你应该使用基本数据类型,如int,或者你可以将对象转换为地图并发送。
你也可以通过一个无状态小部件来实现这一点,我认为它不必是有状态的小部件,我只是在我的项目中使用了有状态的小部件。
你还可以修改这段代码,以发送int而不是bool以获取所有状态。
英文:
I used a Isolate and the flutter_background_service plugin.
You can achieve this with the following:
- Setup a receiver with a ValueNotifier in your background service, this will receive the events from the UI
- Setup a bool with a ValueNotifier in your background service this will be used to keep track of the state of the application.
- In your UI, extends your widget with the WidgetsBindingObserver class, this will be used to catch application lifecycle events(resume, pause, inactive, etc)
- Register your observer in the initState method.
- override the didChangeAppLifecycleState event, this will be triggered once the lifecycle state of the application has been changed, this has a state parameter that you can use to get the current state of the app.
The UI Class:
class _ExampleState extends State<Example> with WidgetsBindingObserver{
SendPort? _sendPort;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
...
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
_sendPort ??= IsolateNameServer.lookupPortByName('appState');
switch(state){
case AppLifecycleState.resumed:
_sendPort?.send(false);
break;
case AppLifecycleState.paused:
_sendPort?.send(true);
break;
default:
break;
}
}
The Service:
class RideBackgroundService {
static final ValueNotifier<bool> _appPausedState = ValueNotifier<bool>(false);
static final ValueNotifier<ReceivePort?> _stateNotifier = ValueNotifier<ReceivePort?>(null);
...
static void onStart(ServiceInstance service) {
if(_stateNotifier.value == null){
_stateNotifier.value = ReceivePort('appState');
IsolateNameServer.registerPortWithName(_stateNotifier.value!.sendPort, 'appState');
_stateNotifier.value?.listen((dynamic value) {
_appPausedState.value = serviceInfo.value as bool;
});
}
...
}
Then you can use the _appPauseState.value to see the state of the application. Please keep in mind, its not possible to send instances, you should rather use basic data types like a int, or you could convert the object to a map and send that.
You can also do this via a stateless widget, i dont think it has to be a statefull widget, I just used a statefull widget in my project.
You can maybe also modify this code to send an int instead of a bool to get all of the states.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论