android - Android服务不断停止-“不允许后台执行:接收意图”
问题描述
我有一个位置服务,当用户单击按钮并应用位置时运行。
然而,它在大约一分钟后被杀死。我已经在 android 8/9 上对其进行了测试。我在这里阅读了其他一些关于它的答案,但它们没有帮助,但我对意图和广播的了解并不好。
定位服务.java
public class LocationService extends Service {
MockLocationProvider mockNetwork;
MockLocationProvider mockGps;
private static final int NOTIFICATION = 1;
static NotificationManager notificationManager;
Context context;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//TODO do something useful
context = getApplicationContext();
pushLocation(intent);
return LocationService.START_STICKY;
}
@Override
public void onDestroy() {
shutdown();
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void pushLocation(Intent intent) {
try {
if (intent.hasExtra("lat") && intent.hasExtra("lng") ) {
double lat = intent.getDoubleExtra("lat", 45);
double lng = intent.getDoubleExtra("lng", 45);
mockNetwork = new MockLocationProvider(LocationManager.NETWORK_PROVIDER, context);
mockGps = new MockLocationProvider(LocationManager.GPS_PROVIDER, context);
mockNetwork.pushLocation(lat, lng);
mockGps.pushLocation(lat, lng);
setNotification(lat, lng);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void setNotification(Double mLat, Double mLng) {
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
NotificationCompat.Builder builder = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel notificationChannel = new NotificationChannel("ID", "Name", importance);
notificationManager.createNotificationChannel(notificationChannel);
builder = new NotificationCompat.Builder(context, notificationChannel.getId());
} else {
builder = new NotificationCompat.Builder(context);
}
//open MainActivity when clicked
pendingIntent = PendingIntent.getActivity(context, 0,
new Intent(context, MainActivity.class)
.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP),
0);
//action when notification button clicked
Intent intentAction = new Intent(context, ActionReceiver.class);
intentAction.putExtra("action","actionNotification");
pendingCloseIntent = PendingIntent.getBroadcast(context,0, intentAction, PendingIntent.FLAG_UPDATE_CURRENT);
//build notification
builder = builder
.setSmallIcon(R.drawable.ic_logo)
.setColor(ContextCompat.getColor(context, R.color.colorPrimary))
.setContentTitle(getString(R.string.app_name) + " is running...")
.setCategory(NotificationCompat.CATEGORY_SERVICE)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setContentText(mLat + ", " + mLng)
.setContentIntent(pendingIntent)
.setWhen(System.currentTimeMillis())
.setTicker(getString(R.string.app_name) + " is running...") //accessibility
.addAction(android.R.drawable.ic_menu_close_clear_cancel, "STOP", pendingCloseIntent)
.setOngoing(true);
notificationManager.notify(NOTIFICATION, builder.build());
}
public void shutdown() {
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(NOTIFICATION);
if (mockNetwork != null)
mockNetwork.shutdown();
if (mockGps != null)
mockGps.shutdown();
}
}
ActionReceiver.java
public class ActionReceiver extends BroadcastReceiver {
Context context;
MockLocationProvider mockNetwork;
MockLocationProvider mockGps;
private static final int NOTIFICATION = 1;
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getStringExtra("action");
if(action.equals("actionNotification")){
mockNetwork = new MockLocationProvider(LocationManager.NETWORK_PROVIDER, context);
mockGps = new MockLocationProvider(LocationManager.GPS_PROVIDER, context);
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(NOTIFICATION);
try {
if (mockNetwork != null)
mockNetwork.shutdown();
if (mockGps != null)
mockGps.shutdown();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
这些在我的 AndroidManifest 中注册并具有权限:
...
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
...
<receiver android:name="com.package.locationtest.ActionReceiver" />
<service
android:name=".LocationService"
android:label="Service">
</service>
我不明白这里的问题。任何人都可以帮忙吗?
解决方案
我想我已经整理好了,或者几乎整理好了。我打电话给服务:
startForegroundService(intent);
代替:
context.startService(intent);
我添加了权限:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
并将服务修改如下:
public class LocationService extends Service {
MockLocationProvider mockNetwork;
MockLocationProvider mockGps;
static NotificationManager notificationManager;
Context context;
private static final int ID_SERVICE = 101;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
context = getApplicationContext();
// Create the Foreground Service
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
String channelId = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? createNotificationChannel(notificationManager) : "";
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, channelId);
Notification notification = notificationBuilder
.setOngoing(true)
.setSmallIcon(R.drawable.ic_menu_pin_drop_24dp)
.setColor(ContextCompat.getColor(context, R.color.default_error_color))
.setContentTitle(getString(R.string.app_name) + " is running...")
.setPriority(PRIORITY_MIN)
.setVisibility(NotificationCompat.VISIBILITY_PRIVATE)
.setCategory(NotificationCompat.CATEGORY_SERVICE)
.build();
startForeground(ID_SERVICE, notification);
pushLocation(intent);
return LocationService.START_STICKY;
}
@RequiresApi(Build.VERSION_CODES.O)
private String createNotificationChannel(NotificationManager notificationManager){
String channelId = "my_service_channelid";
String channelName = "My Foreground Service";
NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH);
// omitted the LED color
channel.setImportance(NotificationManager.IMPORTANCE_NONE);
channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
notificationManager.createNotificationChannel(channel);
return channelId;
}
@Override
public IBinder onBind(Intent intent) {
pushLocation(intent);
return null;
}
private void pushLocation(Intent intent) {
try {
if (intent.hasExtra("lat") && intent.hasExtra("lng") ) {
double lat = intent.getDoubleExtra("lat", 45);
double lng = intent.getDoubleExtra("lng", 45);
mockNetwork = new MockLocationProvider(LocationManager.NETWORK_PROVIDER, context);
mockGps = new MockLocationProvider(LocationManager.GPS_PROVIDER, context);
mockNetwork.pushLocation(lat, lng);
mockGps.pushLocation(lat, lng);
//setNotification(lat, lng);
}
} catch (Exception e) {
e.printStackTrace();
}
}
我在这里使用了示例通知代码:
Android - 为服务实现 startForeground?
我注意到该服务在大约 25-30 分钟后在没有警告的情况下被终止,但随后似乎很快又重新启动了。也许与 onBind 方法有关?
有谁知道如何防止这种重新启动?
编辑:做更多的测试服务没有关闭,我认为这更多地与导致问题的手机上启用的“改进的位置”选项有关!
推荐阅读
- python - 如何查找连续重复三次的列表的副本
- java - SpringBoot 测试配置
- java - @NotNull 约束在 Spring Boot 中不起作用
- python - 将 Lasagne 转换为 Keras 代码 (CNN -> LSTM)
- laravel - MVC/PHP 我在哪里放置发出请求的代码?
- python-3.x - 无法在全新安装中启动 Airflow Webserver
- excel - 如何在 excel 中为隐式函数绘制 3D 曲面?
- javascript - Javascript/Jquery - 打印表中对象的数组
- javascript - 使用 Google Directions API 和 fetch 调用返回默认方向而不是搜索查询
- python - 如何将数组打印为特定格式?