背景服务在Android上的应用程序关闭后不停止
在我的Flutter应用程序中,我写了一个背景服务以获取用户位置。当应用程序在后台时,此位置服务仍然可以获取用户位置,并且该应用程序仍然运行。
我不希望后台位置服务在用户终止应用程序后运行。
但是,当我在Android上终止我的应用程序时,位置服务似乎仍在运行。
同样,当我启动应用程序第二次时,它无法正常运行。我认为这是因为背景服务仍在运行。
如果我通过“强制停止”停止应用程序,则第二次都可以正常工作。
另外,如果我从应用程序中手动停止背景服务(例如单击按钮,调用停止功能),然后关闭应用程序,请同样工作。
有人关闭应用程序时如何停止背景服务,有人可以提供一些建议吗?
mainActivity.kt是;
class MainActivity: FlutterActivity() {
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, LOCATION_CHANNEL).setMethodCallHandler {
call, result ->
if (call.method == "startLocationUpdate") {
var status = startUpdateLocation()
result.success(status.toString())
} else if (call.method == "stopLocationUpdate")
{
var status = stopUpdateLocation()
result.success(status.toString())
} else if (call.method == "isLocationPermissionEnabled")
{
var status = checkPermission()
result.success(status.toString())
}
else {
result.notImplemented()
}
}
EventChannel(flutterEngine.dartExecutor, LOCATION_EVENT_CHANNEL).setStreamHandler(
object : EventChannel.StreamHandler {
override fun onListen(arguments: Any?, events: EventChannel.EventSink) {
locationUpdateReceiver = receiveLocationUpdate(events)
}
override fun onCancel(arguments: Any?) {
unregisterReceiver(locationUpdateReceiver)
locationUpdateReceiver = null
isServiceStarted = false
}
}
)
}
override fun onDestroy() {
try {
if (locationUpdateReceiver != null )
{
unregisterReceiver(locationUpdateReceiver)
}
} catch (e: Exception) {
}
super.onDestroy()
}
private fun stopUpdateLocation() : Int {
if (isServiceStarted) {
unregisterReceiver(locationUpdateReceiver)
stopService(this)
isServiceStarted = false
return SUCCESS
}
else {
return SERVICE_NOT_RUNNING
}
}
private fun startUpdateLocation() : Int {
if (isServiceStarted) {
return SERVICE_ALREADY_STARTED
}
else if (!checkPermission()) {
//requestPermission()
return REQUESTING_PERMISSION
}
else {
registerReceiver(locationUpdateReceiver, locationIntentFilter);
isServiceStarted = true
startService(this)
return SUCCESS
}
}
private fun receiveLocationUpdate(events: EventChannel.EventSink): BroadcastReceiver {
return object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val key = LocationManager.KEY_LOCATION_CHANGED
val location: Location? = intent.extras!![key] as Location?
if (location != null) {
val runningAppProcessInfo = ActivityManager.RunningAppProcessInfo()
ActivityManager.getMyMemoryState(runningAppProcessInfo)
var appRunningBackground: Boolean = runningAppProcessInfo.importance != ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
if (appRunningBackground) {
events.success("0," + location.latitude.toString() + "," + location.longitude.toString())
}
else {
events.success("1," + location.latitude.toString() + "," + location.longitude.toString())
}
}
}
}
}
private fun checkPermission(): Boolean {
val result = ContextCompat.checkSelfPermission(applicationContext, Manifest.permission.ACCESS_FINE_LOCATION)
val result1 = ContextCompat.checkSelfPermission(applicationContext, Manifest.permission.ACCESS_COARSE_LOCATION)
return result == PackageManager.PERMISSION_GRANTED && result1 == PackageManager.PERMISSION_GRANTED
}
companion object {
private const val LOCATION_CHANNEL = "flutter.io/location"
private const val LOCATION_EVENT_CHANNEL = "flutter.io/locationEvent"
private const val LOCATION_UPDATE_INTENT = "FLUTTER_LOCATION"
private const val PERMISSION_REQUEST_CODE = 1
private final const val SERVICE_NOT_RUNNING = 0;
private final const val SUCCESS = 1;
private final const val REQUESTING_PERMISSION = 100;
private final const val SERVICE_ALREADY_STARTED = 2;
var isServiceStarted = false
var duration = "1" ;
var distance = "20";
var locationIntentFilter = IntentFilter(LOCATION_UPDATE_INTENT)
var locationUpdateReceiver: BroadcastReceiver? = null
fun startService(context: Context) {
val startIntent = Intent(context, LocationService::class.java)
ContextCompat.startForegroundService(context, startIntent)
}
fun stopService(context: Context) {
val stopIntent = Intent(context, LocationService::class.java)
context.stopService(stopIntent)
}
}
}
在我的androidmanifest.xml中的位置erivice.kt中
class LocationService : Service() {
private val NOTIFICATION_CHANNEL_ID = "notification_location"
private val duration = 5 // In Seconds
private val distance = 0 // In Meters
override fun onCreate() {
super.onCreate()
isServiceStarted = true
val builder: NotificationCompat.Builder =
NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
.setOngoing(false)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationManager: NotificationManager =
getSystemService(NOTIFICATION_SERVICE) as NotificationManager
val notificationChannel = NotificationChannel(
NOTIFICATION_CHANNEL_ID,
NOTIFICATION_CHANNEL_ID, NotificationManager.IMPORTANCE_LOW
)
notificationChannel.description = NOTIFICATION_CHANNEL_ID
notificationChannel.setSound(null, null)
notificationManager.createNotificationChannel(notificationChannel)
startForeground(1, builder.build())
}
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
LocationHelper().startListeningLocation(this, duration, distance);
return START_STICKY
}
override fun onBind(intent: Intent): IBinder? {
return null
}
override fun onDestroy() {
super.onDestroy()
isServiceStarted = false
}
override fun onTaskRemoved(rootIntent: Intent?) {
super.onTaskRemoved(rootIntent)
stopSelf()
}
companion object {
var isServiceStarted = false
}
}
,我
android:name=".LocationService"
android:enabled="true"
android:exported="true"
android:stopWithTask="true"
在我的flutter应用程序中使用的是我在我也尝试关注的stop服务
@override
void dispose() async {
if (_locationUpdateEventStarted) {
await methodChannel.invokeMethod('stopLocationUpdate');
}
super.dispose();
}
,但它也无效
@override
void didChangeAppLifecycleState(AppLifecycleState state) async {
super.didChangeAppLifecycleState(state);
if (state == AppLifecycleState.detached) {
if (_locationUpdateEventStarted) {
await methodChannel.invokeMethod('stopLocationUpdate');
}
}
}
In my flutter application I have written a background service to get the users location. When the application is in the background this location service still get users location and the application still functions.
I don't want the background location service to run after user terminate the application.
But it seems location service seems to be still running when I terminate my application on Android.
Also when I start the application 2nd time it does not function correctly. I assume this is because the background service is still running.
If I stop the application by "Force Stop" all works fine in 2nd time.
Also if I manually stop the background service from the application (say from a button click, calling the stop function ) then close the app, again all works fine.
Can someone provide some advice on how to stop the background service when I close the application?
MainActivity.kt is;
class MainActivity: FlutterActivity() {
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, LOCATION_CHANNEL).setMethodCallHandler {
call, result ->
if (call.method == "startLocationUpdate") {
var status = startUpdateLocation()
result.success(status.toString())
} else if (call.method == "stopLocationUpdate")
{
var status = stopUpdateLocation()
result.success(status.toString())
} else if (call.method == "isLocationPermissionEnabled")
{
var status = checkPermission()
result.success(status.toString())
}
else {
result.notImplemented()
}
}
EventChannel(flutterEngine.dartExecutor, LOCATION_EVENT_CHANNEL).setStreamHandler(
object : EventChannel.StreamHandler {
override fun onListen(arguments: Any?, events: EventChannel.EventSink) {
locationUpdateReceiver = receiveLocationUpdate(events)
}
override fun onCancel(arguments: Any?) {
unregisterReceiver(locationUpdateReceiver)
locationUpdateReceiver = null
isServiceStarted = false
}
}
)
}
override fun onDestroy() {
try {
if (locationUpdateReceiver != null )
{
unregisterReceiver(locationUpdateReceiver)
}
} catch (e: Exception) {
}
super.onDestroy()
}
private fun stopUpdateLocation() : Int {
if (isServiceStarted) {
unregisterReceiver(locationUpdateReceiver)
stopService(this)
isServiceStarted = false
return SUCCESS
}
else {
return SERVICE_NOT_RUNNING
}
}
private fun startUpdateLocation() : Int {
if (isServiceStarted) {
return SERVICE_ALREADY_STARTED
}
else if (!checkPermission()) {
//requestPermission()
return REQUESTING_PERMISSION
}
else {
registerReceiver(locationUpdateReceiver, locationIntentFilter);
isServiceStarted = true
startService(this)
return SUCCESS
}
}
private fun receiveLocationUpdate(events: EventChannel.EventSink): BroadcastReceiver {
return object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val key = LocationManager.KEY_LOCATION_CHANGED
val location: Location? = intent.extras!![key] as Location?
if (location != null) {
val runningAppProcessInfo = ActivityManager.RunningAppProcessInfo()
ActivityManager.getMyMemoryState(runningAppProcessInfo)
var appRunningBackground: Boolean = runningAppProcessInfo.importance != ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
if (appRunningBackground) {
events.success("0," + location.latitude.toString() + "," + location.longitude.toString())
}
else {
events.success("1," + location.latitude.toString() + "," + location.longitude.toString())
}
}
}
}
}
private fun checkPermission(): Boolean {
val result = ContextCompat.checkSelfPermission(applicationContext, Manifest.permission.ACCESS_FINE_LOCATION)
val result1 = ContextCompat.checkSelfPermission(applicationContext, Manifest.permission.ACCESS_COARSE_LOCATION)
return result == PackageManager.PERMISSION_GRANTED && result1 == PackageManager.PERMISSION_GRANTED
}
companion object {
private const val LOCATION_CHANNEL = "flutter.io/location"
private const val LOCATION_EVENT_CHANNEL = "flutter.io/locationEvent"
private const val LOCATION_UPDATE_INTENT = "FLUTTER_LOCATION"
private const val PERMISSION_REQUEST_CODE = 1
private final const val SERVICE_NOT_RUNNING = 0;
private final const val SUCCESS = 1;
private final const val REQUESTING_PERMISSION = 100;
private final const val SERVICE_ALREADY_STARTED = 2;
var isServiceStarted = false
var duration = "1" ;
var distance = "20";
var locationIntentFilter = IntentFilter(LOCATION_UPDATE_INTENT)
var locationUpdateReceiver: BroadcastReceiver? = null
fun startService(context: Context) {
val startIntent = Intent(context, LocationService::class.java)
ContextCompat.startForegroundService(context, startIntent)
}
fun stopService(context: Context) {
val stopIntent = Intent(context, LocationService::class.java)
context.stopService(stopIntent)
}
}
}
in LocationSerivice.kt
class LocationService : Service() {
private val NOTIFICATION_CHANNEL_ID = "notification_location"
private val duration = 5 // In Seconds
private val distance = 0 // In Meters
override fun onCreate() {
super.onCreate()
isServiceStarted = true
val builder: NotificationCompat.Builder =
NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
.setOngoing(false)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationManager: NotificationManager =
getSystemService(NOTIFICATION_SERVICE) as NotificationManager
val notificationChannel = NotificationChannel(
NOTIFICATION_CHANNEL_ID,
NOTIFICATION_CHANNEL_ID, NotificationManager.IMPORTANCE_LOW
)
notificationChannel.description = NOTIFICATION_CHANNEL_ID
notificationChannel.setSound(null, null)
notificationManager.createNotificationChannel(notificationChannel)
startForeground(1, builder.build())
}
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
LocationHelper().startListeningLocation(this, duration, distance);
return START_STICKY
}
override fun onBind(intent: Intent): IBinder? {
return null
}
override fun onDestroy() {
super.onDestroy()
isServiceStarted = false
}
override fun onTaskRemoved(rootIntent: Intent?) {
super.onTaskRemoved(rootIntent)
stopSelf()
}
companion object {
var isServiceStarted = false
}
}
in my AndroidManifest.xml I have
android:name=".LocationService"
android:enabled="true"
android:exported="true"
android:stopWithTask="true"
In my flutter app I call the stop service in
@override
void dispose() async {
if (_locationUpdateEventStarted) {
await methodChannel.invokeMethod('stopLocationUpdate');
}
super.dispose();
}
I also tried following, but it also did not work
@override
void didChangeAppLifecycleState(AppLifecycleState state) async {
super.didChangeAppLifecycleState(state);
if (state == AppLifecycleState.detached) {
if (_locationUpdateEventStarted) {
await methodChannel.invokeMethod('stopLocationUpdate');
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我使用 Flutter_background_service 有相似或相同的问题。我正在修改 onTaskRemaved 。
flutter_background_service由InvokeMethod停止(“ stopService”)。因此,我发现 stopService 方法代码。
而且我能够通过应用StopService Mothod代码来解决它。
我不确定这是正确的解决方案。但是我希望该解决方案对您的问题有所帮助。
我提交了一个问题,因此请记住这一点。
https://github.com/ekasetiawans/flutter_background_servcookeground_service/service/issues/sissues/300
i had similar or the same problem using flutter_background_service. i'm modify the onTaskRemoved.
flutter_background_service is stop by invokeMethod("stopService"). so, i found the stopService method code.
and i was able to solve it by applying the stopService mothod code.
i'm not sure this is the correct solution. but i hope this solution help your problem.
I submited an issue, so keep that in mind.
https://github.com/ekasetiawans/flutter_background_service/issues/300
实际服务是前景服务即使应用程序已关闭,也可以运行。
Actually service is Foreground service, which runs even if the application is closed.
这是我所做的,它有效
This what i've made and it works