Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android Oreo-在前台启动服务_Android_Android Service_Android Notifications_Foreground_Foregroundnotification - Fatal编程技术网

Android Oreo-在前台启动服务

Android Oreo-在前台启动服务,android,android-service,android-notifications,foreground,foregroundnotification,Android,Android Service,Android Notifications,Foreground,Foregroundnotification,我创建了一个服务,在设备移动时跟踪设备的位置。服务由绑定到它的活动启动,在该活动中有一个“开始跟踪”按钮。当按下此按钮时,我需要在前台启动服务,以便它存储设备移动到的位置,即使绑定到它的活动已关闭,或者应用程序已最小化 我理解,对于前台的服务,必须显示通知。我已尝试这样做,但当活动被销毁时,我无法在前台显示通知或使服务工作 由于通知渠道的原因,Oreo中的通知似乎发生了变化,但我不知道需要做哪些不同的事情。我正在测试的设备是8.0.0 这是我的服务: public class LocationT

我创建了一个服务,在设备移动时跟踪设备的位置。服务由绑定到它的活动启动,在该活动中有一个“开始跟踪”按钮。当按下此按钮时,我需要在前台启动服务,以便它存储设备移动到的位置,即使绑定到它的活动已关闭,或者应用程序已最小化

我理解,对于前台的服务,必须显示通知。我已尝试这样做,但当活动被销毁时,我无法在前台显示通知或使服务工作

由于通知渠道的原因,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;
        }
    }
}
公共类LocationTrackerService扩展服务{
私有位置侦听器位置侦听器;
私人场所经理场所经理;
private IBinder binder=new LocalBinder();
私有布尔跟踪;
专用ArrayList跟踪航路点;
私有字符串提供者;
私人定时器;
私人距离;
@SuppressLint(“丢失许可”)
@凌驾
public void onCreate(){
super.onCreate();
locationManager=(locationManager)getApplicationContext().getSystemService(Context.LOCATION\u服务);
标准=新标准();
bestProvider=locationManager.getBestProvider(标准,true);
isTracking=false;
locationListener=新locationListener(){
@凌驾
已更改位置上的公共无效(位置){
意向意向=新意向(“位置更新”);
intent.putExtra(“纬度”,location.getLatitude());
intent.putExtra(“经度”,location.getLongitude());
发送广播(意图);
如果(正在跟踪){
如果(trackedWaypoints.size()>1){
distance.add(trackedWaypoints.get(trackedWaypoints.size()-1).distance到(位置));
}
跟踪航路点。添加(位置);
}
}
@凌驾
public void onStatusChanged(字符串s,int i,Bundle){}
@凌驾
public void onProviderEnabled(字符串s){}
@凌驾
公共无效onProviderDisabled(字符串s){
意向意向=新意向(设置、动作、位置、来源、设置);
intent.setFlags(intent.FLAG\u活动\u新任务);
星触觉(意向);
}
};
locationManager.RequestLocationUpdate(bestProvider,0,0,locationListener);
}
@凌驾
公共空间{
super.ondestory();
如果(locationManager!=null){
locationManager.RemoveUpdate(locationListener);
}
}
公共无效开始跟踪(){
trackedWaypoints=新的ArrayList();
定时器=新定时器();
距离=新距离();
timer.start();
isTracking=true;
startInForeground();
}
私有void startInForeground(){
Intent notificationIntent=新的Intent(这是WorkoutActivity.class);
下垂的,下垂的=
PendingEvent.getActivity(this,0,notificationIntent,0);
通知=
新建Notification.Builder(此)
.setContentTitle(“测试”)
.setContentText(“你好”)
.setSmallIcon(右可绘制ic\U方向\U运行\U黑色\U 24dp)
.setContentIntent(挂起内容)
.setTicker(“TICKER”)
.build();
启动前(101,通知);
}
公共空间停止追踪(){
isTracking=false;
停止前景(真);
}
公共布尔isTracking(){
返回跟踪;
}
公共阵列列表GetTracketWayPoints(){
返回跟踪航路点;
}
公共计时器getTime(){
timer.update();
返回计时器;
}
公共距离getDistance(){
返回距离;
}
公共int getSteps(){
返回0;
}
@可空
@凌驾
公共IBinder onBind(意向){
返回活页夹;
}
公共类LocalBinder扩展了Binder{
public LocationTrackerService getLocationTrackerInstance(){
返回LocationTrackerService.this;
}
}
}

在显示通知之前,您必须创建通知频道:

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);
    }
}

尝试使用以下代码更改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(或更高版本)时,将创建通知通道,否则不会创建。

您似乎没有调用
startTracking()
。当按下按钮时,它将从活动中调用。如果
targetSdkVersion
为26或更高版本,则需要定义通知通道(如果您以前没有定义它)在建造者中使用那个频道ID。你也可以考虑切换到代码> NoTrimeCupAT.Builder < /Cord>。定义通知通道是我丢失的地方。我只是把它设置为通知通道的整数集吗?看看MAC229发布的答案。然后使用两个参数<代码> Builder < /C> >构造函数和P。ass
PRIMARY\u CHANNEL\u ID
in,以及
Context
。另请参阅和来自我的一个示例应用程序。感谢它的成功,对代码进行了少量更新,而不是使用26,您可以使用Build.VERSION\u code.O,这将提高代码的可读性。您从哪个库使用“NotificationCompat.Builder”?我找到的变量只接受一个参数(上下文)。刚刚找到答案。您需要设置所有参数
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);
}