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

时间:2019-06-12 11:48:26

标签: android android-8.0-oreo android-location foreground-service

我的应用要求定期跟踪用户。 这是我的位置服务类,旨在在设置的时间间隔内提供位置更新。该代码在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();
    }

  }

}

1 个答案:

答案 0 :(得分:-1)

这是Android> = O中前台服务的两个常见陷阱:

1。您是否请求了前台服务许可?参见here

  

注意:面向Android 9(API级别28)或更高版本的应用   前台服务必须请求FOREGROUND_SERVICE权限。   这是普通权限,因此系统会自动将其授予   请求的应用。

     

如果针对API级别为28或更高级别的应用尝试创建一个   无需请求FOREGROUND_SERVICE的前台服务,系统   引发SecurityException。

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

  

如果应用程序需要创建前台服务,则该应用程序应调用   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);
}