30秒后前台服务上的locationListener不起作用 [英] locationListener doesn't work after 30 seconds on foreground service

查看:128
本文介绍了30秒后前台服务上的locationListener不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个服务,该服务可以查找用户的坐标,然后将其存储在SQLite数据库中.

I have created a service which finds and then stores the user's coordinates in an SQLite database.

public class GPS_Service extends Service {

DatabaseHelper myDb;

private LocationListener locationListener;
private LocationManager locationManager;

private String latitude, longitude;

@Override
public void onCreate() {
    super.onCreate();

    myDb = new DatabaseHelper(this);

}

@SuppressLint("MissingPermission")
@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    Intent notificationIntent = new Intent(this, MainActivity.class);
    PendingIntent pendingIntent = PendingIntent.getActivity(this,0, notificationIntent, 0);

    Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
            .setContentTitle("Service")
            .setContentText("Coordinates Location Running")
            .setContentIntent(pendingIntent)
            .build();

    startForeground(1, notification);

    locationListener = new LocationListener() {

        @Override
        public void onLocationChanged(Location location) {

            Log.d("myTag", "Hello");

            latitude = String.valueOf(location.getLatitude());
            longitude = String.valueOf(location.getLongitude());

            insertCoordinates(latitude, longitude);

            Intent i = new Intent("location_update");
            i.putExtra("latitude", latitude);
            i.putExtra("longitude",longitude);

            sendBroadcast(i);

        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {

        }

        @Override
        public void onProviderEnabled(String provider) {

        }

        @Override
        public void onProviderDisabled(String provider) {

            Intent i = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
            i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(i);

        }

    };

    locationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000, 0, locationListener);

    return START_NOT_STICKY;

}

@Override
public void onDestroy() {

    super.onDestroy();

    if(locationManager != null)
        locationManager.removeUpdates(locationListener);

}

private void insertCoordinates(String latitude, String longitude) {

    boolean inserted = myDb.insertData(latitude, longitude); //Insert coordinates

    //Check if insertion is completed
    if(inserted)
        Toast.makeText(GPS_Service.this, "Coordinates Inserted", Toast.LENGTH_SHORT).show();
    else
        Toast.makeText(GPS_Service.this, "Coordinates Not Inserted", Toast.LENGTH_SHORT).show();

}

@Nullable
@Override
public IBinder onBind(Intent intent) {
    return null;
}

}

我可以这样从MainActivity启动或停止服务

I can either start or stop the service from the MainActivity like this

private void enable_buttons() {

    buttonStartService.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            Intent serviceIntent = new Intent(getApplicationContext(), GPS_Service.class);

            //Checks if the SDK version is higher than 26 to act accordingly
            ContextCompat.startForegroundService(MainActivity.this, serviceIntent);

        }
    });

    buttonStopService.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            Intent serviceIntent = new Intent(MainActivity.this, GPS_Service.class);
            stopService(serviceIntent);

        }
    });

}

问题在于,当我启动此服务时,如果我完全关闭该应用程序或将其保留在后台,则locationListener将工作30秒,然后它将停止.如果我重新打开该应用程序,则该服务将从停止处继续运行.我还检查了开发人员选项是否服务正在运行,即使locationListener没有输出预期的结果,它的确是这样.有什么想法吗?

The problem is that when I start this service, if I either completely close the app or leave it in the background, the locationListener will work for 30 seconds and then it will stop. If I reopen the app, the service continues to work from where it stopped. Also I checked in the developer options if the service is running, and it indeed is even though the locationListener doesn't output the expected results. Any ideas?

推荐答案

TL; DR:

Service's清单条目中添加android:foregroundServiceType="location".

EXPLANATION

针对Android 10的此新行为与您所描述的完全相同:即使您可能正在使用前台服务,应用程序离开屏幕30秒后-位置更新也会停止.

This new behavior, for Android 10, is exactly as you've described: Even though you may be using a foreground service, 30 seconds after your app leaves the screen -- location updates cease.

您可能已经注意到,在授予位置权限时(对于旧版(API <29)应用程序或声明了ACCESS_BACKGROUND_LOCATION权限的应用程序),Android 10设备向用户提供了两个新选择:

You might've noticed that Android 10 devices present two new choices to the user when granting location permissions (for legacy (API < 29) apps, or apps that declare the ACCESS_BACKGROUND_LOCATION permission):

  • 一直允许"
  • 仅在使用此应用程序时允许"

仅在使用此应用程序时允许"实际上表示在屏幕上可见应用程序时允许".这是因为用户现在可以根据该标准选择性地删除位置访问权限,甚至是对前台服务的访问权限.即使您的应用正在运行,用户也可以随时 更改此设置.

"Allow only while using this app" effectively means, "Allow while the app is visible onscreen". That's because the user now has the option of selectively removing location access -- even to a foreground service -- based on that criteria. Users can change this setting at any time, even if your app is running.

Android文档解释说,解决方案android:foregroundServiceType="location"适用于您的确切用例:类似"Google Maps"的应用程序,具有前台服务,但是如果用户切换到其他应用程序,则有望继续处理位置数据.该技术称为继续用户发起的操作",即使您的应用程序放置在背景"中,它也允许您获取位置更新.

The Android docs explain that the solution, android:foregroundServiceType="location", was intended for your precise use case: "Google Maps"-like apps, which have a foreground service, but are expected to continue processing location data if the user switches to another app. The technique is called "continuing a user-initiated action", and it allows you to get location updates even after your app is placed in the "background".

(文档似乎在这里扩展了背景"一词的定义.过去,如果您拥有前台服务,则您的应用被视为前台"-至少出于任务目的优先级,Doze等.现在,如果最近30秒钟内未在屏幕上显示某个应用程序,则该应用程序在位置访问方面就被视为在后台".

(The docs seem to be expanding the definition of the term "background", here. In the past, if you had a foreground service, your app was considered "in the foreground" -- at least for the purposes of task priority, Doze, and so forth. Now it appears that an app is considered "in the background", with respect to location access, if it hasn't been onscreen in the last 30 seconds.)

我不确定在设置特定的foregroundServiceType时会发生什么UI更改(例如在Google Play商店中).无论如何,在我看来,用户不太可能会反对.

I am not sure what UI changes (like in the Google Play store) take place when you set a particular foregroundServiceType. Regardless, it seems to me that users are unlikely to object.

用于Android 10设备的其他解决方案

或者,您可以将targetSdkVersion声明为28以下,这将使您的应用在兼容模式"下运行.

Alternatively, you could've declared a targetSdkVersion of 28 or less, which will let your app function in a location "compatibility mode".

您还可以选择获得ACCESS_BACKGROUND_LOCATION权限,但是文档警告:

You also have the option of gaining the ACCESS_BACKGROUND_LOCATION permission, but the docs caution against this:

如果您的应用在后台运行时不需要位置访问权限,则强烈建议您不要请求ACCESS_BACKGROUND_LOCATION ...

对于您的用例,不需要这种方法,因为您使用Activity来启动Service;您可以确保在Service开始获取后台位置更新之前,您的应用已至少出现在屏幕上一次. (至少,我假定,这就是操作系统确定用户启动的操作"的开始的方式.如果您启动foregroundServiceType方法将无法正常工作. >从JobSchedulerBroadcastReceiver之类的东西.)

This approach isn't required, for your use case, because your Activity is used to start your Service; you can be guaranteed that your app has been onscreen at least once before the Service starts getting background location updates. (At least, I assume that that is how the OS determines the start of a "user-initiated action". Presumably, the foregroundServiceType approach won't work if you're starting the Service from a JobScheduler, or a BroadcastReceiver, or something.)

PS::继续使用该WakeLock代码.如果要保持10秒钟的稳定更新速度,则需要使设备保持唤醒状态.

PS: Hang on to that WakeLock code. You're going to need to keep the device awake, if you want to keep getting updates at a steady 10-second pace.

这篇关于30秒后前台服务上的locationListener不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆