奥利奥 - 在前台启动服务

9
我创建了一个能够跟踪设备移动位置的服务。该服务由一个Activity启动并绑定,Activity中有一个“开始跟踪”按钮。当按下此按钮时,我需要该服务在前台启动,以便保存设备移动到的位置,即使绑定到该服务的Activity被关闭或应用被最小化。
我知道要使服务在前台运行,必须显示通知。我尝试过这样做,但我无法在Activity被销毁时显示通知或让服务在前台工作。
似乎由于通知渠道,Oreo中的通知已经发生了变化,但我无法弄清楚需要做什么不同。我正在测试这个设备上的版本是8.0.0
以下是我的服务:
public class LocationTrackerService extends Service {

    private LocationListener locationListener;
    private LocationManager locationManager;
    private IBinder binder = new LocalBinder();
    private boolean isTracking;
    private ArrayList<Location> trackedWaypoints;
    private String bestProvider;
    private Timer timer;
    private Distance distance;

    @SuppressLint("MissingPermission")
    @Override
    public void onCreate() {
        super.onCreate();

        locationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
        Criteria criteria = new Criteria();
        bestProvider = locationManager.getBestProvider(criteria, true);

        isTracking = false;

        locationListener = new LocationListener() {
            @Override
            public void onLocationChanged(Location location) {
                Intent intent = new Intent("location_update");
                intent.putExtra("latitude", location.getLatitude());
                intent.putExtra("longitude", location.getLongitude());
                sendBroadcast(intent);
                if (isTracking) {
                    if (trackedWaypoints.size() > 1) {
                        distance.add(trackedWaypoints.get(trackedWaypoints.size() - 1).distanceTo(location));
                    }
                    trackedWaypoints.add(location);
                }
            }

            @Override
            public void onStatusChanged(String s, int i, Bundle bundle) { }

            @Override
            public void onProviderEnabled(String s) { }

            @Override
            public void onProviderDisabled(String s) {
                Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(intent);
            }
        };

        locationManager.requestLocationUpdates(bestProvider, 0, 0, locationListener);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (locationManager != null) {
            locationManager.removeUpdates(locationListener);
        }
    }

    public void startTracking() {
        trackedWaypoints = new ArrayList<Location>();
        timer = new Timer();
        distance = new Distance();
        timer.start();
        isTracking = true;
        startInForeground();
    }

    private void startInForeground() {
        Intent notificationIntent = new Intent(this, WorkoutActivity.class);
        PendingIntent pendingIntent =
                PendingIntent.getActivity(this, 0, notificationIntent, 0);

        Notification notification =
                new Notification.Builder(this)
                        .setContentTitle("TEST")
                        .setContentText("HELLO")
                        .setSmallIcon(R.drawable.ic_directions_run_black_24dp)
                        .setContentIntent(pendingIntent)
                        .setTicker("TICKER")
                        .build();

        startForeground(101, notification);
    }

    public void stopTracking() {
        isTracking = false;
        stopForeground(true);
    }

    public boolean isTracking() {
        return isTracking;
    }

    public ArrayList<Location> getTrackedWaypoints() {
        return trackedWaypoints;
    }

    public Timer getTime() {
        timer.update();
        return timer;
    }

    public Distance getDistance() {
        return distance;
    }

    public int getSteps() {
        return 0;
    }

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

    public class LocalBinder extends Binder {
        public LocationTrackerService getLocationTrackerInstance() {
            return LocationTrackerService.this;
        }
    }
}

1
你似乎没有调用startTracking()函数。 - CommonsWare
当按下按钮时,它会从活动中被调用。 - KOB
1
如果您的targetSdkVersion为26或更高版本,则需要定义一个通知渠道(如果之前没有定义),并在构建器中使用该渠道ID。您还可以考虑切换到NotificationCompat.Builder - CommonsWare
定义通知渠道是我迷失的地方。我只需将其设置为通知渠道设置中的一个整数吗? - KOB
好的,你正在调用 stopService()。这将停止服务。 - CommonsWare
显示剩余2条评论
2个回答

19

尝试使用以下代码更改您的startInForeground()方法:

private void startInForeground() {
        Intent notificationIntent = new Intent(this, WorkoutActivity.class);
        PendingIntent pendingIntent=PendingIntent.getActivity(this,0,notificationIntent,0);
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this,NOTIFICATION_CHANNEL_ID)
                .setSmallIcon(R.drawable.shsl_notification)
                .setContentTitle("TEST")
                .setContentText("HELLO")
                .setTicker("TICKER") 
                .setContentIntent(pendingIntent);
        Notification notification=builder.build();
        if(Build.VERSION.SDK_INT>=26) {
            NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
            channel.setDescription(NOTIFICATION_CHANNEL_DESC);
            NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            notificationManager.createNotificationChannel(channel);
        }
        startForeground(NOTIFICATION_ID, notification);
}

因此,当您的Android版本为Oreo(或更高版本)时,将创建通知渠道,否则不会。


3
谢谢,它有效了。代码有小更新,可以使用 Build.VERSION_CODES.O 代替使用数字 26,这将提高您的代码可读性。 - A.Alqadomi
你是从哪个库使用“NotificationCompat.Builder”的?我找到的变量只接受一个参数(Context)。 - j3App
刚刚找到了答案。你需要将所有的谷歌支持库设置为最低版本26.1.0。 - j3App

2
在显示通知之前,您必须创建通知渠道:
private void createNotificationChannel() {
    if (Build.VERSION_CODES.O <= Build.VERSION.SDK_INT) {
        NotificationChannel notificationChannel =
                new NotificationChannel(PRIMARY_CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
        notificationManager.createNotificationChannel(notificationChannel);
    }
}

然后更改创建通知生成器

new Notification.Builder(context, PRIMARY_CHANNEL_ID)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接