포 그라운드 서비스와 관련하여 Android 프로세스 관리의 동작을 발견했습니다.
나에게 합리적인 것
- '최근 앱'에서 앱을 스 와이프하면 OS는 가까운 시일 내에 앱 프로세스를 완료해야합니다.
- 포 그라운드 서비스를 실행하는 동안 '최근 앱'에서 앱을 스 와이프하면 앱이 계속 활성화됩니다.
- '최근 앱'에서 앱을 스 와이프하기 전에 포 그라운드 서비스를 중지하면 1)과 동일합니다.
나를 혼란스럽게하는 것
포 그라운드에서 활동이없는 상태에서 포 그라운드 서비스를 중지하면 (앱이 '최근 앱'에 표시되지 않음) 앱이 이제 종료 될 것으로 예상합니다.
그러나 이것은 일어나지 않고 앱 프로세스는 여전히 살아 있습니다.
예
이 동작을 보여주는 최소한의 예를 만들었습니다.
ForegroundService :
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 :
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)
}
}
활동:
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))
}
}
매니페스트 :
<?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>
다음과 같은 방법으로 시도하십시오.
- 앱 시작, 포 그라운드 서비스 중지, '최근 앱'에서 앱 제거
- 앱 시작, '최근 앱'에서 앱 제거, 포 그라운드 서비스 중지
Android Studio의 LogCat에서 사례 1에 대해서는 앱 프로세스가 [DEAD]로 표시되어 있지만 사례 2에는 표시되지 않았 음을 알 수 있습니다.
재현하기가 쉽기 때문에 의도 된 동작 일 수는 있지만 문서에서 실제로 언급 한 내용을 찾지 못했습니다.
아무도 여기서 무슨 일이 일어나고 있는지 알고 있습니까?
onDestroy
(서비스)가 호출되지만 모든 것이 사라진 후에도 프로세스는 계속 살아 있습니다. 서비스가 다시 시작될 때를 대비하여 OS가 프로세스를 활성 상태로 유지하더라도 서비스를 먼저 중지했을 때 왜 똑같은 일을하지 않는지 모르겠다가 최근 앱을 제거하십시오. 표시되는 동작은 특히 백그라운드 실행 제한에 대한 최근 변경 사항을 고려할 때 직관적이지 않은 것처럼