英文:
Android broadcast reciever called but doesn't starts foreground service
问题
我为重新启动前台服务设置了广播接收器。
我有两台设备,它在魅族 M1 Note(Android 5.1)
上运行,但在三星 A8(Android 9)
上不起作用。在Oreo
之后查找限制的原因,似乎没问题,但以防万一可以参考 https://developer.android.com/about/versions/oreo/background.html
在第二个设备上,广播接收器被调用,但服务在重启后没有启动。
该服务跟踪位置并使用带有通知的startForeground()
进行正确工作。还尝试添加Worker
以便在重启后重新启动服务,但似乎工作丢失了。
请提供任何建议,为什么我的接收器不会运行服务。
感谢。
清单:
<!-- 你的清单内容 -->
接收器:
// 你的接收器内容
服务:
// 你的服务内容
注意:这只是你提供的代码的中文翻译部分。如有更多问题或需要进一步帮助,请随时问我。
英文:
I set up broadcast reciever for restarting my foreground service after reboot.
I have two devices and it works on Meizu M1 note (android 5.1)
but doesn't work on Samsung A8 (android 9)
. Looking for reason in restrictions after Oreo
and seems like it ok, but just in case https://developer.android.com/about/versions/oreo/background.html
On the second one broadcast reciever called, but service not started after reboot.
Service tracks location and uses startForeground()
with Notification
for correct work.
Also tried to add Worker
to restart service after reboot, but seems like work missing after that.
Please, geve any suggestions why my reciever doesn't run service.
Thanks.
Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.tracker">
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:name=".ui.di.App"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:isolatedProcess="true"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<receiver android:name="com.example.tracker.ui.broadcast.ServiceRestart">
<intent-filter>
<action android:name="restartService" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.ACTION_BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<service
android:name="com.example.tracker.ui.service.TrackerService"
android:enabled="true" />
<service
android:name="com.example.tracker.ui.worker.RestartIntentService"
android:enabled="true" />
<activity android:name=".ui.screen.main.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Reciever:
public class ServiceRestart extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.i("Broadcast Listened", "Service tried to stop");
Toast.makeText(context, "Broadcast: ServiceRestart launched " + intent.getAction(), Toast.LENGTH_LONG).show();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(new Intent(context, TrackerService.class));
} else {
context.startService(new Intent(context, TrackerService.class));
}
}
}
Service:
public class TrackerService extends Service implements LocationListener {
public static final String TAG = "TrackerService";
private static final int PROCESS_ID = 1024;
private static final int INTERVAL = 120; //seconds
private ConnectivityManager connectivityManager;
private PeriodicWorkRequest workRequest;
private PeriodicWorkRequest restartTrackerRequest;
private DbFirebaseModel dbFirebaseModel = new DbFirebaseModel();
private ServiceHandler mServiceHandler;
private static final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message message) {
}
}
public void onCreate() {
super.onCreate();
HandlerThread mHandlerThread = new HandlerThread("TrackerService.HandlerThread");
mHandlerThread.start();
mServiceHandler = new ServiceHandler(mHandlerThread.getLooper());
}
public TrackerService() {
super();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
addNotificationAndStartForeground();
addWorkers();
mServiceHandler.post(() -> {
connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
runLocationTransfer();
});
Log.d(TAG, "===== SERVICE START");
return START_STICKY;
}
private void addWorkers() {
workRequest = new PeriodicWorkRequest.Builder(
FirebaseWorker.class, 15, TimeUnit.MINUTES, 2, TimeUnit.MINUTES)
.build();
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
FirebaseWorker.TAG,
ExistingPeriodicWorkPolicy.REPLACE,
workRequest);
restartTrackerRequest = new PeriodicWorkRequest.Builder(
TrackerRestartWorker.class, 15, TimeUnit.MINUTES, 2, TimeUnit.MINUTES
).build();
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
TrackerRestartWorker.TAG,
ExistingPeriodicWorkPolicy.REPLACE,
restartTrackerRequest);
}
private void addNotificationAndStartForeground() {
String name = getString(R.string.app_name);
String description = "Service running...";
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0);
Notification.Builder notificationBuilder;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
Integer.toString(PROCESS_ID), "Tracker", NotificationManager.IMPORTANCE_HIGH);
channel.setDescription("Notify me when location tracking");
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(channel);
notificationBuilder = new Notification.Builder(this, Integer.toString(PROCESS_ID));
notificationBuilder.setContentTitle(name)
.setContentText(description)
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentIntent(pendingIntent);
notificationManager.notify(PROCESS_ID, notificationBuilder.build());
} else {
notificationBuilder = new Notification.Builder(this);
notificationBuilder.setContentTitle(name)
.setContentText(description)
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentIntent(pendingIntent);
}
startForeground(PROCESS_ID, notificationBuilder.build());
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "===== SERVICE STOP");
if (FirebaseAuth.getInstance().getCurrentUser() == null) {
WorkManager.getInstance(this).cancelWorkById(workRequest.getId());
WorkManager.getInstance(this).cancelWorkById(restartTrackerRequest.getId());
Log.d(TAG, "===== WORKERS STOP");
}
}
@Override
public void onTaskRemoved(Intent rootIntent) {
Log.d(TAG, "TASK REMOVED");
Toast.makeText(this, "LOCATION TASK REMOVED", Toast.LENGTH_SHORT).show();
super.onTaskRemoved(rootIntent);
}
private void runLocationTransfer() {
LocationRequest locationRequest = new LocationRequest();
locationRequest.setPriority(LocationRequest.PRIORITY_LOW_POWER);
locationRequest.setInterval(INTERVAL * 1000);
locationRequest.setFastestInterval(INTERVAL * 1000);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(locationRequest);
LocationSettingsRequest locationSettingsRequest = builder.build();
SettingsClient settingsClient = LocationServices.getSettingsClient(this);
settingsClient.checkLocationSettings(locationSettingsRequest);
try {
getFusedLocationProviderClient(this).requestLocationUpdates(locationRequest, new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
onLocationChanged(locationResult.getLastLocation());
}
},
Looper.myLooper());
} catch (SecurityException e) {
e.printStackTrace();
}
}
@Override
public void onLocationChanged(@NonNull Location location) {
if (FirebaseAuth.getInstance().getCurrentUser() == null) {
stopSelf();
Log.d(TAG, "====== SERVICE STOPPED by itself");
} else if (connectivityManager.getActiveNetworkInfo() != null
&& connectivityManager.getActiveNetworkInfo().isConnected()) {
dbFirebaseModel.saveLocation(location);
// test using sound notifications
try {
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Ringtone r = RingtoneManager.getRingtone(getApplicationContext(), notification);
r.play();
} catch (Exception e) {
e.printStackTrace();
}
Toast.makeText(this, "LOCATION ------ LATITUDE: " + location.getLatitude() + " LONGITUDE: " + location.getLongitude(), Toast.LENGTH_SHORT).show();
} else {
saveToLocalStorage(location);
}
}
private void saveToLocalStorage(Location location) {
Hawk.init(this).build();
String userId = Objects.requireNonNull(
FirebaseAuth.getInstance().getCurrentUser()
).getUid();
LocationData locationData = new LocationData(userId, location);
long count = 0;
if (Hawk.count() > count) {
count = Hawk.count();
}
while (Hawk.contains(String.valueOf(count))) {
count++;
}
Hawk.put(String.valueOf(count), locationData);
Log.d(TAG, "HAWK /// Saved to local storage. COUNT = " + Hawk.count());
}
}
答案1
得分: 0
以下步骤帮助我解决了这个问题:
-
卸载并重新安装应用
-
根据以下更改
manifest
<receiver android:name="com.foxminded.tracker.ui.broadcast.ServiceRestart" android:exported="true" android:enabled="true"> <intent-filter> <action android:name="restartService" /> <action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter>
</receiver>
在此处添加了 "android.intent.action.LOCKED_BOOT_COMPLETED"
和 android:exported="true" android:enabled="true;"
。
英文:
Following steps helped me solve it:
-
Remove and reinstall app
-
Change
manifest
according to this<receiver android:name="com.foxminded.tracker.ui.broadcast.ServiceRestart" android:exported="true" android:enabled="true"> <intent-filter> <action android:name="restartService" /> <action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter>
</receiver>
Here added "android.intent.action.LOCKED_BOOT_COMPLETED"
and android:exported="true" android:enabled="true"
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论