Saya menemukan perilaku dalam manajemen proses Android dalam hubungannya dengan layanan latar depan, yang benar-benar membingungkan saya.
Apa yang masuk akal bagi saya
- Saat Anda menggesek aplikasi dari 'Aplikasi terbaru', OS akan menyelesaikan proses aplikasi dalam waktu yang relatif dekat.
- Saat Anda menggesek aplikasi dari 'Aplikasi terbaru' saat menjalankan layanan latar depan, aplikasi tetap hidup.
- Ketika Anda menghentikan layanan latar depan sebelum menggesek aplikasi Anda dari 'Aplikasi terbaru' Anda mendapatkan yang sama dengan untuk 1).
Yang membingungkan saya
Ketika Anda menghentikan layanan latar depan sementara tidak memiliki aktivitas di latar depan (aplikasi TIDAK muncul di 'Aplikasi terbaru'), saya berharap aplikasi tersebut terbunuh sekarang.
Namun, ini tidak terjadi, proses aplikasi masih hidup.
Contoh
Saya telah membuat contoh minimal yang menunjukkan perilaku ini.
Layanan Foreground:
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)
}
}
BroadcastReceiver untuk menghentikan layanan:
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)
}
}
Kegiatan:
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))
}
}
Manifes:
<?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>
Cobalah beberapa cara berikut:
- Mulai aplikasi, hentikan layanan latar depan, hapus aplikasi dari 'Aplikasi terbaru'
- Mulai aplikasi, hapus aplikasi dari 'Aplikasi terbaru', hentikan layanan latar depan
Anda dapat melihat di LogCat Android Studio bahwa proses aplikasi ditandai [MATI] untuk kasus 1 tetapi tidak untuk kasus 2.
Karena cukup mudah untuk mereproduksi, itu mungkin merupakan perilaku yang dimaksudkan, tetapi saya tidak menemukan penyebutan yang sebenarnya dalam dokumen ini.
Adakah yang tahu apa yang sedang terjadi di sini?
onDestroy
(Layanan) dipanggil, namun prosesnya tetap hidup lama setelah semuanya hilang. Bahkan jika OS menjaga proses tetap hidup jika layanan akan di-restart, saya tidak melihat mengapa itu tidak melakukan hal yang sama ketika Anda menghentikan layanan terlebih dahulu, kemudian hapus aplikasi dari baru-baru ini. Perilaku yang ditampilkan tampaknya agak tidak intuitif, terutama mengingat perubahan terbaru pada batas eksekusi latar belakang, jadi alangkah baiknya mengetahui cara memastikan bahwa proses dihentikan