Oreo+ 中位置更新的前台服务不起作用

Posted

技术标签:

【中文标题】Oreo+ 中位置更新的前台服务不起作用【英文标题】:Foreground service for location update in Oreo+ not working 【发布时间】:2019-10-26 22:18:07 【问题描述】:

我的应用要求定期跟踪用户。 这是我的位置服务类,旨在在设定的时间间隔内提供位置更新。这段代码在 Nougat 之前工作正常,但在 Oreo 上不起作用。几天前这段代码运行良好,不知道出了什么问题。欢迎提出建议和评论。

 @Override
 public int onStartCommand(Intent intent, int flags, int startId) 
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
        startMyOwnForeground();
    else
        startForeground(1, createNotification());
    getLocationUpdates();
    thread = new LocationMonitoringThread();
    thread.start();
    mLocationCallback = new LocationCallback()
        @Override
        public void onLocationResult(LocationResult locationResult) 
            sendNewLocationBroadcast(locationResult);
        
    ;

    return START_STICKY;


private void startMyOwnForeground() 

    String CHANNEL_ID = "my_channel_01";
    CharSequence name = "Project U";
    String Description = "You are being Monitored";

    int NOTIFICATION_ID = 234;

    NotificationManager notificationManager = (NotificationManager) 
getSystemService(Context.NOTIFICATION_SERVICE);


    if (android.os.Build.VERSION.SDK_INT >= 
android.os.Build.VERSION_CODES.O) 

        int importance = NotificationManager.IMPORTANCE_HIGH;
        NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID, 
name, importance);
        mChannel.setDescription(Description);
        mChannel.setVibrationPattern(new long[] 0 );
        mChannel.enableVibration(true);
        if (notificationManager != null) 

            notificationManager.createNotificationChannel(mChannel);
        

    

    NotificationCompat.Builder builder = new 
NotificationCompat.Builder(this, CHANNEL_ID)
            .setContentText("You Are being Monitored")
            .setSmallIcon(R.drawable.ic_baseline_satellite_24px)
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
            .setAutoCancel(true);
    builder.setOngoing(true);

    if (notificationManager != null) 

        notificationManager.notify(NOTIFICATION_ID, builder.build());
    




private void getLocationUpdates() 

    mLocationProviderClient = 
LocationServices.getFusedLocationProviderClient(this);

    mLocationRequest = new LocationRequest();
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    mLocationRequest.setInterval(900000);
    mLocationRequest.setFastestInterval(20000);



private void sendNewLocationBroadcast(LocationResult result)

    Log.i(TAG, "sendNewLocationBroadcast: ");

    Intent intent = new Intent("com.example.projectu.LocationService");

    double latitude = result.getLastLocation().getLatitude();
    double longtitude = result.getLastLocation().getLongitude();
    int complete = 1;
    Log.d(TAG, "date: " + latitude);
    Log.d(TAG, "date: " + longtitude);
    intent.putExtra("latitude", latitude);
    intent.putExtra("longtitude", longtitude);
    intent.putExtra("complete", complete);
    sendBroadcast(intent);
    FirebaseApp.initializeApp(this);

    if (FirebaseAuth.getInstance().getCurrentUser() != null) 
        uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
    
    adb = FirebaseFirestore.getInstance();
    Map<String, Object> att = new HashMap<>();
    att.put("Location", (new GeoPoint(latitude, longtitude)));
    att.put("latestUpdateTimestamp", FieldValue.serverTimestamp());
    adb.collection("Users").document(uid + "")
            .update(att);



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


private Notification createNotification()
    String CHANNEL_ID = "my_channel_01";
    NotificationCompat.Builder builder = new 
NotificationCompat.Builder(this,
            CHANNEL_ID)
            .setSmallIcon(R.drawable.ic_baseline_satellite_24px)
            .setContentTitle("Project U")
            .setContentText("You are being Monitored")
            .setPriority(NotificationCompat.PRIORITY_DEFAULT);
    builder.setOngoing(true);
    return builder.build();



class LocationMonitoringThread extends Thread

    Looper looper;

    @Override
    public void run() 
        if (ActivityCompat.checkSelfPermission(LocationService.this, 
Manifest.permission.ACCESS_FINE_LOCATION) != 
PackageManager.PERMISSION_GRANTED) 
             return;
        
        getLocationUpdates();
        looper = Looper.myLooper();
        looper.prepare();
        mLocationProviderClient.requestLocationUpdates(
                mLocationRequest,
                mLocationCallback,
                looper
        );

        looper.loop();
    

  


【问题讨论】:

“这段代码几天前运行良好,不知道出了什么问题。” 就像以前一样,那么问题是你做了哪些代码更改来破坏它? Android Studio 可以通过VCS -&gt; Local history -&gt; Show history 菜单显示对当前显示的源文件的最近更改。 不幸的是,该项目已迁移到不存在的其他计算机历史记录:( 有什么问题?你有任何错误吗?是否调用了服务? 没有错误,日志中也没有位置更新。是的,该服务是从主要活动中调用的。还会出现牛轧糖及以下的通知。此问题仅适用于奥利奥及以上。 @Jasurbek 请阅读meta.***.com/questions/254990/… 【参考方案1】:

以下是 Android 中前台服务的两个常见缺陷 >= O:

1.您是否请求了前台服务权限?见here:

注意:针对 Android 9(API 级别 28)或更高版本并使用 前台服务必须请求 FOREGROUND_SERVICE 权限。 这是一个正常的权限,所以系统会自动授予 请求的应用程序。

如果以 API 级别 28 或更高级别为目标的应用尝试创建 前台服务不请求 FOREGROUND_SERVICE,系统 引发 SecurityException。

2。您是否使用Context.startForegroundService() 启动服务?

如果应用需要创建前台服务,应用应该调用 开始前台服务()。该方法创建一个后台服务, 但是该方法向系统发出信号,表明该服务将推广 自己到前台。创建服务后, 服务必须在五秒内调用它的 startForeground() 方法。

我的一个项目中的示例代码,以确保调用正确的方法来启动服务:

Intent i = new Intent(context, MyService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) 
    context.startForegroundService(i);
 else 
    context.startService(i);

【讨论】:

以上是关于Oreo+ 中位置更新的前台服务不起作用的主要内容,如果未能解决你的问题,请参考以下文章

当应用程序移到后台时,在前台服务中获取位置更新不起作用

为啥在 Android Oreo 上关闭屏幕时前台服务停止?

广播接收器在 Android 8 的前台服务中不起作用

Xamarin Forms 使用 CrossGeolocator 获取前台服务位置更新

Android O 在打盹模式下前台服务未接收位置更新

屏幕关闭时,前台服务未在 Android 7.0+ 中接收位置更新