#android #variables #background-process #worker
#Android #переменные #фоновый процесс #рабочий
Вопрос:
После изнурительного дня попыток внедрить процесс, который работает в фоновом режиме (даже после закрытия приложения) и проверяет наличие новых уведомлений, я достиг успешного завершения. Я думал, что приближаюсь к успешному концу.
У меня есть следующая реализация
Загрузочный приемник: — проверяет, что устройство включено и что пользователь вошел в систему.
public class BootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction()) amp;amp; !getEmail(context).isEmpty()) {
startService(context);
}
}
}
утилиты: — запускает / останавливает повторяющиеся действия (или перезапускается, если пользователь изменяет частоту выполнения действия)
public class utils {
private static final String TAG = "NotificationsChecker";
@SuppressLint("StaticFieldLeak")
public static NotificationsHelper notificationsHelper;
public static MutableLiveData<Boolean> newNotification = new MutableLiveData<>();
public static void startService(Context context) {
createNotificationsHelper(context);
if (newNotification == null || newNotification.getValue() == null) {
SQLiteData sqLiteData = new SQLiteData(context);
newNotification.setValue(sqLiteData.isUnreadNotification());
}
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build();
PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(NotificationsWorker.class, getNotificationsFrequency(context), TimeUnit.MINUTES)
.addTag(TAG)
.setConstraints(constraints)
.build();
WorkManager.getInstance(context).enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.REPLACE, workRequest);
}
private static void createNotificationsHelper(Context context) {
notificationsHelper = new NotificationsHelper(context, APIUtils.getAPIService(), newNotifications -> {
if (newNotification != null amp;amp; newNotification.getValue() != null amp;amp; !newNotification.getValue()) {
newNotification.setValue(newNotifications);
if (newNotification.getValue() amp;amp; !newNotification.hasActiveObservers())
showNotification(context, 1, "default_system_notification", "New notification", "There is new notification in Wedos app");
}
});
}
public static void stopService(Context context) {
WorkManager.getInstance(context).cancelAllWorkByTag(TAG);
Log.d("Notification service", "notification value is: " newNotification.getValue());
}
public static void restartService(Context context) {
stopService(context);
startService(context);
}
public static void destroyService(Context context) {
stopService(context);
if (notificationsHelper != null)
notificationsHelper.destroy();
}
}
Рабочий — проверяет наличие новых уведомлений
public class NotificationsWorker extends Worker {
public NotificationsWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
Log.d("Notifications worker", "Worker initiated");
}
@NonNull
@Override
public Result doWork() {
//if (notificationsHelper != null)
notificationsHelper.prepareAPI();
return Result.success();
}
}
NotificationsHelper — возвращает результат из notificationsHelper.prepareAPI()
back to utils
...
//API call
...
listener.onCheck(newNotifications); //depends on API result
проблема в том, что Worker возвращает мне следующее, когда я закрываю приложение:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.package.example.ui.notifications.NotificationsHelper.prepareAPI()' on a null object reference
Общая идея заключается в следующем:
после перезагрузки устройства проверяется, вошел ли пользователь в систему. Если это так, вызывается метод startService(), который проверяет наличие новых уведомлений.
Если пользователь выходит из приложения, вызывается метод serviceDestroy(), Который отменяет PeriodicWorker и уничтожает NotificationsHelper (подключение к базе данных SQLite и т. Д.).
После успешного входа в приложение вызывается метод startService(), который создает новый NotificationHelper и снова запускает PeriodicWorker.
Если пользователь изменяет частоту опроса новых уведомлений, вызывается метод restartService(), который перезапускает PeriodicWorker.
Если приложение не запущено (я проверяю с помощью hasActiveObservers()), я выведу уведомление.
Если приложение запущено, я ничего не буду делать, потому что
newNotification.observe((LifecycleOwner) context, aBoolean -> {
if (aBoolean) newNotificationPin.setVisibility(View.VISIBLE);
else newNotificationPin.setVisibility(View.GONE);
});
который визуально указывает, есть ли непрочитанные уведомления, вызывается из каждого действия или фрагмента.
Конечно, переменная newNotification должна по-прежнему сохранять свое установленное состояние, чтобы правильно указывать новые уведомления (т.Е. Когда непрочитанные уведомления обнаруживаются в фоновом режиме, и я открываю приложение, я должен увидеть визуальное изображение непрочитанного уведомления)
Спасибо за помощь
Комментарии:
1. Я полагаю, что исключение nullpointer происходит из метода prepareApi() , там что-то равно нулю, проверьте с помощью отладчика и проверьте, прошел ли ответ успешно
2. @takieddine К сожалению, ошибка указывает непосредственно на
notificationsHelper.prepareAPI();
строку, поэтому я боюсь, что значение notificationsHelper равно null.3. prepareApi() — это функция, в которой вы правильно выполнили свой вызов api, поэтому проверьте, не являются ли данные, которые вы получаете из api, null , и убедитесь, что prepareApi не возвращает что-то нулевое
4. @takieddine ХОРОШО, я проверю это завтра, но я использую эту функцию в другом классе (я думаю), и там все в порядке. Кстати, в prepareAPI () Я извлекаю API и сохраняю уведомления в базе данных SQLite
5. Когда ваше приложение выходит из строя, ваш logcat покажет строки, по которым вы должны щелкнуть, и это приведет вас к точной строке проблемы с сбоем
Ответ №1:
«проблема в том, что Worker возвращает мне следующее, когда я закрываю приложение»
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.package.example.ui.notifications.NotificationsHelper.prepareAPI()' on a null object reference
Если вы закроете приложение до завершения рабочего процесса, а затем снова запустите приложение, новый экземпляр этого рабочего будет создан с тем же Worker.id раньше. Когда это произойдет, DoWork будет вызван снова. Итак, если этот парень (NotificationsHelper) еще не создан, когда Рабочий запускается снова, мы получаем этот NPE.
Комментарии:
1. Однако NotificationsHelper следует создавать только один раз, при вызове метода startService() в классе utils. Это означает, что переменная NotificationsHelper должна оставаться неизменной при закрытии приложения, не так ли?
2. проверьте мой ответ (я добавил logcat)
3. Если приложение действительно закрыто, это означает, что экземпляр NotificationHelper больше не существует, поскольку процесс был завершен.
Ответ №2:
Logcat:
2020-12-22 12:03:47.867 28181-28208/com.example.android D/Notifications worker: Worker initiated
2020-12-22 12:03:47.876 28181-28212/com.example.android D/Notifications worker: doWork initiated
2020-12-22 12:03:47.881 28181-28212/com.example.android D/Notifications worker: notificationsHelper is null
2020-12-22 12:03:47.882 28181-28211/com.example.android E/WM-WorkerWrapper: Work [ id=26e5ac17-51f0-4f38-9c61-ba29e76525cc, tags={ com.example.android.BackgroundService.NotificationsWorker, NotificationsChecker } ] failed because it threw an exception/error
java.util.concurrent.ExecutionException: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.example.android.ui.notifications.NotificationsHelper.prepareAPI()' on a null object reference
at androidx.work.impl.utils.futures.AbstractFuture.getDoneValue(AbstractFuture.java:516)
at androidx.work.impl.utils.futures.AbstractFuture.get(AbstractFuture.java:475)
at androidx.work.impl.WorkerWrapper$2.run(WorkerWrapper.java:298)
at androidx.work.impl.utils.SerialExecutor$Task.run(SerialExecutor.java:91)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.example.android.ui.notifications.NotificationsHelper.prepareAPI()' on a null object reference
at com.example.android.BackgroundService.NotificationsWorker.doWork(NotificationsWorker.java:25)
at androidx.work.Worker$1.run(Worker.java:85)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
2020-12-22 12:03:47.884 28181-28211/com.example.android I/WM-WorkerWrapper: Worker result FAILURE for Work [ id=26e5ac17-51f0-4f38-9c61-ba29e76525cc, tags={ com.example.android.BackgroundService.NotificationsWorker, NotificationsChecker } ]
Редактировать:
После перезагрузки устройства Worker запустится и отобразит уведомление, если появится новое уведомление. При втором запуске значение notificationsHelper уже равно нулю. Без какого-либо взаимодействия с приложением.