백그라운드 서비스가 실행 중인지 어떻게 확인합니까?
서비스 상태를 전환하는 Android 활동이 필요합니다. 서비스가 켜져 있으면 켜고 끌 수 있습니다.
getRunningTasks()
아마 그럴 것이다.
백그라운드 서비스가 실행 중인지 어떻게 확인합니까?
서비스 상태를 전환하는 Android 활동이 필요합니다. 서비스가 켜져 있으면 켜고 끌 수 있습니다.
getRunningTasks()
아마 그럴 것이다.
답변:
얼마 전 같은 문제가있었습니다. 내 서비스가 로컬이기 때문에 hackbod에 설명 된 것처럼 서비스 클래스에서 정적 필드를 사용하여 상태를 전환했습니다 .
편집 (레코드 용) :
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)
ActivityManager # getRunningServices를 통해 Android 운영 체제에서 제공하는 서비스 실행에 대한 정보를 기반으로하기 때문에 안정적으로 작동합니다 .
onDestroy 또는 onSometing 이벤트 또는 바인더 또는 정적 변수를 사용하는 모든 접근 방식은 개발자가 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 메소드는 싱글 톤 인스턴스가 작성된 경우이를 리턴합니다. 그러나 실제로 싱글 톤 자체를 시작하거나 구성하지는 않습니다. 서비스는 일반적인 서비스 시작 방법을 통해서만 시작됩니다.
그런 다음 혼동하는 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
이 솔루션은 훌륭하지만 서비스 클래스에 액세스 할 수 있고 클래스의 경우에만 서비스의 앱 / 패키지와 관련이있는 경우에만 관련이 있습니다. 클래스가 서비스 앱 / 패키지 외부에있는 경우 Pieter-Jan Van Robays에 의해 밑줄이 그어진 제한 사항으로 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 오브젝트를 리턴합니다. 그렇지 않으면 null이 반환됩니다.
public abstract 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
. 동 기적으로 브로드 캐스트 할 수 있으므로 UI 스레드에서 브로드 캐스트하고 결과를 동 기적으로 얻을 수 있습니다 .
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를 구현하십시오. 서비스가 시작될 때 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()
호출되지 않음 : 설정-> 응용 프로그램-> 응용 프로그램 관리-> 서비스가 실행중인 응용 프로그램을 선택하고 "강제 중지"로 이동하십시오. 그러나 애플리케이션이 여기서 중지되므로 서비스 인스턴스도 확실히 중지됩니다.
마지막으로 싱글 톤 클래스에서 정적 변수를 사용하여 언급 한 접근 방식이 효과가 있다고 언급하고 싶습니다.
먼저 ActivityManager를 사용하여 서비스에 접근하지 마십시오. ( 여기서 논의 )
서비스는 자체적으로 실행되거나 활동에 바인딩되거나 둘 다에 바인딩 될 수 있습니다. 서비스가 실행 중인지 활동을 체크인하는 방법은 활동과 서비스 모두 이해하는 메소드를 선언하는 인터페이스 (바인더 확장)를 작성하는 것입니다. "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
.
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)
서비스 하위 클래스에서 정적 부울을 사용하여 아래에 설명 된대로 서비스 상태를 가져옵니다.
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
}
Kotlin 클래스에서 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
클래스 이름이 같은 여러 서비스가있을 수 있습니다.
방금 두 개의 앱을 만들었습니다. 첫 번째 앱의 패키지 이름은입니다 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
패키지 이름과 클래스 이름을 모두 비교합니다. 또한 장치에 동일한 패키지 이름을 가진 두 개의 앱을 설치할 수 없습니다.
의 equals () 메소드 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;
}
서비스가 다른 프로세스 또는 APK에 속하는 경우 ActivityManager를 기반으로 솔루션을 사용하십시오.
소스에 액세스 할 수 있으면 정적 필드를 기반으로하는 솔루션을 사용하십시오. 그러나 대신 부울을 사용하면 Date 객체를 사용하는 것이 좋습니다. 서비스가 실행되는 동안 값을 'now'로 업데이트하고 완료되면 null로 설정하십시오. 활동에서 널 또는 날짜가 너무 오래된 지 점검하여 실행 중이 아님을 확인할 수 있습니다.
또한 서비스에서 진행률과 같은 추가 정보를 따라 실행 중임을 나타내는 브로드 캐스트 알림을 보낼 수도 있습니다.
TheServiceClass 내부에서 다음을 정의합니다.
public static Boolean serviceRunning = false;
그런 다음 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/issues/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 (의도 서비스, 문자열 resolveType, 문자열 callingPackage)에서 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
기반 답변 의 내 kotlin 변환 . 이 기능을 활동에 넣으십시오.
private fun isMyServiceRunning(serviceClass: Class<out Service>) =
(getSystemService(ACTIVITY_SERVICE) as ActivityManager)
.getRunningServices(Int.MAX_VALUE)
?.map { it.service.className }
?.contains(serviceClass.name) ?: false
쉬운 사람을 가져 가라 ... :)
가장 적합한 솔루션은 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
가 호출 되지 않고 종료 되는 것을 보았습니다 .