Java 当应用程序也从后台删除时,无法获取位置更新
“我正试图在后台获取位置,但它显示了此错误。我无论如何都无法获取位置。通知不起作用。我的doMystuff()函数在主活动中应该是什么样子的?有人能提供我如何在清单中注册广播接收器,以及如何使用onButton Click实现代码吗?” 更新[2]:“我刚刚在这里写入了要访问的运行时权限。现在,单击doStuff函数中的“startButton”按钮,我应该写入startService还是startForegroundService?” “主要活动”Java 当应用程序也从后台删除时,无法获取位置更新,java,android,Java,Android,“我正试图在后台获取位置,但它显示了此错误。我无论如何都无法获取位置。通知不起作用。我的doMystuff()函数在主活动中应该是什么样子的?有人能提供我如何在清单中注册广播接收器,以及如何使用onButton Click实现代码吗?” 更新[2]:“我刚刚在这里写入了要访问的运行时权限。现在,单击doStuff函数中的“startButton”按钮,我应该写入startService还是startForegroundService?” “主要活动” 你应该使用ForegroundService
你应该使用ForegroundService而不是Service。要启动startForegroundService()时调用它 接下来,在onCreate方法中的新ForegroundsService中调用startForeground()。使用startForeground,您必须传递通知以通知用户服务正在运行 此外,我发现像华为这样的一些设备有一个叫做“电源密集型应用程序监视器”的功能“。它会杀死所有在后台长时间运行的应用程序,除非用户授予其特殊权限。执行此操作的路径:设置->安全和隐私->位置服务->最近的位置请求:您的应用程序名称->电池->取消选中耗电量大的提示,应用程序启动:手动管理:检查所有三个位置:自动启动,秒启动。”dary启动,在后台运行
我不知道有没有一种方法可以通过编程来实现这一点。我认为最好的方法是创建一种帮助活动,并向用户解释如果应用程序不起作用该怎么办。您应该使用ForegroundsService而不是Service。要启动它,请调用StartForegroundsService() 接下来,在onCreate方法中调用startForeground()的新ForegroundService中。使用startForeground,您必须传递通知以通知用户服务正在运行 此外,我发现像华为这样的一些设备有一个叫做“电源密集型应用程序监视器”的功能“。它会杀死所有在后台长时间运行的应用程序,除非用户授予其特殊权限。执行此操作的路径:设置->安全和隐私->位置服务->最近的位置请求:您的应用程序名称->电池->取消选中耗电量大的提示,应用程序启动:手动管理:检查所有三个位置:自动启动,秒启动。”dary启动,在后台运行
我不知道有没有一种方法可以通过编程来实现这一点。我认为最好的方法是创建一种帮助活动,并向用户解释如果应用程序无法工作该怎么做。每10秒更新一次位置的服务代码
public class LocationService extends Service implements com.google.android.gms.location.LocationListener,
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener{
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
private String mChannelId = "my_service";
private int mNotificationId = 1;
private NotificationCompat.Builder mNotifBuilder = new NotificationCompat.Builder(this, mChannelId);
private Notification mNotif;
private NotificationManager mNotificationManager;
private boolean mRestartService = true;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void initGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
}
@Override
public void onCreate() {
super.onCreate();
initGoogleApiClient();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null && intent.getAction() != null) {
String mAction = intent.getAction();
if(mAction.equals("start_service")){
startForegroundService();
}else if(mAction.equals("stop_service")){
stopForegroundService();
}
}
return START_NOT_STICKY;
}
@Override
public void onConnected(@Nullable Bundle bundle) {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(10000);
mLocationRequest.setFastestInterval(5000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
try {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
} catch (SecurityException e) {
e.printStackTrace();
}
}
@Override
public void onConnectionSuspended(int i) {
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
}
@Override
public void onLocationChanged(Location location) {
Toast.makeText(this, "Location Updated", Toast.LENGTH_SHORT).show();
//Broadcast Location
}
private void createNotificationChannel(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
String description = "Foreground Service Channel";
String name = "My Background Channel";
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel channel = new NotificationChannel(mChannelId, name, importance);
channel.setDescription(description);
mNotificationManager.createNotificationChannel(channel);
}
}
private void startForegroundService() {
//Initializing Notifications and intents
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
createNotificationChannel();
mNotifBuilder.setContentText("Notification Content")
.setContentTitle("Notification Title")
.setSmallIcon(R.drawable.ic_notify)
.setContentIntent(pendingIntent)
.setOngoing(true)
.setAutoCancel(true);
mNotif = mNotifBuilder.build();
startForeground(mNotificationId, mNotif);
}
private void stopForegroundService() {
mRestartService = false;
if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
stopForeground(true);
}
/*@Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
Toast.makeText(this, "Task Removed", Toast.LENGTH_SHORT).show();
if (mRestartService){
Intent intent = new Intent(this, RestartService.class);
intent.setAction("restart_service");
sendBroadcast(intent);
}
}*/
}
然后在活动中添加按钮或切换按钮以启动和停止服务。您也可以使用通知中的按钮来执行此操作
private void startService() {
Intent intent = new Intent(MainActivity.this, LocationService.class);
intent.setAction("start_service");
startService(intent);
}
private void stopService() {
Intent intent = new Intent(MainActivity.this, LocationService.class);
intent.setAction("stop_service");
startService(intent);
}
即使应用程序被终止,服务也应该运行。在一些设备中,如小米、OPPO、维梧……等,无论您在服务中做了什么,它都可能被终止。在这些设备中,您可以尝试通过广播重新启动服务,以便在服务终止时启动服务
public class RestartService extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(action.equals("restart_service")){
Intent intent1 = new Intent(context, LocationService.class);
intent.setAction("start_service");
context.startService(intent1);
}
}
}
如果从后台删除活动时服务被终止,则可以将其添加到onTaskRemoved()
中。如果从后台删除活动后某个时间服务被终止,则可以将其添加到ondestory()
中
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
Toast.makeText(this, "Task Removed", Toast.LENGTH_SHORT).show();
if (mRestartService){
Intent intent = new Intent(this, RestartService.class);
intent.setAction("restart_service");
sendBroadcast(intent);
}
}
即使这样,某些手机上的服务也可能会被终止。在这种情况下,您需要要求用户将该服务从电池优化中排除,并允许其他例外情况自由运行。服务代码每10秒更新一次位置
public class LocationService extends Service implements com.google.android.gms.location.LocationListener,
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener{
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
private String mChannelId = "my_service";
private int mNotificationId = 1;
private NotificationCompat.Builder mNotifBuilder = new NotificationCompat.Builder(this, mChannelId);
private Notification mNotif;
private NotificationManager mNotificationManager;
private boolean mRestartService = true;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void initGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
}
@Override
public void onCreate() {
super.onCreate();
initGoogleApiClient();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null && intent.getAction() != null) {
String mAction = intent.getAction();
if(mAction.equals("start_service")){
startForegroundService();
}else if(mAction.equals("stop_service")){
stopForegroundService();
}
}
return START_NOT_STICKY;
}
@Override
public void onConnected(@Nullable Bundle bundle) {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(10000);
mLocationRequest.setFastestInterval(5000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
try {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
} catch (SecurityException e) {
e.printStackTrace();
}
}
@Override
public void onConnectionSuspended(int i) {
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
}
@Override
public void onLocationChanged(Location location) {
Toast.makeText(this, "Location Updated", Toast.LENGTH_SHORT).show();
//Broadcast Location
}
private void createNotificationChannel(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
String description = "Foreground Service Channel";
String name = "My Background Channel";
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel channel = new NotificationChannel(mChannelId, name, importance);
channel.setDescription(description);
mNotificationManager.createNotificationChannel(channel);
}
}
private void startForegroundService() {
//Initializing Notifications and intents
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
createNotificationChannel();
mNotifBuilder.setContentText("Notification Content")
.setContentTitle("Notification Title")
.setSmallIcon(R.drawable.ic_notify)
.setContentIntent(pendingIntent)
.setOngoing(true)
.setAutoCancel(true);
mNotif = mNotifBuilder.build();
startForeground(mNotificationId, mNotif);
}
private void stopForegroundService() {
mRestartService = false;
if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
stopForeground(true);
}
/*@Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
Toast.makeText(this, "Task Removed", Toast.LENGTH_SHORT).show();
if (mRestartService){
Intent intent = new Intent(this, RestartService.class);
intent.setAction("restart_service");
sendBroadcast(intent);
}
}*/
}
然后在活动中添加按钮或切换按钮以启动和停止服务。您也可以使用通知中的按钮来执行此操作
private void startService() {
Intent intent = new Intent(MainActivity.this, LocationService.class);
intent.setAction("start_service");
startService(intent);
}
private void stopService() {
Intent intent = new Intent(MainActivity.this, LocationService.class);
intent.setAction("stop_service");
startService(intent);
}
即使应用程序被终止,服务也应该运行。在一些设备中,如小米、OPPO、维梧……等,无论您在服务中做了什么,它都可能被终止。在这些设备中,您可以尝试通过广播重新启动服务,以便在服务终止时启动服务
public class RestartService extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(action.equals("restart_service")){
Intent intent1 = new Intent(context, LocationService.class);
intent.setAction("start_service");
context.startService(intent1);
}
}
}
如果从后台删除活动时服务被终止,则可以将其添加到onTaskRemoved()
中。如果从后台删除活动后某个时间服务被终止,则可以将其添加到ondestory()
中
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
Toast.makeText(this, "Task Removed", Toast.LENGTH_SHORT).show();
if (mRestartService){
Intent intent = new Intent(this, RestartService.class);
intent.setAction("restart_service");
sendBroadcast(intent);
}
}
即使这样,某些手机上的服务也可能会被终止。在这种情况下,您需要要求用户将该服务从电池优化中排除,并允许其他例外情况使其自由运行。当应用程序从后台删除时,您能看到该服务的锁定通知吗?如果不能,则该服务可能会被终止活动终止时终止。您可以重写
OnDestroy()
在MainActivity
和LocationUpdateService
中,添加一些日志以检查发生了什么。是的,当从后台删除应用程序时,通知也会消失。然后当从后台删除应用程序时,服务会被终止。这可能是因为您正在绑定服务和活动。请尝试删除绑定/解除绑定机制,并独立运行服务。如果服务仍被终止,请尝试返回START\u STICKY;'in your
onStartCommand',或在onDestroy
或onTaskRemoved
中再次重新启动服务。您可以查看答案以获得有关保持服务活动的更多帮助。@Arun先生,请检查我的新实现,并告诉我我做错了什么?我已经发布了一个带有工作代码的答案。你可以使用它。当应用程序从后台删除时,你是否能够看到服务的固定通知?如果不是,那么当活动被终止时,服务很可能被终止。你可以覆盖OnDestroy()
在MainActivity
和LocationUpdateService
中,添加一些日志以检查发生了什么。是的,当从后台删除应用程序时,通知也会消失。然后,当从后台删除应用程序时,服务会被终止。这可能是因为您正在绑定服务