Примечание. В этом вопросе предполагается, что вы знаете, как привязать службу к контексту.
Все на производстве знают об этой проблеме, или даже некоторые пользователи, у которых есть устройство Android Oreo или Pie. Исключение выглядит так:
Fatal Exception: android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1792)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6523)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:857)
Когда вы звоните Context.startForegroundService(Intent)
, вы также должны позвонить Service.startForeground(int, Notification)
в течение 5 секунд (даже если ваш телефон, возможно, даже не может запустить вашу службу, по какой-то причине это становится вашей ошибкой), иначе ваше приложение зависнет или выдаст исключение. из Android framework. Поразмыслив, я разработал решение.
Поскольку Context.startForegroundService(Intent)
не гарантирует, что служба будет создана в течение 5 секунд и является асинхронной операцией, я подумал, что что-то происходит следующим образом:
// Starts service.
public static void startService(Context context)
{
// If the context is null, bail.
if (context == null)
return;
// This is the same as checking Build.VERSION.SDK_INT >= Build.VERSION_CODES_O
if (Utilities.ATLEAST_OREO)
{
Log.w(TAG, "startForegroundService");
// Create the service connection.
ServiceConnection connection = new ServiceConnection()
{
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
// The binder of the service that
// returns the instance that is created.
MyService.LocalBinder binder = (MyService.LocalBinder) service;
// The getter method to acquire the service.
MyService myService = binder.getService();
// getServiceIntent(context) returns the relative service intent.
context.startForegroundService(getServiceIntent(context));
// This is the key: Without waiting Android Framework
// to call this method inside Service.onCreate(),
// immediately call here to post the notification.
// MyService.createNotification(context) is static
// for other purposes.
myService.startForeground(19982, MyService.createNotification(context));
// Release the connection to prevent leaks.
context.unbindService(this);
}
@Override
public void onServiceDisconnected(ComponentName name)
{
}
};
// Try to bind the service.
try
{
context.bindService(getServiceIntent(context), connection, Context.BIND_AUTO_CREATE);
}
catch (RuntimeException ignored)
{
// This is probably a broadcast receiver context
// even though we are calling getApplicationContext().
// Just call startForegroundService instead
// since we cannot bind a service to a
// broadcast receiver context.
// The service also have to call startForeground in this case.
context.startForegroundService(getServiceIntent(context));
}
}
else
{
// Normal stuff below API 26.
Log.w(TAG, "startService");
context.startService(getServiceIntent(context));
}
}
Эта функция вызывается из действия, запускающего службу. Интересно следующее: он работает и не вызывает исключения. Я тестировал на эмуляторах мое устройство, которое также является Oreo, и хочу подтвердить, что это лучший способ предотвратить это исключение. от происходящего.
Мой вопрос: действительно ли это хороший способ создать службу переднего плана? Есть предположения? Спасибо за ваши Коментарии.
FOREGROUND_SERVICE
разрешение в файл AndroidManifest? - person Nikunj Sorathiya   schedule 29.04.2019