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
- Uygulamanızı 'Son uygulamalar'dan kaydırdığınızda, işletim sistemi uygulama sürecini nispeten yakın bir gelecekte bitirmelidir.
- Bir ön plan hizmeti çalıştırırken uygulamanızı 'Son uygulamalar'dan kaydırdığınızda uygulama canlı kalır.
- 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:
- Uygulamayı başlatın, ön plan hizmetini durdurun, 'Son uygulamalar'dan uygulamayı kaldırın
- 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ı?
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