Android:通过bindService检查服务是否正在运行

21
什么是检查 Android 服务是否在运行的最佳方法?我知道 ActivityManager API,但是似乎不建议在类似我的情况下使用该 API(来源)。我也知道可以使用全局/持久变量来维护服务的状态。
我尝试使用设置为 0 的标志与 bindService,但我遇到了与 来源 链接中的人相同的问题(唯一的例外是,我正在尝试使用本地服务的 bindService)。
下面是调用:
getApplicationContext().bindService(new Intent(getApplicationContext(),
        MyService.class), mServiceConnection, 0);

始终返回true,但没有连接到服务。这是否是预期行为?在我看来,如果服务尚未运行(它确实没有运行,我已经检查过了),或者未设置BIND_AUTO_CREATE标志(同样,也没有设置),那么bindService应该返回false。

7个回答

11

使用共享首选项来保存服务运行标志。

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    int res = super.onStartCommand(intent, flags, startId);
    setRunning(true);
    return res;
}

@Override
public void onDestroy() {
    super.onDestroy();
    setRunning(false);
}

private void setRunning(boolean running) {
    SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
    SharedPreferences.Editor editor = pref.edit();

    editor.putBoolean(PREF_IS_RUNNING, running);
    editor.apply();
}

public static boolean isRunning(Context ctx) {
    SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(ctx.getApplicationContext());
    return pref.getBoolean(PREF_IS_RUNNING, false);
}

11
这不是一个好主意,SharedPreferences 会持久保存在非易失性存储器中,因此如果设备出现崩溃或断电的情况,您的 onDestroy 方法将不会被调用,下次启动您的应用程序时,它会认为服务正在运行,尽管实际上并不是这样。 - satur9nine
是的,我同意。SharedPreferences 不适用于此目的。但是,可以在应用程序启动时删除运行 pref。另一种方法是将运行布尔变量存储在 Application 对象中。 - Андрей Москвичёв
onDestroy并不总是被调用。 - Zar E Ahmer
1
最好保留一个静态布尔值,因为如果用户结束应用程序(例如:清除最近的应用程序)或设备意外关闭(例如:电量不足),共享首选项仍将保持为 true。 - Erick M. Sprengel

11

我有同样的问题;目前最好的解决方案似乎是在WhateverService中创建一个公共静态布尔值,在onCreate(或onStartCommand,由您选择)期间设置为true,并在onDestroy期间设置为false。然后,您可以从任何其他位于同一apk中的类中访问它。但这可能存在竞争条件。Android没有API可以检查服务是否正在运行(不带副作用):请参见http://groups.google.com/group/android-developers/browse_thread/thread/8c4bd731681b8331/bf3ae8ef79cad75d

我想竞争条件可能来自于操作系统可能随时终止远程服务(在另一个进程中)。如上所述,检查本地服务(同一进程)对我来说似乎没有竞争条件 - 如果操作系统终止服务,则会同时终止检查其状态的任何内容。


3

另一种方法:

public static boolean isServiceRunning(Context ctx, String serviceClassName) {
    ActivityManager manager = (ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE);
    for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
        if (TrackingService.class.getName().equals(serviceClassName)) {
            return true;
        }
    }
    return false;
}

当我使用上述代码时,它只提供了系统运行服务的信息。我正在寻找所有服务,包括我创建的那个。 - user1810931

1

我有同样的需求,并发现在已经绑定了其他内容的情况下运行.bindService会导致错误。我在运行.bindService之前做了这件事。

try{
    context.unbindService(fetch_connection);
} catch (IllegalArgumentException e){
    System.out.println("Unbinding didn't work. little surprise");
}

这只是检查您是否绑定了服务,而不是它是否已启动。 - Falmarri

0

在您的活动中,您可以通过使用服务实例来简单地检查它。在我的情况下,我是这样做的:

  button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            Intent intent=new Intent(MainActivity.this, MyService.class);
            //startService(intent);
            bindService(intent,serviceConnection,BIND_AUTO_CREATE);
            if (myService!=null)
            {
                myService.RecData(editText.getText().toString());
            }
        }
    });
}

ServiceConnection serviceConnection=new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        Toast.makeText(MainActivity.this,"onServiceConnected called",Toast.LENGTH_SHORT).show();
        MyService.MyBinder myBinder= (MyService.MyBinder) iBinder;
        myService= myBinder.getServiceInstant();
        myService.SetActivity(MainActivity.this);
        myService.RecData(editText.getText().toString());
    }


-1
你打算在服务运行/未运行时做什么?为什么不直接调用startService()呢?这将在服务未运行时创建它,如果已经运行,则会调用其onStart()方法。

2
假设我想打印一条消息“服务正在运行”或“服务未运行”。这就是为什么我必须获取服务是否正在运行的信息。我不能通过调用startService来实现这一点。 - Igor
但是为什么你要打印这个消息呢?如果服务没有运行,你只能做两件事:启动它或者不启动。 - Falmarri
1
因为我想告知用户服务是否正在运行。用户应该手动启动和停止服务(通过按下按钮)。当用户关闭活动(点击返回按钮)时,服务应继续运行。并且活动应该在用户下次启动它时知道服务已经在运行。 - Igor
2
我认为让用户了解服务通常是一个不好的主意。相反,让用户了解功能。如果您无法完成某个功能,因为未连接到服务,请优雅地失败并通知用户。如果每次用户运行您的应用程序时都告诉他们服务正在运行,那将变得非常烦人。他们不关心服务是否正在运行,他们想要的只是功能。 - Falmarri
6
好的,我看到这里我的信息不足 - 我说这个活动将打印一条消息,只是为了说明在特定时间(在活动开始时)需要什么类型的信息(服务是否正在运行)。我并不是真正关注可用性方面,因为其他应用程序正在使用类似的模式(例如Android音乐播放器),而是关注如何实现这一点。所以,让我重新表达我的问题 - Android音乐播放器是如何知道在活动开始时何时显示“播放按钮”(音乐播放器已停止)和何时显示“暂停按钮”(mp正在运行)? - Igor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接