在我的flutter应用程序中,我写了一个后台服务来获取用户的位置。当应用程序在后台时,这个位置服务仍然可以获取用户的位置,应用程序仍然可以运行。
我不希望后台位置服务在用户终止应用程序后运行。
但当我在Android上终止我的应用程序时,位置服务似乎仍在运行。
另外,当我第二次启动应用程序时,它不能正常工作。我假设这是因为后台服务仍在运行。
- 如果我通过“强制停止”停止应用程序,所有工作正常,在第二次。
- 此外,如果我手动停止后台服务,从应用程序(说,从一个按钮点击,调用停止功能),然后关闭应用程序,再次所有工作正常。
有人能提供一些建议,如何停止后台服务时,我关闭应用程序?
主要活动.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)
}
}
}
位置服务.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
}
}
在我的AndroidManifest.xml中,我有
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');
}
}
}
2条答案
按热度按时间9ceoxa921#
实际上,服务是Foreground service,即使应用程序关闭,它也会运行。
前台服务会显示状态栏通知,以便用户主动了解您的应用正在前台执行任务并消耗系统资源。除非停止服务或将其从前台移除,否则无法取消通知。
cwdobuhd2#
这就是我做的而且很管用