Ön plan hizmeti son durdurulduğunda uygulama çalışmaya devam eder


9

Android'in süreç yönetiminde ön plan hizmetleriyle birlikte beni gerçekten şaşırtan bir davranışla karşılaştım.

Benim için makul olan nedir

  1. Uygulamanızı 'Son uygulamalar'dan kaydırdığınızda, işletim sistemi uygulama sürecini nispeten yakın bir gelecekte bitirmelidir.
  2. Bir ön plan hizmeti çalıştırırken uygulamanızı 'Son uygulamalar'dan kaydırdığınızda uygulama canlı kalır.
  3. Uygulamanızı 'Son uygulamalar'dan kaydırmadan önce ön plan hizmetini durdurduğunuzda 1) ile aynı olur.

Beni şaşırtan ne

Ön planda hiç etkinlik olmadığında ön plan hizmetini durdurduğunuzda (uygulama 'Son uygulamalar' bölümünde görünmez), uygulamanın şimdi öldürülmesini beklerim.

Ancak, bu gerçekleşmiyor, uygulama süreci hala yaşıyor.

Misal

Bu davranışı gösteren minimal bir örnek oluşturduk.

Ön Plan Hizmeti:

import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.IBinder
import androidx.core.app.NotificationCompat
import timber.log.Timber

class MyService : Service() {

    override fun onBind(intent: Intent?): IBinder? = null

    override fun onCreate() {
        super.onCreate()
        Timber.d("onCreate")
    }

    override fun onDestroy() {
        super.onDestroy()
        Timber.d("onDestroy")

        // just to make sure the service really stops
        stopForeground(true)
        stopSelf()
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        Timber.d("onStartCommand")
        startForeground(ID, serviceNotification())
        return START_NOT_STICKY
    }

    private fun serviceNotification(): Notification {
        createChannel()

        val stopServiceIntent = PendingIntent.getBroadcast(
            this,
            0,
            Intent(this, StopServiceReceiver::class.java),
            PendingIntent.FLAG_UPDATE_CURRENT
        )
        return NotificationCompat.Builder(this, CHANNEL_ID)
            .setSmallIcon(R.drawable.ic_launcher_foreground)
            .setContentTitle("This is my service")
            .setContentText("It runs as a foreground service.")
            .addAction(0, "Stop", stopServiceIntent)
            .build()
    }

    private fun createChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val notificationManager = getSystemService(NotificationManager::class.java)
            notificationManager.createNotificationChannel(
                NotificationChannel(
                    CHANNEL_ID,
                    "Test channel",
                    NotificationManager.IMPORTANCE_DEFAULT
                )
            )
        }
    }

    companion object {
        private const val ID = 532207
        private const val CHANNEL_ID = "test_channel"

        fun newIntent(context: Context) = Intent(context, MyService::class.java)
    }
}

Hizmeti durdurmak için BroadcastReceiver:

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent

class StopServiceReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {

        val serviceIntent = MyService.newIntent(context)

        context.stopService(serviceIntent)
    }
}

Aktivite:

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        startService(MyService.newIntent(this))
    }
}

Manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.christophlutz.processlifecycletest">

    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service android:name=".MyService"/>
        <receiver android:name=".StopServiceReceiver" />
    </application>

</manifest>

Aşağıdaki yöntemleri deneyin:

  1. Uygulamayı başlatın, ön plan hizmetini durdurun, 'Son uygulamalar'dan uygulamayı kaldırın
  2. Uygulamayı başlatın, 'Son uygulamalar'dan uygulamayı kaldırın, ön plan hizmetini durdurun

Android Studio LogCat uygulamasında uygulama işleminin vaka 1 için [DEAD] olarak işaretlendiğini, ancak vaka 2 için olmadığını görebilirsiniz.

Yeniden üretilmesi oldukça kolay olduğu için, amaçlanan bir davranış olabilir, ancak dokümanlarda bundan gerçek bir söz bulamadım.

Burada neler olduğunu bilen var mı?

Yanıtlar:


0

Bu, ön plan hizmetinin gerçekte ne yaptığına bağlıdır. Etkin bir şekilde belleği tüketen iş parçacıkları, ağ bağlantıları, dosya G / Ç vb. Bu, hizmeti durdurmaya çalışırken hayatta kalan tüm arabirim geri çağrılarını da içerir. Özellikle hala çalışmakta olan (hatta kesilen) iş parçacıkları ve bağlı hizmetler, hizmeti düzgün bir şekilde durduran yaşam döngüsünü engeller.

Hizmetinizde bellek sızıntısı olmadığından emin olun ve her bağlantıyı (veritabanı, ağ vb.) Kapatın, hizmetinizi durdurmadan önce tüm arabirimlerdeki tüm geri çağrıları kaldırın. Eğer onDestroy()çağrılırsa servisin imha edileceğinden emin olabilirsiniz .

Farklı süreçler için: Sürecin hayatta kalmasının nedeninin, sistemin hizmetin bir süre daha yeniden başlayabileceği şekilde göreceğine inanıyorum, bu yüzden süreci kısa bir süre hayatta tutuyor. En azından gözlemledim, çünkü sonra bile onDestroy()çağrıldım, süreç hayatta kaldı, hata ayıklayıcıdan görebildim.

Her şey yok edildikten sonra sürecin kesin olarak öldürülmesini sağlamak istiyorsanız (bu şekilde tavsiye edilmese de), işlemi her zaman sonlandırmak için bunu çağırabilirsiniz:

android.os.Process.killProcess(android.os.Process.myPid());

Davranışı, hiçbir bağlantı, iş parçacığı veya başka bir şey çalışmaya devam etmeyecek sorusundaki örnekle yeniden oluşturabilirsiniz. onDestroy(Hizmet) çağrılır, ancak her şey bittikten sonra süreç canlı kalır. Hizmetin yeniden başlatılması durumunda işletim sistemi süreci canlı tutsa bile, önce hizmeti durdurduğunuzda, ardından uygulamayı sonlardan kaldırdığınızda neden aynı şeyi yapmadığını görmüyorum. Görüntülenen davranış, özellikle arka plan yürütme sınırlarında yapılan son değişiklikler göz önüne alındığında oldukça sezgisel görünmüyor, bu nedenle sürecin durdurulmasını nasıl sağlayacağınızı bilmek güzel olurdu
David Medenjak

@DavidMedenjak Kullandığınız getApplicationContext().startService(MyService.newIntent(this));şeyin yerine kullanmayı deneyin ve sonuçları lütfen bana bildirin. Etkinliğin canlı kaldığına inanıyorum çünkü uygulama bağlamı yerine aktivite bağlamı kullanılıyor. Ayrıca Oreo veya üstü için test yapıyorsanız, kullanmayı deneyingetApplicationContext().startforegroundService(MyService.newIntent(this));
Furkan Yurdakul

0

Android sistemi, bellek, işlemci gücü ve uygulama süreçleri ömür boyu kendi bilinciyle bilinir - bir işlemi öldürmemeye karar verir (faaliyetler ve hizmetler ile aynıdır)

İşte bu konuyla ilgili resmi belgeler.

Ön plan ile ilgili söylediklerine bakın

Sistemde böyle birkaç süreç olacak ve bunlar sadece bellek çok düşükse, bu süreçlerin bile çalışmaya devam edemeyeceği son çare olarak öldürülecek. Genel olarak, bu noktada, cihaz bir bellek sayfalama durumuna ulaşmıştır, bu nedenle kullanıcı arabirimini duyarlı tutmak için bu eylem gereklidir.

ve görünür süreçler (Ön Plan Hizmeti görünür bir süreçtir)

Sistemde çalışan bu işlemlerin sayısı ön plan işlemlerinden daha az sınırlıdır, ancak yine de nispeten kontrol edilir. Bu süreçler son derece önemli kabul edilir ve tüm ön plan süreçlerinin çalışması için gerekli olmadıkça öldürülmez.

Bu, Android işletim sisteminin tüm ön plan süreçlerini destekleyecek kadar belleğe sahip olduğu sürece uygulama işleminizin çalışacağı anlamına gelir . Durdurursanız bile - sistem önbelleğe alınmış işlemlere taşıyabilir ve kuyruk benzeri bir şekilde işleyebilir. Sonunda her iki şekilde de öldürülecek - ama genellikle sizin karar vermeniz gerekmiyor. Açıkçası, tüm Android yaşam döngüsü yöntemleri çağrıldıktan sonra (ve sürece) uygulama sürecinizle ne olduğunu umursamamanız gerekir. Android daha iyi bilir.

Tabii ki süreci öldürmekle birlikte android.os.Process.killProcess(android.os.Process.myPid());uygun Android öğelerinin yaşam döngüsünü bozduğu ve uygun geri aramalar çağrılamayabileceği için önerilmez, bu nedenle uygulamanız bazı durumlarda yanlış davranabilir.

Umarım yardımcı olur.


0

Android'de hangi uygulamaların öldürüldüğüne karar veren işletim sistemidir.

Öncelik sırası vardır:
Ön plan hizmeti olan uygulamalar nadiren öldürülür, bunun yerine diğer uygulamalar ve hizmetler bir süre kullanılmadığında öldürülür ve uygulamanızla olan budur.

Ön plan hizmetini bitirdiğinizde, sistem uygulamanızı öldürme olasılığını arttırır, ancak hiçbir durumda derhal öldürüleceği anlamına gelmez.


0

Son İşlemler Ekranı [...] listeleri son erişilen bir sistem düzeyi UI'sında faaliyetleri ve görevleri .

Listedeki tek bir uygulamadan birden fazla etkinliğiniz veya göreviniz olabilir. Onun olmayan bir Son Uygulamalar listesi.

Dolayısıyla, unsurların arasında doğrudan bir ilişki yoktur. Son Aramalar Ekranının uygulama süreci .

Her neyse , uygulamanızın son etkinliğini kapatırsanız ve işlem içinde çalışan başka bir şey yoksa (ön plan hizmeti gibi), işlem temizlenir.

Yani ön planda koşmayı bıraktığınızda ( stopService() ya da stopSelf()bağlamayı kaldırdığınızda), sistem, çalıştığı işlemi de temizler.

Yani bu gerçekten amaçlanan bir davranış .

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.