Як перевірити, чи працює фонова служба?
Я хочу активувати Android, що перемикає стан сервісу - він дозволяє мені його включати, якщо він вимкнений і вимкнений, якщо він увімкнено.
getRunningTasks()
, мабуть, так і буде.
Як перевірити, чи працює фонова служба?
Я хочу активувати Android, що перемикає стан сервісу - він дозволяє мені його включати, якщо він вимкнений і вимкнений, якщо він увімкнено.
getRunningTasks()
, мабуть, так і буде.
Відповіді:
У мене була така ж проблема недавно. Оскільки моя служба була локальною, я закінчив просто використовувати статичне поле в класі обслуговування для переключення стану, як описано тут hackbod
EDIT (для запису):
Ось рішення, запропоноване hackbod:
Якщо ваш клієнтський і серверний код є одним і тим же .apk і ви зобов’язуєтесь до служби конкретним наміром (той, який визначає точний клас обслуговування), тоді ви можете просто встановити службу глобальною змінною, коли вона працює, ваш клієнт може перевірити.
Ми навмисно не маємо API, щоб перевірити, чи працює служба, тому що, майже безвідмовно, коли ви хочете зробити щось подібне, ви в кінцевому підсумку перебуваєте в гоночних умовах.
onDestroy()
не викликається. Тож статична змінна не може бути оновлена в такому сценарії, що призводить до непослідовної поведінки.
Я використовую наступне в межах діяльності:
private boolean isMyServiceRunning(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
І я називаю це за допомогою:
isMyServiceRunning(MyService.class)
Це працює надійно, оскільки базується на інформації про запущені послуги, що надаються операційною системою Android через ActivityManager # getRunningServices .
Всі підходи, що використовують події onDestroy або onSometing або Binders або статичні змінні, не працюватимуть надійно, оскільки як розробник ви ніколи не знаєте, коли Android вирішить вбити ваш процес або який із згаданих зворотних зворотних викликів викликається чи ні. Зверніть увагу на стовпець "підлягає вбиттю" в таблиці подій життєвого циклу в документації на Android.
getRunningServices
є застарілим. Ця відповідь потребує оновлення для нової версії.
Зрозумів!
Ви ОБОВ'ЯЗКИ закликати, startService()
щоб Ваша послуга була зареєстрована належним чином, і проходження BIND_AUTO_CREATE
не буде достатньо.
Intent bindIntent = new Intent(this,ServiceTask.class);
startService(bindIntent);
bindService(bindIntent,mConnection,0);
А тепер клас ServiceTools:
public class ServiceTools {
private static String LOG_TAG = ServiceTools.class.getName();
public static boolean isServiceRunning(String serviceClassName){
final ActivityManager activityManager = (ActivityManager)Application.getContext().getSystemService(Context.ACTIVITY_SERVICE);
final List<RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);
for (RunningServiceInfo runningServiceInfo : services) {
if (runningServiceInfo.service.getClassName().equals(serviceClassName)){
return true;
}
}
return false;
}
}
Невелике доповнення:
Моя мета - дізнатися, чим надалі служба працює без її фактичного запуску, якщо вона не працює.
Виклик bindService або виклик наміру, який може бути спійманий службою, не є гарною ідеєю, оскільки він запустить службу, якщо вона не працює.
Отже, як запропонував miracle2k, найкраще - стати статичне поле в класі обслуговування, щоб знати, була послуга запущена чи ні.
Щоб зробити його ще чистішим, я пропоную перетворити послугу в синглтон з дуже дуже ледачим вилученням: тобто немає жодної інстанції у сінгтона екземплярах статичними методами. Статичний метод getInstance вашої служби / singleton просто повертає екземпляр синглтона, якщо він був створений. Але це насправді не запускає і не приводить сингл в сам. Служба запускається лише за допомогою звичайних методів запуску служби.
Тоді було б ще чистішим чином змінити схему дизайну сингл, щоб перейменовувати заплутаний метод getInstance в щось на зразок isInstanceCreated() : boolean
методу.
Код виглядатиме так:
public class MyService extends Service
{
private static MyService instance = null;
public static boolean isInstanceCreated() {
return instance != null;
}//met
@Override
public void onCreate()
{
instance = this;
....
}//met
@Override
public void onDestroy()
{
instance = null;
...
}//met
}//class
Це рішення є елегантним, але воно доречне лише в тому випадку, якщо у вас є доступ до класу обслуговування і лише для класів є додаток / пакет послуги. Якщо ваші заняття знаходяться за межами програми / пакету послуг, ви можете запитати ActivityManager з обмеженнями, підкресленими Пітер-Яном Ван Робейсом.
Ви можете використовувати це (я ще цього не пробував, але сподіваюся, що це працює):
if(startService(someIntent) != null) {
Toast.makeText(getBaseContext(), "Service is already running", Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(getBaseContext(), "There is no service running, starting service..", Toast.LENGTH_SHORT).show();
}
Метод startService повертає об'єкт ComponentName, якщо вже існує служба. Якщо ні, нуль буде повернуто.
Див. Загальнодоступний реферат ComponentName startService (Служба намірів) .
Думаю, це не так, як перевірка, тому що вона запускає послугу, тому ви можете додати stopService(someIntent);
під кодом.
if(startService(someIntent) != null)
це перевірить, IsserviceRunning
але це також відтворить нову службу.
/**
* Check if the service is Running
* @param serviceClass the class of the Service
*
* @return true if the service is running otherwise false
*/
public boolean checkServiceRunning(Class<?> serviceClass){
ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE))
{
if (serviceClass.getName().equals(service.service.getClassName()))
{
return true;
}
}
return false;
}
Виписка з Android документів:
Як і sendBroadcast (Намір) , але якщо є якісь приймачі для наміру, ця функція буде заблокована та негайно відправити їх перед поверненням.
Подумайте про цей хак як про "пінг"Service
. Оскільки ми можемо транслювати синхронно, ми можемо транслювати та отримувати результат синхронно , на потоці інтерфейсу користувача.
Service
@Override
public void onCreate() {
LocalBroadcastManager
.getInstance(this)
.registerReceiver(new ServiceEchoReceiver(), new IntentFilter("ping"));
//do not forget to deregister the receiver when the service is destroyed to avoid
//any potential memory leaks
}
private class ServiceEchoReceiver extends BroadcastReceiver {
public void onReceive (Context context, Intent intent) {
LocalBroadcastManager
.getInstance(this)
.sendBroadcastSync(new Intent("pong"));
}
}
Activity
bool serviceRunning = false;
protected void onCreate (Bundle savedInstanceState){
LocalBroadcastManager.getInstance(this).registerReceiver(pong, new IntentFilter("pong"));
LocalBroadcastManager.getInstance(this).sendBroadcastSync(new Intent("ping"));
if(!serviceRunning){
//run the service
}
}
private BroadcastReceiver pong = new BroadcastReceiver(){
public void onReceive (Context context, Intent intent) {
serviceRunning = true;
}
}
Переможець у багатьох додатках, звичайно, статичне логічне поле на службі, встановлюється в true
у Service.onCreate()
і false
в , Service.onDestroy()
тому що це набагато простіше.
Я трохи змінив одне з рішень, представлених вище, але передаючи клас замість загальної назви рядка, щоб обов'язково порівняти рядки, що виходять із того самого методу class.getName()
public class ServiceTools {
private static String LOG_TAG = ServiceTools.class.getName();
public static boolean isServiceRunning(Context context,Class<?> serviceClass){
final ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
final List<RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);
for (RunningServiceInfo runningServiceInfo : services) {
Log.d(Constants.TAG, String.format("Service:%s", runningServiceInfo.service.getClassName()));
if (runningServiceInfo.service.getClassName().equals(serviceClass.getName())){
return true;
}
}
return false;
}
}
і потім
Boolean isServiceRunning = ServiceTools.isServiceRunning(
MainActivity.this.getApplicationContext(),
BackgroundIntentService.class);
Class<? extends Service>
Правильний спосіб перевірити, чи працює служба - просто запитати її. Створіть у своєму сервісі широкомовний приймач, який відповідає на пінг вашої діяльності. Зареєструйте програму BroadcastReceiver, коли послуга починається, і скасуйте її, коли послуга знищена. Здійснюючи свою діяльність (або будь-який компонент), надішліть службі локальну трансляцію, і якщо вона відповість, ви знаєте, що вона працює. Зверніть увагу на тонку різницю між ACTION_PING та ACTION_PONG у наведеному нижче коді.
public class PingableService extends Service
{
public static final String ACTION_PING = PingableService.class.getName() + ".PING";
public static final String ACTION_PONG = PingableService.class.getName() + ".PONG";
public int onStartCommand (Intent intent, int flags, int startId)
{
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, new IntentFilter(ACTION_PING));
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy ()
{
LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
super.onDestroy();
}
private BroadcastReceiver mReceiver = new BroadcastReceiver()
{
@Override
public void onReceive (Context context, Intent intent)
{
if (intent.getAction().equals(ACTION_PING))
{
LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getApplicationContext());
manager.sendBroadcast(new Intent(ACTION_PONG));
}
}
};
}
public class MyActivity extends Activity
{
private boolean isSvcRunning = false;
@Override
protected void onStart()
{
LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getApplicationContext());
manager.registerReceiver(mReceiver, new IntentFilter(PingableService.ACTION_PONG));
// the service will respond to this broadcast only if it's running
manager.sendBroadcast(new Intent(PingableService.ACTION_PING));
super.onStart();
}
@Override
protected void onStop()
{
LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
super.onStop();
}
protected BroadcastReceiver mReceiver = new BroadcastReceiver()
{
@Override
public void onReceive (Context context, Intent intent)
{
// here you receive the response from the service
if (intent.getAction().equals(PingableService.ACTION_PONG))
{
isSvcRunning = true;
}
}
};
}
Я просто хочу додати примітку до відповіді від @Snicolas. Наступні кроки можуть бути використані для перевірки зупинки обслуговування з / без виклику onDestroy()
.
onDestroy()
називається: Перейдіть у Налаштування -> Додаток -> Запуск послуг -> Виберіть і зупиніть свою послугу.
onDestroy()
не називається: Перейдіть у Налаштування -> Програма -> Керування програмами -> Виберіть та "Примусово зупиніть" свою програму, в якій працює ваша служба. Однак, оскільки ваша програма тут зупинена, то, безумовно, також будуть зупинені екземпляри служби.
Нарешті, я хотів би зазначити, що підхід, згаданий там із використанням статичної змінної в одиночному класі, працює для мене.
onDestroy
не завжди викликається в службі, тому це марно!
Наприклад: просто запустіть додаток ще раз із однією зміною від Eclipse. Заява закривається за допомогою SIG: 9.
Перш за все, ви не намагаєтеся отримати доступ до служби за допомогою ActivityManager. ( Тут обговорюється )
Послуги можуть працювати самостійно, прив'язуватися до діяльності або обох. Спосіб перевірити активність, чи працює Ваша Служба чи ні, - це створити інтерфейс (який розширює Binder), де ви заявляєте про методи, які розуміють і те, і Діяльність та Сервіс. Це можна зробити, створивши власний інтерфейс, де ви оголошуєте, наприклад, "isServiceRunning ()". Потім ви можете прив’язати свою активність до вашої служби, застосувати метод isServiceRunning (), служба перевірить, чи працює вона чи ні, і поверне булеві дані вашій діяльності.
Ви також можете використовувати цей метод, щоб зупинити Службу або взаємодіяти з нею іншим способом.
Я використовував цей підручник, щоб дізнатися, як реалізувати цей сценарій у своїй програмі.
Знову ще одна альтернатива, яку люди можуть знайти більш чистою, якщо вони використовують очікувані наміри (наприклад, із AlarmManager
:
public static boolean isRunning(Class<? extends Service> serviceClass) {
final Intent intent = new Intent(context, serviceClass);
return (PendingIntent.getService(context, CODE, intent, PendingIntent.FLAG_NO_CREATE) != null);
}
Де CODE
константа, яку ви визначаєте приватно у своєму класі, щоб визначити очікувані наміри, пов’язані з вашою службою.
Нижче представлений елегантний хакер, який охоплює всі Ifs
. Це лише для місцевих служб.
public final class AService extends Service {
private static AService mInstance = null;
public static boolean isServiceCreated() {
try {
// If instance was not cleared but the service was destroyed an Exception will be thrown
return mInstance != null && mInstance.ping();
} catch (NullPointerException e) {
// destroyed/not-started
return false;
}
}
/**
* Simply returns true. If the service is still active, this method will be accessible.
* @return
*/
private boolean ping() {
return true;
}
@Override
public void onCreate() {
mInstance = this;
}
@Override
public void onDestroy() {
mInstance = null;
}
}
А потім пізніше:
if(AService.isServiceCreated()){
...
}else{
startService(...);
}
Версія Xamarin C #:
private bool isMyServiceRunning(System.Type cls)
{
ActivityManager manager = (ActivityManager)GetSystemService(Context.ActivityService);
foreach (var service in manager.GetRunningServices(int.MaxValue)) {
if (service.Service.ClassName.Equals(Java.Lang.Class.FromType(cls).CanonicalName)) {
return true;
}
}
return false;
}
GetSystemService
.
Для наведеного тут випадку використання ми можемо просто скористатися stopService()
зворотним значенням методу. Він повертається, true
якщо існує вказана послуга, і вона вбита. Інакше це повертається false
. Таким чином, ви можете перезапустити службу, якщо результат false
інший, ви впевнені, що поточна служба була зупинена. :) Було б краще, якщо ви подивитесь на це .
Ще один підхід з використанням kotlin. Натхненний відповідями інших користувачів
fun isMyServiceRunning(serviceClass: Class<*>): Boolean {
val manager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
return manager.getRunningServices(Integer.MAX_VALUE)
.any { it.service.className == serviceClass.name }
}
Як розширення kotlin
fun Context.isMyServiceRunning(serviceClass: Class<*>): Boolean {
val manager = this.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
return manager.getRunningServices(Integer.MAX_VALUE)
.any { it.service.className == serviceClass.name }
}
Використання
context.isMyServiceRunning(MyService::class.java)
У kotlin ви можете додати boolean змінну в супровідний об'єкт і перевірити його значення з будь-якого класу, який ви бажаєте:
companion object{
var isRuning = false
}
Змініть його значення, коли служба створена та знищена
override fun onCreate() {
super.onCreate()
isRuning = true
}
override fun onDestroy() {
super.onDestroy()
isRuning = false
}
У своєму підкласі послуг Використовуйте статичний булевий стан, щоб отримати стан Сервісу, як показано нижче.
MyService.kt
class MyService : Service() {
override fun onCreate() {
super.onCreate()
isServiceStarted = true
}
override fun onDestroy() {
super.onDestroy()
isServiceStarted = false
}
companion object {
var isServiceStarted = false
}
}
MainActivity.kt
class MainActivity : AppCompatActivity(){
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val serviceStarted = FileObserverService.isServiceStarted
if (!serviceStarted) {
val startFileObserverService = Intent(this, FileObserverService::class.java)
ContextCompat.startForegroundService(this, startFileObserverService)
}
}
}
Для Kotlin ви можете використовувати наведений нижче код.
fun isMyServiceRunning(calssObj: Class<SERVICE_CALL_NAME>): Boolean {
val manager = requireActivity().getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
for (service in manager.getRunningServices(Integer.MAX_VALUE)) {
if (calssObj.getName().equals(service.service.getClassName())) {
return true
}
}
return false
}
Відповідь geekQ, але в класі Котліна. Спасибі geekQ
fun isMyServiceRunning(serviceClass : Class<*> ) : Boolean{
var manager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
for (service in manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.name.equals(service.service.className)) {
return true
}
}
return false
}
Виклик
isMyServiceRunning(NewService::class.java)
ActivityManager.getRunningServices
застаріло, оскільки Android O
Тут може бути кілька служб з однаковою назвою класу.
Я щойно створив два додатки. Ім'я пакета першого додатка є com.example.mock
. Я створив підпакет, який називається lorem
в додатку, і послуга під назвою Mock2Service
. Тож його цілком кваліфікована назва com.example.mock.lorem.Mock2Service
.
Потім я створив другий додаток і сервіс під назвою Mock2Service
. Ім'я пакета другого додатка є com.example.mock.lorem
. Повна кваліфікована назва сервісуcom.example.mock.lorem.Mock2Service
теж.
Ось мій вихід logcat.
03-27 12:02:19.985: D/TAG(32155): Mock-01: com.example.mock.lorem.Mock2Service
03-27 12:02:33.755: D/TAG(32277): Mock-02: com.example.mock.lorem.Mock2Service
Краща ідея полягає в порівняння ComponentName
випадків , так як equals()
вComponentName
порівняння як імена пакетів і імена класів. І на пристрої не може бути двох додатків з однаковою назвою пакета.
Метод рівних () ComponentName
.
@Override
public boolean equals(Object obj) {
try {
if (obj != null) {
ComponentName other = (ComponentName)obj;
// Note: no null checks, because mPackage and mClass can
// never be null.
return mPackage.equals(other.mPackage)
&& mClass.equals(other.mClass);
}
} catch (ClassCastException e) {
}
return false;
}
Будь ласка, використовуйте цей код.
if (isMyServiceRunning(MainActivity.this, xyzService.class)) { // Service class name
// Service running
} else {
// Service Stop
}
public static boolean isMyServiceRunning(Activity activity, Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
Це більше стосується налагодження намірної служби, оскільки вони породили нитку, але можуть працювати і для звичайних служб. Я знайшов цю тему завдяки Binging
У моєму випадку я пограв з налагоджувачем і виявив подання теми. Це виглядає як значок кулі в MS Word. У будь-якому випадку, вам не потрібно бути в режимі налагодження, щоб використовувати його. Натисніть на процес і натисніть на цю кнопку. Будь-які сервіси намірів з’являться під час роботи, принаймні, на емуляторі.
Якщо послуга належить до іншого процесу або APK, використовуйте рішення, засноване на ActivityManager.
Якщо у вас є доступ до його джерела, просто використовуйте рішення на основі статичного поля. Але замість використання булевого я б запропонував використовувати об'єкт Date. Поки служба працює, просто оновіть її значення на "зараз", а після завершення встановіть її на нуль. З цього виду можна перевірити, чи його нуль або дата занадто стара, це означає, що вона не працює.
Ви також можете надсилати сповіщення про трансляцію від своєї служби, вказуючи, що працює над додатковою інформацією, наприклад про хід.
Всередині TheServiceClass визначають:
public static Boolean serviceRunning = false;
Тоді In onStartCommand (...)
public int onStartCommand(Intent intent, int flags, int startId) {
serviceRunning = true;
...
}
@Override
public void onDestroy()
{
serviceRunning = false;
}
Потім зателефонуйте if(TheServiceClass.serviceRunning == true)
з будь-якого класу.
stopService
. Принаймні, для послуг Намір. onDestroy()
буде викликаний негайно, але onHandleIntent()
все ще працюватиме
просте використання зв'язується з не створюють автоматичне - див. ps. і оновити ...
public abstract class Context {
...
/*
* @return {true} If you have successfully bound to the service,
* {false} is returned if the connection is not made
* so you will not receive the service object.
*/
public abstract boolean bindService(@RequiresPermission Intent service,
@NonNull ServiceConnection conn, @BindServiceFlags int flags);
приклад:
Intent bindIntent = new Intent(context, Class<Service>);
boolean bindResult = context.bindService(bindIntent, ServiceConnection, 0);
чому б не використовувати? getRunningServices ()
List<ActivityManager.RunningServiceInfo> getRunningServices (int maxNum)
Return a list of the services that are currently running.
Примітка. Цей метод призначений лише для налагодження або реалізації користувальницьких інтерфейсів типу управління послугами.
пс. Документація на андроїд вводить в оману. Я відкрив проблему з трекером Google, щоб усунути будь-які сумніви:
https://issuetracker.google.com/isissue/68908332
як ми бачимо, служба зв’язування насправді викликає транзакцію через зв'язувальник ActivityManager через зв'язувачі кеш-сервісу - я маю відстежувати, яка служба відповідає за прив’язку, але, як ми бачимо, результат для прив’язки є:
int res = ActivityManagerNative.getDefault().bindService(...);
return res != 0;
транзакція здійснюється через палітурку:
ServiceManager.getService("activity");
наступний:
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return getIServiceManager().getService(name);
це встановлено в ActivityThread через:
public final void bindApplication(...) {
if (services != null) {
// Setup the service cache in the ServiceManager
ServiceManager.initServiceCache(services);
}
це називається у ActivityManagerService у методі:
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
...
thread.bindApplication(... , getCommonServicesLocked(),...)
тоді:
private HashMap<String, IBinder> getCommonServicesLocked() {
але немає "активності" лише віконного пакета та сигналізації.
тому нам потрібно повернутися до дзвінка:
return getIServiceManager().getService(name);
sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
це робить дзвінок через:
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
що призводить до:
BinderInternal.getContextObject()
і це рідний метод….
/**
* Return the global "context object" of the system. This is usually
* an implementation of IServiceManager, which you can use to find
* other services.
*/
public static final native IBinder getContextObject();
Зараз я не встигаю викопати c, поки я не розсічу дзвінок на відпочинок, я не зупиняю свою відповідь.
але найкращий спосіб перевірити, чи працює служба це створити прив'язку (якщо прив'язка не створена, служба не існує) - і запитувати службу про її стан через прив'язку (використовуючи збережений внутрішній прапор на ній стан).
мені було цікаво:
/**
* Provide a binder to an already-bound service. This method is synchronous
* and will not start the target service if it is not present, so it is safe
* to call from {@link #onReceive}.
*
* For peekService() to return a non null {@link android.os.IBinder} interface
* the service must have published it before. In other words some component
* must have called {@link android.content.Context#bindService(Intent, ServiceConnection, int)} on it.
*
* @param myContext The Context that had been passed to {@link #onReceive(Context, Intent)}
* @param service Identifies the already-bound service you wish to use. See
* {@link android.content.Context#bindService(Intent, ServiceConnection, int)}
* for more information.
*/
public IBinder peekService(Context myContext, Intent service) {
IActivityManager am = ActivityManager.getService();
IBinder binder = null;
try {
service.prepareToLeaveProcess(myContext);
binder = am.peekService(service, service.resolveTypeIfNeeded(
myContext.getContentResolver()), myContext.getOpPackageName());
} catch (RemoteException e) {
}
return binder;
}
коротко :)
"Надайте в'яжучу інформацію вже пов'язаній службі. Цей метод є синхронним і не запускає цільову службу, якщо її немає."
загальнодоступний IBinder peekService (Інтенційна служба, String разрешеноType, String callPackage) кидає RemoteException;
*
public static IBinder peekService(IBinder remote, Intent service, String resolvedType)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken("android.app.IActivityManager");
service.writeToParcel(data, 0);
data.writeString(resolvedType);
remote.transact(android.os.IBinder.FIRST_CALL_TRANSACTION+84, data, reply, 0);
reply.readException();
IBinder binder = reply.readStrongBinder();
reply.recycle();
data.recycle();
return binder;
}
*
Моє перетворення котліну на ActivityManager::getRunningServices
основі відповідей. Покладіть цю функцію на активність-
private fun isMyServiceRunning(serviceClass: Class<out Service>) =
(getSystemService(ACTIVITY_SERVICE) as ActivityManager)
.getRunningServices(Int.MAX_VALUE)
?.map { it.service.className }
?.contains(serviceClass.name) ?: false
Ви можете скористатися цими параметрами з опцій розробника Android, щоб побачити, чи ваша послуга все ще працює у фоновому режимі.
1. Open Settings in your Android device.
2. Find Developer Options.
3. Find Running Services option.
4. Find your app icon.
5. You will then see all the service that belongs to your app running in the background.
Легко, хлопці ... :)
Я думаю, що найбільш підходящим рішенням є проведення пари ключ-значення, SharedPreferences
приблизно, якщо служба працює чи ні.
Логіка дуже пряма; в будь-якому бажаному місці у вашому класі обслуговування; поставте булеве значення, яке буде виступати для вас як прапор щодо того, працює служба чи ні. Потім прочитайте це значення, де ви хочете, у своїй програмі.
Приклад коду, який я використовую у своєму додатку, наведено нижче:
У своєму сервісному класі (послуга для аудіо потоку) я виконую наступний код, коли послуга працює;
private void updatePlayerStatus(boolean isRadioPlaying)
{
SharedPreferences sharedPref = this.getSharedPreferences(getString(R.string.str_shared_file_name), Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putBoolean(getString(R.string.str_shared_file_radio_status_key), isRadioPlaying);
editor.commit();
}
Потім у будь-якій діяльності моєї заявки я перевіряю стан послуги за допомогою наступного коду;
private boolean isRadioRunning() {
SharedPreferences sharedPref = this.getSharedPreferences(getString(R.string.str_shared_file_name), Context.MODE_PRIVATE);
return sharedPref.getBoolean(getString(R.string.str_shared_file_radio_status_key), false);
}
Ніяких спеціальних дозволів, без циклів ... Простий спосіб, чисте рішення :)
Якщо вам потрібна додаткова інформація, перейдіть за посиланням
Сподіваюсь, це допомагає.
onDestroy
не завжди викликається, коли служба вбита. Наприклад, я бачив, як мої служби загинули в ситуаціях з низькою пам’яттю, не onDestroy
викликаючи.