Uygulama android'de kaydırılarak öldürüldüğünde kod nasıl ele alınır?


106

Uygulamam çalışıyorsa ve ana sayfa düğmesine basarsam, uygulama arka planda çalışıyor. Uzun bir basın ev düğmesi ve son uygulama listesinden kaydırarak uygulama kapatılacaktır Şimdi, eğer olayların hiçbiri gibi onPause(), onStop()ya da onDestroy()işlem sonlandırılır ziyade çağrılır. Öyleyse hizmetlerimin durdurulmasını, bildirimleri kapatmasını ve dinleyicilerin kaydını silmesini istiyorsam bunu nasıl yapabilirim? Pek çok makale ve blog okudum, ancak herhangi bir yararlı bilgi almadım ve bununla ilgili herhangi bir belge bulamadım. Herhangi bir yardım memnuniyetle karşılanacaktır. Şimdiden teşekkürler.


Sorunumu çözüyorum. Check
MysticMagicϡ

@MysticMagic Bir Hizmet için işe yarayan, Bildirimleri iptal etmeye ve dinleyicilerin kaydını silmeye ne dersiniz?
CodeWarrior

OnTaskRemoved'da dinleyicilerin kaydını silebilirsiniz. Değil mi? Ve bildirimleri iptal etmek için de aynı
MysticMagicϡ

@ MysticMagicϡ Uygulama güncellemesinde aynı şeyleri yapmak istersem ne olur?
reji

Yanıtlar:


152

Az önce benzer bir sorunu çözdüm.

İşte, Son uygulama listesinden kaydırarak uygulama öldürüldüğünde hizmeti durdurmakla ilgili ise yapabilecekleriniz .

Manifest dosyanızın içinde, Hizmet için stopWithTaskolduğu gibi bayrağı tutun true. Sevmek:

<service
    android:name="com.myapp.MyService"
    android:stopWithTask="true" />

Ancak, dinleyicilerin kaydını silmek ve bildirimi durdurmak vb. İstediğinizi söylediğiniz gibi, şu yaklaşımı öneriyorum:

  1. Manifest dosyanızın içinde, Hizmet için stopWithTaskolduğu gibi bayrağı tutun false. Sevmek:

    <service
        android:name="com.myapp.MyService"
        android:stopWithTask="false" />
  2. Şimdi MyServicehizmetinizde geçersiz kılma yöntemi onTaskRemoved. (Bu yalnızca stopWithTaskolarak ayarlanmışsa ateşlenecektir false).

    public void onTaskRemoved(Intent rootIntent) {
    
        //unregister listeners
        //do any other cleanup if required
    
        //stop service
        stopSelf();  
    }

Kodun diğer kısımlarını da içeren daha fazla ayrıntı için soruma bakın .

Bu yardımcı olur umarım.


Teşekkürler. Bu yöntemin hızlıca öldürmeleri tanımlamak için kullanılıp kullanılamayacağını düşünüyorum. Basit boş servis?
Kiran

Evet @Kiran deneyebilirsiniz. :)
MysticMagicϡ

1
@ MysticMagicϡ merhaba, bir soru, çözümünüzü kullanmayı denedim, ancak sunucuya veri gönderme, google'a analitik vb. Gibi uzun işlemler bazen tamamen başarısız oluyor. Bu yöntemin kendisini tam olarak tamamlama şansı bulamadan süreç öldürülmüş olabilir mi? Ayrıca bu yöntemi bir Huawei cihazında denediniz mi? Görünüşe göre onTaskRemoved bu cihazlarda asla çağrılmıyor. Herhangi bir fikriniz neden?
Alon Minski

2
@ MysticMagicϡ public void onTaskRemoved (..) Yöntem Android O'da çağrı değil. Diğer işletim sistemlerinde sorunsuz çalışıyor ancak Android O'da sorun oluşuyor
Jay Patel

2
Bu kod, arka plan Hizmet sınırlaması nedeniyle Android O için çalışmıyor. Bunu tüm Android cihazlarda halletmenin bir yolu var mı?
Aanal Mehta

34

Bunu yapmanın bir yolunu buldum

bunun gibi bir hizmet yap

public class OnClearFromRecentService extends Service {

@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.d("ClearFromRecentService", "Service Started");
    return START_NOT_STICKY;
}

@Override
public void onDestroy() {
    super.onDestroy();
    Log.d("ClearFromRecentService", "Service Destroyed");
}

@Override
public void onTaskRemoved(Intent rootIntent) {
    Log.e("ClearFromRecentService", "END");
    //Code here
    stopSelf();
}

}

2) bu hizmeti manifest.xml dosyasına kaydedin

<service android:name="com.example.OnClearFromRecentService" android:stopWithTask="false" />

3) Ardından bu hizmeti sıçrama etkinliğinizde başlatın

startService(new Intent(getBaseContext(), OnClearFromRecentService.class));

Ve şimdi ne zaman uygulamanızı android'den temizlerseniz, o zaman bu yöntem onTaskRemoved () çalıştırılacaktır.


1
Bu yanıttan bire bir kopyalayıp yapıştırın: stackoverflow.com/questions/21040339
Flot2011

17

Benzer sorunu çözdüm. Son görevden kaydırdıktan sonra ve bir sonraki açılışta düzgün davranmasını istiyorsanız, aşağıdaki adımları izleyin: -

1) İşlem kimliğini paylaşılan tercihe kaydedin:

SharedPreferencesUtils.getInstance().putInt(SharedPreferencesUtils.APP_PROCESS_ID, android.os.Process.myPid());

2) Uygulama, son görevden silindikten sonra başlatıcıdan başlatıldığında şunları yapın:

int previousProcessID = mSharedPreferencesUtils.getInt(SharedPreferencesUtils.APP_PROCESS_ID);

int currentProcessID = android.os.Process.myPid();

if ((previousProcessID == currentProcessID)) {
    // This ensures application not killed yet either by clearing recent or anyway
} else {
    // This ensures application killed either by clearing recent or by anyother means
}

Onaylandı - Android 8'de hizmet olmadan kullanıldı. OnTaskRemoved () - güzelce yapıldı
Gal Rom

4
Bu çözüm yalnızca uygulamanın yeniden başlatılıp başlatılmadığını algılar, ancak uygulamanın öldürüldüğü anı tam olarak algılayamazsınız
Vadim Kotov

6

Ana sayfaya bastığınızda - onPauseve onStopAktiviteniz çağrılırken, şu anda tüm tasarruf ve temizliği yapmanız gerekir, çünkü Android platformu bunu daha fazla garanti etmez onDestroyveya başka herhangi bir yaşam döngüsü yönteminin çalıştırılacağı için süreç sonlandırılabilir. herhangi bir bildirimde bulunmadan.


12
Öneriniz için teşekkürler, ancak bildirimlerimi, servislerimi ve dinleyicilerimi öldürmek istemiyorum onPause()ve onstop()yalnızca kullanıcı uygulamadan çıktığında yani oturumu kapattığında öldürülmeleri gerekiyor.
CodeWarrior

1

Açıldığında verilerinizi kaydetmeniz gerekir onPause(). Şu yaşam döngüsü şemasına bakın: Android Geliştiricisi

Bir uygulamanın onPause()veya sonrasında kapatılabileceğini görebilirsiniz onStop().

Verilerinizi orada işleyin ve onRestart()\ konumunda kurtarın onCreate().

iyi şanslar!


1

Kaydırmayı kaldıramazsınız, çünkü sistem herhangi bir geri aramayı çağırmadan sürecinizi bellekten kaldırır.

Kullanıcı "son uygulamalar" ekranını aramadan önce, onPause () ekranının her zaman çağrılacağını kontrol ettim. Bu nedenle, tüm verileri isFinishing () öğesini işaretlemeden onPause yöntemine kaydetmeniz gerekir.

Geri düğmesini kontrol etmek için onBackPressed yöntemini kullanın.


1
Bunun tüm android sürümleri için tek güvenli yöntem olduğuna inanıyorum.
Sergio

@Sergio evet bu en güvenli yöntem ve daha büyük ölçekli Uygulama üzerinde test ettim.
Ahmad

1

ViewModel.onCleared (), amaç kullanıcı "durdur" ya da düğmesine basmak yerine kaydırarak sürpriz bir çıkış yaptığında bazı kaynakları (belki ağda başka bir yerde çalışan bir sistem) serbest bırakmaksa yararlı olabilir. [Bu soruya ilk olarak bu şekilde ulaştım].

Uygulama bir bildirim almaz ve yöndeki değişiklikler gibi yapılandırma değişiklikleri için Activity.onDestroy () çağrılır, bu nedenle yanıt orada değildir. Ancak ViewModel.onCleared, Uygulama kaydırıldığında (ve ayrıca kullanıcı etkinlikten geri çekildiğinde) çağrılır. Kullanmak istediğiniz kaynak yığındaki birden fazla etkinlikle ilişkiliyse, ViewModel.onClear'ın kaynağı serbest bırakıp bırakmayacağına karar vermek için referans sayıları veya başka bir mekanizma ekleyebilirsiniz.

Bu, ViewModel'i kullanmak için birçok iyi nedenden bir diğeridir.

- Bob


1

Yukarıdaki yaklaşımların neden benim durumum üzerinde çalışmadığını gerçekten bilmiyorum android:stopWithTask="false", onTaskRemoved()onu çağrılmamasını ayarlasam bile .

Başka bir iyi yaklaşım kullanmak olacaktır AndroidViewModel. Bu, kullanıcı geri düğmesine basarak uygulamadan çıktığı durumda bile çalışır.

Sadece ViewModelsınıfı MainActivitykendinize bağlayın ve ardından görevinizi onCleared()geri çağırın.

Misal:

public class MainViewModel extends AndroidViewModel {
    public MainViewModel(@NonNull Application application) {
        super(application);
    }

    @Override
    protected void onCleared() {
        // Do your task here
        Log.e("MainViewModel", "OnCleared mainViewModel");
        super.onCleared();
    }
}

daha sonra MainActivity'nize bağlayın:

MainViewModel viewModel = new ViewModelProvider(this).get(MainViewModel.class);

~ Voila!


Diğer yorum yapanların da belirttiği gibi Android O ve üstü nedeniyle hizmet yaklaşımıyla çalışmıyor olabilir. Bu, bunun için görünüm modellerini kullanmak için ilginç bir çözüm gibi görünüyor. Uygulama zorla öldürülürse (uygulama değiştirici ekranında kaydırılırsa) bu yine de tetiklenir mi? düzenleme: Bob'un cevabı bu durumlarda işe yaradığını gösteriyor
William Reed,

evet işe yarıyor, karşılaştığım durum bu
droidhs

0

Bu benim için android 6,7,8,9'da çalıştı.

Bunun gibi bir hizmet yapın:

 public class OnClearFromRecentService extends Service {

 @Override public IBinder onBind(Intent intent) {
     return null; }

 @Override public int onStartCommand(Intent intent, int flags, int
 startId) {
     Log.d("ClearFromRecentService", "Service Started");
     return START_NOT_STICKY; }

 @Override public void onDestroy() {
     super.onDestroy();
     Log.d("ClearFromRecentService", "Service Destroyed"); }

 @Override public void onTaskRemoved(Intent rootIntent) {
     Log.e("ClearFromRecentService", "END");
     //Code here
     stopSelf(); } }

2) Bu hizmeti şuraya kaydedin manifest.xml:

<service android:name="com.example.OnClearFromRecentService"
 android:stopWithTask="false" />

3) Ardından bu hizmeti sıçrama etkinliğinizde başlatın

 startService(new Intent(getBaseContext(),
 OnClearFromRecentService.class));

1
Ve neden hizmetiniz Android 8 ve üzeri sürümlerde çalışmaya devam edecek? Android 8 sonrası Başlatılan Hizmetlerde kısıtlama olduğunun farkındasınız, değil mi?
rahil008

0

Bob Cram'ın cevabında bahsettiği gibi, View Model'in onCleared () yöntemi cevaptır. Her iki durumda da çalışır:

  1. Kullanıcı uygulamayı arka planda kaydırarak kaldırdığında.
  2. Kullanıcı listeyi temizle düğmesini kullanarak tüm uygulamayı temizlediğinde.

Hizmetin onTaskRemoved () işlevi, kullanıcı uygulamayı arka plandan kaydırdığında çalışacak, ancak tümünü öldür düğmesi kullanılarak uygulamalar temizlendiğinde çalışmayacaktır.

Ancak viewModel'in onCleared () yöntemi her iki durumda da çalışır. Devam eden herhangi bir işlemi durdurmak veya uzak sunucudaki herhangi bir görevi temizlemek için if seçeneğini kullanabilirsiniz.

 override fun onCleared() {
        super.onCleared()
        Log.d(TAG , "App Killed")
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.