Bir arka plan hizmetinin çalışıp çalışmadığını nasıl kontrol ederim?
Hizmetin durumunu değiştiren bir Android etkinliği istiyorum - açıksa kapatıp açmamı sağlar.
getRunningTasks()
, muhtemelen öyle olacaktır.
Bir arka plan hizmetinin çalışıp çalışmadığını nasıl kontrol ederim?
Hizmetin durumunu değiştiren bir Android etkinliği istiyorum - açıksa kapatıp açmamı sağlar.
getRunningTasks()
, muhtemelen öyle olacaktır.
Yanıtlar:
Uzun zaman önce aynı problemi yaşadım. Hizmetim yerel olduğundan, burada hackbod tarafından açıklandığı gibi, durumu değiştirmek için hizmet sınıfında statik bir alan kullandım
EDIT (kayıt için):
Hackbod tarafından önerilen çözüm:
İstemciniz ve sunucu kodunuz aynı .apk dosyasının bir parçasıysa ve hizmete somut bir Niyet (tam hizmet sınıfını belirten bir tane) ile bağlanıyorsanız, hizmetinizi çalıştırırken bir genel değişken ayarlamanız yeterlidir. müşteriniz kontrol edebilir.
Kasten bir hizmetin çalışıp çalışmadığını kontrol etmek için bir API'miz yok, çünkü neredeyse başarısız olmadan, kodunuzda yarış koşullarına sahip olduğunuz gibi bir şey yapmak istediğinizde.
onDestroy()
çağrısı yapılmaz. Dolayısıyla statik değişken, böyle bir senaryoda güncellenemez ve bu da tutarsız davranışlara neden olur.
Bir faaliyetin içinden aşağıdakileri kullanıyorum:
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;
}
Ve ben şunu kullanarak diyorum:
isMyServiceRunning(MyService.class)
ActivityManager # getRunningServices aracılığıyla Android işletim sistemi tarafından sağlanan hizmetlerin çalıştırılması hakkındaki bilgilere dayandığı için bu güvenilir bir şekilde çalışır .
OnDestroy veya onSometing olaylarını veya Bağlayıcıları veya statik değişkenleri kullanan tüm yaklaşımlar güvenilir bir şekilde çalışmaz, çünkü asla tanımadığınız bir geliştirici olarak, Android işleminizi öldürmeye karar verdiğinde veya belirtilen geri aramalardan hangisi çağrılır veya çağrılmaz. Android dokümanındaki yaşam döngüsü etkinlikleri tablosundaki "killable" sütununa dikkat edin .
getRunningServices
kullanımdan kaldırılmıştır. Bu yanıtın daha yeni bir sürüm için güncellenmesi gerekiyor.
Anladım!
Sen GEREKİR çağrı startService()
servis düzgün kayıtlı olması ve geçen için BIND_AUTO_CREATE
yeterli olmayacaktır.
Intent bindIntent = new Intent(this,ServiceTask.class);
startService(bindIntent);
bindService(bindIntent,mConnection,0);
Ve şimdi ServiceTools sınıfı:
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;
}
}
Küçük bir tamamlayıcı:
Amacım, bir hizmetin çalışmadığı halde gerçekte çalışmadan çalışıp çalışmadığını bilmek.
BindService'i çağırmak veya hizmet tarafından yakalanabilecek bir amacı aramak iyi bir fikir değildir, çünkü çalışmazsa hizmeti başlatacaktır.
Bu nedenle, miracle2k'nin önerdiği gibi, en iyisi, hizmetin başlatılıp başlatılmadığını bilmek için hizmet sınıfında statik bir alana sahip olmaktır.
Daha da temiz hale getirmek için, hizmeti çok tembel bir getirme ile tek birtonda dönüştürmeyi öneririm: yani, tekil örnekte statik yöntemlerle hiçbir somutlaşma yoktur . Hizmetinizin / singletonunuzun statik getInstance yöntemi, oluşturulmuşsa singleton örneğini döndürür. Fakat aslında singletonun kendisini başlatmaz veya başlatmaz. Hizmet yalnızca normal hizmet başlatma yöntemleri ile başlatılır.
Daha sonra, karmaşık getInstance yöntemini yöntem gibi bir şeye yeniden adlandırmak için singleton tasarım desenini değiştirmek daha da temiz olacaktır isInstanceCreated() : boolean
.
Kod şöyle görünecektir:
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
Bu çözüm zariftir, ancak yalnızca hizmet sınıfına erişiminiz varsa ve yalnızca sınıflar için hizmetin uygulaması / paketi söz konusuysa geçerlidir. Sınıflarınız hizmet uygulamasının / paketinin dışındaysa, Pieter-Jan Van Robays tarafından vurgulanan sınırlamalarla ActivityManager'ı sorgulayabilirsiniz.
Bunu kullanabilirsiniz (henüz denemedim, ama umarım bu işe yarar):
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();
}
Zaten çalışan bir hizmet varsa startService yöntemi bir ComponentName nesnesi döndürür. Değilse, null değeri döndürülür.
Genel özet BileşenAdı startService (Amaç hizmeti) konusuna bakın .
Bu sanırım kontrol gibi değil, çünkü hizmet başlıyor, böylece stopService(someIntent);
kodun altına ekleyebilirsiniz .
if(startService(someIntent) != null)
bunu kontrol edecek IsserviceRunning
ama aynı zamanda yeni bir servis oynayacak.
/**
* 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 dokümanlarından bir alıntı :
Gibi (Niyet) sendBroadcast , ama orada bu işlev engeller Niyet herhangi alıcıları ve hemen dönmeden önce sürükleyiveririz eğer.
Bu kesmek "ping" olarak düşününService
. Eşzamanlı olarak yayınlayabildiğimiz için, UI iş parçacığında eşzamanlı olarak yayın yapabilir ve bir sonuç elde edebiliriz .
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;
}
}
Birçok uygulamada kazanan, tabii ki, ayarlandığında hizmet üzerinde statik boole alandır true
içinde Service.onCreate()
ve false
de Service.onDestroy()
bu çok daha basit olduğu için.
Yukarıda sunulan çözümlerden birini biraz değiştirdim, ancak aynı yöntemden çıkan dizeleri karşılaştırmak için genel bir dize adı yerine sınıfı geçirerek 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;
}
}
ve sonra
Boolean isServiceRunning = ServiceTools.isServiceRunning(
MainActivity.this.getApplicationContext(),
BackgroundIntentService.class);
Class<? extends Service>
Bir hizmetin çalışıp çalışmadığını kontrol etmenin uygun yolu, bunu sormaktır. Hizmetinizde faaliyetlerinizdeki ping'lere yanıt veren bir BroadcastReceiver uygulayın. Hizmet başladığında BroadcastReceiver'ı kaydedin ve hizmet imha edildiğinde kaydını silin. Etkinliğinizden (veya herhangi bir bileşenden) hizmete yerel bir yayın amacı gönderin ve yanıt verirse çalıştığını bilirsiniz. Aşağıdaki kodda ACTION_PING ve ACTION_PONG arasındaki küçük farkı not edin.
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;
}
}
};
}
Sadece @Snicolas'ın cevabına bir not eklemek istiyorum. Durdurma servisini çağrılarak / çağırmadan kontrol etmek için aşağıdaki adımlar kullanılabilir onDestroy()
.
onDestroy()
çağrılan: Ayarlar -> Uygulama -> Çalışan Hizmetler -> Hizmetinizi seçin ve durdurun.
onDestroy()
Aranmadı: Servisinizin çalıştığı uygulamanızı Ayarlar -> Uygulama -> Uygulamaları Yönet -> seçin ve "Zorla Durdur" a gidin. Ancak, başvurunuz burada durdurulduğundan, kesinlikle hizmet örnekleri de durdurulacaktır.
Son olarak, singleton sınıfında statik bir değişken kullanan bu yaklaşımın benim için çalıştığını belirtmek isterim.
onDestroy
bu işe yaramaz yani her zaman hizmet çağrılmaz!
Örneğin: Sadece Eclipse'deki bir değişiklikle uygulamayı tekrar çalıştırın. Uygulama SIG: 9 kullanılarak zorla çıkar.
Öncelikle ActivityManager'ı kullanarak servise ulaşmaya çalışamazsınız. ( Burada tartışıldı )
Hizmetler kendi başlarına çalışabilir, bir Faaliyete veya her ikisine birden bağlı olabilir. Bir Etkinliğin Hizmetinizin çalışıp çalışmadığını kontrol etmenin yolu, hem Etkinliğin hem de Hizmetin anladığı yöntemleri bildirdiğiniz bir arabirim (Bağlayıcıyı genişleten) yapmaktır. Bunu, örneğin "isServiceRunning ()" gibi beyan ettiğiniz kendi Arayüzünüzü yaparak yapabilirsiniz. Daha sonra Etkinliğinizi Hizmetinize bağlayabilir, isServiceRunning () yöntemini çalıştırabilirsiniz, Hizmet çalışıp çalışmadığını kontrol eder ve Faaliyetinize bir boole döndürür.
Bu yöntemi, Hizmetinizi durdurmak veya başka bir şekilde etkileşimde bulunmak için de kullanabilirsiniz.
Bu öğreticiyi uygulamamda bu senaryoyu nasıl uygulayacağımı öğrenmek için kullandım .
Yine, beklemede olan hedefleri kullanan kişilerin daha temiz bulabileceği başka bir alternatif (örneğin 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
Hizmetinizle ilişkili bekleyen hedefleri belirlemek için sınıfınızda özel olarak tanımladığınız bir sabit nerede .
Aşağıda hepsini kapsayan zarif bir kesmek var Ifs
. Bu yalnızca yerel hizmetler içindir.
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;
}
}
Ve daha sonra:
if(AService.isServiceCreated()){
...
}else{
startService(...);
}
Xamarin C # sürümü:
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
.
Burada verilen kullanım durumu için, sadece stopService()
yöntemin dönüş değerini kullanabiliriz. true
Belirtilen hizmet varsa geri döner ve öldürülür. Yoksa geri döner false
. Dolayısıyla, sonuç false
başka bir durumda geçerli hizmetin durdurulmuş olduğundan emin olabilirseniz hizmeti yeniden başlatabilirsiniz . Eğer bir göz varsa :) daha iyi olurdu bu .
Kotlin kullanan başka bir yaklaşım. Diğer kullanıcıların cevaplarından ilham aldı
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 uzantısı olarak
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 }
}
kullanım
context.isMyServiceRunning(MyService::class.java)
Kotlin'de, tamamlayıcı nesneye boolean değişkeni ekleyebilir ve değerini istediğiniz herhangi bir sınıftan kontrol edebilirsiniz:
companion object{
var isRuning = false
}
Hizmet oluşturulduğunda ve yok edildiğinde değerini değiştirin
override fun onCreate() {
super.onCreate()
isRuning = true
}
override fun onDestroy() {
super.onDestroy()
isRuning = false
}
Hizmet Alt Sınıfınızda Hizmetin durumunu aşağıda gösterildiği gibi almak için bir Statik Boole kullanın.
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 için aşağıdaki kodu kullanabilirsiniz.
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'nun yanıtı Kotlin sınıfında. Teşekkürler 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
}
Arama
isMyServiceRunning(NewService::class.java)
ActivityManager.getRunningServices
Android O'dan beri kullanımdan kaldırıldı
Aynı sınıf adına sahip birkaç hizmet olabilir.
Az önce iki uygulama oluşturdum. İlk uygulamanın paket adı com.example.mock
. lorem
Uygulamada çağrılan bir alt paket ve çağrılan bir hizmet oluşturdum Mock2Service
. Yani tam adı com.example.mock.lorem.Mock2Service
.
Sonra ikinci uygulamayı ve adlı bir hizmeti yarattım Mock2Service
. İkinci uygulamanın paket adı com.example.mock.lorem
. Hizmetin tam adı com.example.mock.lorem.Mock2Service
da.
İşte benim logcat çıktı.
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
Daha iyi bir fikir karşılaştırmaktır ComponentName
çünkü örneklerini equals()
ait ComponentName
paket isimleri ve sınıf isimleri hem karşılaştırır. Ayrıca, bir cihazda aynı paket adına sahip iki uygulama bulunamaz.
Eşittir () yöntemi 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;
}
Lütfen bu kodu kullanın.
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;
}
Bu, bir iş parçacığı oluşturduğundan Intent Service hata ayıklaması için daha fazla geçerlidir, ancak düzenli hizmetler için de çalışabilir. Binging sayesinde bu konuyu buldum
Benim durumumda, hata ayıklayıcı ile oynadım ve iş parçacığı görünümü bulundu. MS Word'deki kurşun noktası simgesine benziyor. Her neyse, kullanmak için hata ayıklayıcı modunda olmanıza gerek yok. Süreci ve o düğmeyi tıklayın. Tüm Intent Services çalışırken en azından taklitçide görünecektir.
Hizmet başka bir işleme veya APK'ya aitse, ActivityManager'a dayalı çözümü kullanın.
Kaynağına erişiminiz varsa, statik alana dayalı olan çözümü kullanın. Ama bunun yerine bir boolean kullanarak bir Date nesnesi kullanmanızı öneririm. Hizmet çalışırken değerini 'şimdi' olarak güncelleyin ve işiniz bittiğinde değeri null olarak ayarlayın. Etkinlikten, boş değerinin veya tarihin çok eski olup olmadığını kontrol edebilirsiniz, bu da çalışmadığı anlamına gelir.
Hizmetinizden ilerleme durumu gibi daha fazla bilgi için yayınlandığını belirten yayın bildirimi de gönderebilirsiniz.
TheServiceClass içinde şunları tanımlar:
public static Boolean serviceRunning = false;
Sonra onStartCommand (...)
public int onStartCommand(Intent intent, int flags, int startId) {
serviceRunning = true;
...
}
@Override
public void onDestroy()
{
serviceRunning = false;
}
Ardından, if(TheServiceClass.serviceRunning == true)
herhangi bir sınıftan arayın .
stopService
. En azından Niyet hizmetleri için. onDestroy()
hemen çağrılır, ancak onHandleIntent()
yine de çalışır durumda
basit kullanım ile bağlama otomatik oluşturmayın - bkz. ps. ve güncelle ...
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);
misal :
Intent bindIntent = new Intent(context, Class<Service>);
boolean bindResult = context.bindService(bindIntent, ServiceConnection, 0);
neden kullanmıyorsun? getRunningServices ()
List<ActivityManager.RunningServiceInfo> getRunningServices (int maxNum)
Return a list of the services that are currently running.
Not: Bu yöntem yalnızca hizmet yönetimi türü kullanıcı arabirimlerinde hata ayıklama veya uygulama amaçlıdır.
ps. android dokümantasyon yanıltıcı herhangi bir şüpheyi ortadan kaldırmak için google tracker bir sorun açtı:
https://issuetracker.google.com/issues/68908332
Bağlama hizmetinin aslında Hizmet önbellek bağlayıcıları aracılığıyla ActivityManager bağlayıcı aracılığıyla bir işlem başlattığını görebildiğimiz için, bağlantının hangi hizmetten sorumlu olduğunu izlerim ama bağlamanın sonucunu görebildiğimiz gibi:
int res = ActivityManagerNative.getDefault().bindService(...);
return res != 0;
işlem bağlayıcı yoluyla yapılır:
ServiceManager.getService("activity");
Sonraki:
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return getIServiceManager().getService(name);
bu EtkinlikThread'de ayarlanır:
public final void bindApplication(...) {
if (services != null) {
// Setup the service cache in the ServiceManager
ServiceManager.initServiceCache(services);
}
bu yöntemde ActivityManagerService içinde çağrılır:
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
...
thread.bindApplication(... , getCommonServicesLocked(),...)
sonra:
private HashMap<String, IBinder> getCommonServicesLocked() {
ancak "aktivite" sadece pencere paketi ve alarm yoktur ..
bu yüzden aramak için geri dönmeliyiz:
return getIServiceManager().getService(name);
sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
bu çağrı yapar:
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
hangi yol açar:
BinderInternal.getContextObject()
ve bu yerli yöntem ....
/**
* 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();
Ben dinlenme çağrı disseke kadar ben cevabımı askıya kadar c kazdık şimdi zaman yok.
ancak hizmetin çalışıp çalışmadığını denetlemenin en iyi yolu bağlama oluşturmaktır (bağlama oluşturulmamışsa hizmet mevcut değilse) - ve bağlama üzerinden hizmeti durumu hakkında sorgulamaktır (bu durumda kayıtlı dahili bayrağı kullanarak).
bu ilginç buldum:
/**
* 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;
}
Kısacası :)
"Zaten bağlı bir hizmete bir bağlayıcı sağlayın. Bu yöntem eşzamanlıdır ve yoksa hedef hizmeti başlatmaz."
public IBinder peekService (Amaç hizmeti, String resolvedType, String callingPackage) RemoteException'ı atar;
*
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;
}
*
Benim kotlin dönüşüm ActivityManager::getRunningServices
tabanlı cevaplar. Bu işlevi bir etkinliğe
private fun isMyServiceRunning(serviceClass: Class<out Service>) =
(getSystemService(ACTIVITY_SERVICE) as ActivityManager)
.getRunningServices(Int.MAX_VALUE)
?.map { it.service.className }
?.contains(serviceClass.name) ?: false
Hizmetinizin hala arka planda çalışıp çalışmadığını görmek için Android Geliştirici seçeneklerindeki bu seçenekleri kullanmanız mümkündür.
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.
Sakin olun çocuklar :)
Bence en uygun çözüm, SharedPreferences
hizmetin çalışıp çalışmadığı hakkında bir anahtar / değer çifti tutmaktır .
Mantık çok düzdür; servis sınıfınızda istediğiniz herhangi bir konumda; hizmetin çalışıp çalışmadığı konusunda sizin için bayrak görevi görecek bir boolean değeri girin. Ardından, uygulamanızda istediğiniz yerde bu değeri okuyun.
Uygulamamda kullandığım örnek bir kod aşağıda:
Hizmet sınıfımda (Ses Akışı için bir hizmet), hizmet hazır olduğunda aşağıdaki kodu yürütürüm;
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();
}
Sonra benim uygulama herhangi bir etkinliğinde, aşağıdaki kod yardımı ile hizmet durumunu kontrol ediyorum;
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);
}
Özel izin yok, döngü yok ... Kolay yol, temiz çözüm :)
Daha fazla bilgiye ihtiyacınız varsa, lütfen bağlantıya bakın
Bu yardımcı olur umarım.
onDestroy
hizmet öldürüldüğünde her zaman çağrılmaz. Örneğin, düşük bellek durumlarında hizmetlerimin onDestroy
çağrılmadan öldüğünü gördüm .