Рабочая-нить заканчивается преждевременно
Я нацеливаюсь на Oreo. Как вы знаете, в oreo введены ограничения на время выполнения фоновых задач. Обходные пути - согласно Google - поставить фоновую задачу на передний план. Это то, что я пытался сделать, но после запуска службы переднего плана она через некоторое время разрушается. Сначала телефон выключает экран, затем, когда я снова его активирую, фоновая задача продолжается. Иногда служба onDestroy на переднем плане вызывается без выполнения задачи.
Моя цель состоит в том, чтобы все задачи, задаваемые enqueueWork, выполнялись без вызова ondestroy и без режима ожидания телефона для его прерывания.
ForeGroundService
public class ForeGroundService extends JobIntentService {
static final int JOB_ID = 1000;
static final int ONGOING_NOTIFICATION_ID = 33;
static void enqueueWork(Context context, Intent work) {
enqueueWork(context, ForeGroundService.class, JOB_ID, work);
}
Notification.Builder notification;
NotificationManager mNotificationManager;
@RequiresApi(api = Build.VERSION_CODES.O)
void einleitung(String Titel, String Text)
{
Intent notificationIntent = new Intent(this, ForeGroundService.class);
PendingIntent pendingIntent =
PendingIntent.getActivity(this, 0, notificationIntent, 0);
mNotificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(Titel,
Text,
NotificationManager.IMPORTANCE_HIGH);
channel.setSound(null,null);
mNotificationManager.createNotificationChannel(channel);
}
notification =
new Notification.Builder(this,Titel)
.setContentTitle(Titel)
.setContentText(Text)
.setSmallIcon(R.drawable.kleinesicon)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
.setContentIntent(pendingIntent)
.setTicker("setTicker");
mNotificationManager.notify(ONGOING_NOTIFICATION_ID, notification.build());
startForeground(ONGOING_NOTIFICATION_ID, notification.build());
}
@RequiresApi(api = Build.VERSION_CODES.O)
void vordergrund(String Titel, String Text)
{
notification.setContentTitle(Titel);
notification.setContentText(Text);
mNotificationManager.notify(ONGOING_NOTIFICATION_ID, notification.build());
}
PowerManager.WakeLock wakeLock;
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
protected void onHandleWork(Intent intent) {
if (beginn) {
einleitung("Test", "Test");
beginn = false;
}
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"MyWakelockTag");
wakeLock.acquire();
//Do Work
}
@Override
public void onDestroy() {
super.onDestroy();
Intent local = new Intent();
local.setAction("de.test.action");
this.sendBroadcast(local);
stopForeground(true);
//toast("Fertig");
if (wakeLock != null)
wakeLock.release();
}
final Handler mHandler = new Handler();
}
Основная деятельность
public class MainActivity extends AppCompatActivity {
private int JI = 1000;
private BroadcastReceiver updateUIReciver;
@RequiresApi(api = Build.VERSION_CODES.O)
void somefunction(someparameters)
{
Intent mServiceIntent = new Intent();
mServiceIntent.putExtra...
ForeGroundService.enqueueWork(getBaseContext(),ForeGroundService.class,JI,mServiceIntent);
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(updateUIReciver);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(R.style.AppTheme);
super.onCreate(savedInstanceState);
IntentFilter filter = new IntentFilter();
filter.addAction("de.test.action");
updateUIReciver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
ForeGroundService.shouldContinue = false;
}
};
registerReceiver(updateUIReciver,filter);
btnB.setOnClickListener(new View.OnClickListener() {
@RequiresApi(api = Build.VERSION_CODES.O)
public void onClick(View v) {
if (startcondition)
{
Intent startIntent = new Intent(MainActivity.this, MyService.class);
startIntent.setAction(Constants.ACTION.START_ACTION);
startService(startIntent);
Intent serviceIntent = new Intent(MainActivity.this,ForeGroundService.class);
startForegroundService(serviceIntent);
somefunction(someparameters);
}
else
{
Intent stopIntent = new Intent(MainActivity.this, MyService.class);
stopIntent.setAction(Constants.ACTION.STOP_ACTION);
startService(stopIntent);
}
}
});
}
}
РЕДАКТИРОВАТЬ: я сделал это работать с решением Сандхья Сасане и
public int onStartCommand(Intent intent, int flags, int startId)
{
if (beginn) {
executorService = Executors.newFixedThreadPool(1);
beginn = false;
}
final Intent i2 = intent;
executorService.execute(new Runnable(){
@Override
public void run(){
abarbeiten(i2);
}
});
return START_STICKY;
}
Важным является 1 в newFixedThreadPool(1); чтобы только один поток работал одновременно
1 ответ
Я нацеливаюсь на Oreo. Как вы знаете, в oreo введены ограничения на время выполнения фоновых задач.
Да, это так. Я могу понять вас, так как Google сделал вещи сначала очень странными и сложными..., потом снова сложными... потом снова... потом снова... И теперь разработчики, как я и вы, и ваш вопрос и проблема, обозначает результат / результат / доказательство этого.
Обходные пути - по словам Google...
Пожалуйста, сэкономьте время и себя тоже... Документация Google наихудшая.. Я дал -10 из 10 за их документацию.
поставить фоновое задание на передний план.
Вы неверно воспринимаете концепцию переднего плана..!! Внимательно прочитайте полный ответ дословно, Ваша проблема будет решена..!!
Это то, что я пытался сделать, но после запуска службы переднего плана она через некоторое время разрушается...
Теперь очень просто... Ваша концепция и реализация, оба неверны..., так что попробуйте новый пример проекта и рекомендации, приведенные здесь, а также пример рабочего и протестированного кода от 4.0 до последней версии Android P.
Сначала телефон выключает экран, затем, когда я снова его активирую, фоновая задача продолжается. Иногда служба onDestroy на переднем плане вызывается без выполнения задачи.
Это никак не связано с обслуживанием переднего плана.... забудьте об этом.
Моя цель состоит в том, чтобы все задачи, задаваемые enqueueWork, выполнялись без вызова ondestroy и без режима ожидания телефона для его прерывания.
Забудьте об этом тоже... Давайте сначала посмотрим, что такое служба переднего плана и как она создается...
Что такое передний план обслуживания
- Служба, которая остается активной (это не означает... непрерывно работающий, как никогда не заканчивающийся цикл do-while)
- Оставаться активным до следующей загрузки / перезагрузки
- Даже если пользователь удаляет приложение из последних, оно остается
- Но он не остается активным после следующей загрузки
- Он должен быть перезапущен пользователем путем повторного открытия приложения или через широковещательный приемник ON_BOOT_COMPLETE, либо с помощью AlarmManager, либо с помощью JobScedular.
Когда использовать
На мой взгляд, пользователям не нравится постоянное уведомление, показывающее сообщение ^ Это работает на переднем плане и может скоро разрядить вашу батарею ^, Опять же, пользователь не сможет смахнуть его и сможет только остановить или удалить приложение, чтобы остановить его. Так что, согласно моей точке зрения реализации, ^ Разработчики должны использовать это для реализации приемников времени выполнения, так как пост-oreo устройства не приветствуют статические приемники, реализованные путем расширения Broadcastreceiver
и поместив запись о своем намерении в файл manifest.xml... Даже если разработчик попытается сделать это, получатель никогда не будет вызываться на устройствах post-oreo..., Да, он будет вызываться ниже устройств oreo. Так что реализуйте только приемник ON_BOOT_COMPLETE и отдыхайте все в сервисе.
Как реализовать сервис переднего плана
Щелкните правой кнопкой мыши структуру проекта и создайте службу с именем RunnerService, а затем сгенерируйте все обязательные методы. для этого не требуется вводить весь код вручную. Сгенерируйте его, как сказано. Пример обслуживания переднего плана:
public class RunnerService extends Service
{
NotificationManager mNotifyManager;
NotificationCompat.Builder mBuilder;
NotificationChannel notificationChannel;
String NOTIFICATION_CHANNEL_ID = "1";
public RunnerService() { }
@Override
public void onCreate()
{
super.onCreate();
Log.d("RUNNER : ", "PROGRAMMED.... \n");
Bitmap IconLg = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_foreground);
mNotifyManager = (NotificationManager) getApplicationContext().getSystemService(NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(this, null);
mBuilder.setContentTitle("App Name")
.setContentText("Foreground service...")
.setTicker("Foreground service...")
.setSmallIcon(R.drawable.ic_menu_slideshow)
.setLargeIcon(IconLg)
.setPriority(Notification.PRIORITY_HIGH)
.setVibrate(new long[] {100})
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setOngoing(true)
.setAutoCancel(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "My Notifications", NotificationManager.IMPORTANCE_HIGH);
// Configure the notification channel.
notificationChannel.setDescription("Channel description");
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.setVibrationPattern(new long[]{100});
notificationChannel.enableVibration(true);
notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
mNotifyManager.createNotificationChannel(notificationChannel);
mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
startForeground(1, mBuilder.build());
}
else
{
mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
mNotifyManager.notify(1, mBuilder.build());
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.d("RUNNER : ", "\n IT IS ACTIVE UNTIL NEXT BOOT....");
return START_STICKY;
}
@Override
public void onDestroy()
{
Log.d("RUNNER : ", "\n IT WILL BE AGAIN ACTIVE BY ANDROID OS AUTOMATICALLY, DO NOT WORRY AND DONT CODE TO START IT AGAIN !!....");
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent)
{
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("NOT_YET_IMPLEMENTED_BY_DEVELOPER");
}
}
Как начать
Это зависит от того, на какой андроид вы нацеливаетесь ниже oreo или post oreo... Я предпочитаю все, как показано ниже:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
this.startForegroundService(new Intent(this, RunnerService.class));
}
else
{
this.startService(new Intent(this, RunnerService.class));
}
Либо из MainActivity, либо из ON_BOOT_RECEIVER, либо откуда угодно, просто запустите его, как сказано здесь...
Как проверить на переднем плане
Удаляя его из последних записей... Он вызовет onDestroy, но он никогда не будет уничтожен, вы не сможете смахнуть уведомление. Это означает успех.
Как проверить это быстро
С примером нового проекта с MainActivity просто вызывает сервис в указанном порядке.
Что дальше..?
Да, вы можете задать свои следующие задачи только здесь..., я буду продолжать обновлять и направлять... Я надеюсь, что вы сохранили enqueueWork
концепция и все ваши понятия в стороне и не думая об этом...
Давайте пошагово и дайте мне знать об обновлениях....
ОБНОВЛЕНИЕ 2
Вы должны попробовать это только на эмуляторе... В случае успеха, попробуйте на реальных устройствах... Здесь снова проблема...
В настоящее время в мире существует множество производителей мобильных телефонов, которые берут Android из Google, так как он является открытым исходным кодом, и модифицируют его, чтобы отключить все службы в BOOT. Это только удерживает Google, WhatsApp, FaceBook, Twitter и лидеров крупнейших рынков... Как будто они не позволяют им, никто не будет покупать их устройства...
Примеры:
- Vivo = FunTouchOs
- Oppo = ColorOs
- Есть огромный список....
Не проверяйте это для BOOT_COMPLETE..., он не будет работать, поскольку они модифицированы Android.
Но я хочу проверить это на реальном устройстве
Затем протестируйте его на таком устройстве, которое является чисто Google и имеет Android OS.
Тогда что мне делать для других ОС, измененных с Android
Есть трюки..., но давайте идти шаг за шагом.... Я дам вам знать, как только вы добьетесь успеха в этом..!!
ОБНОВЛЕНИЕ: 3
Поскольку не ясно, каково требование, я делаю некоторые предположения и пишу ответ:
Что вы можете сделать, чтобы реализовать выполнение переднего плана:
- Реализуйте передний план службы, как я изобразил
- Используйте местный
broadcastmanager
транслировать собственные события. - в
onCreate
приемника времени выполнения регистра службы переднего плана для приема этих передач - При получении трансляции обращайтесь к методам определенного пользователем класса с
context
переднего плана обслуживания. И выполнить все задачи оттуда. - Отменить регистрацию получателя в сервисе onDestroy переднего плана.
Что вы можете сделать для реализации фонового выполнения:
Если у вас повторяющиеся задачи и вы хотите выполнить их в background
даже если приложение удалено из последних выпусков... Тогда:
- Используйте Firebase Job Dispatcher, который использует GooglePLAYServices
- Если вы используете
forever
тогда это задание будет запущено автоматически, даже если система перезагружена, и даже если приложение находится не на переднем плане, не в фоновом режиме или не в копиях...
На данный момент я не вижу никакой необходимости в JobIntentService
и, следовательно, его статический enqueueWork
Способ; Для решения вашей проблемы требуется больше разрешения и деталей.