Tôi đã bắt gặp một hành vi trong quản lý quy trình của Android kết hợp với các dịch vụ tiền cảnh, điều đó thực sự làm tôi bối rối.
Điều gì hợp lý với tôi
- Khi bạn vuốt ứng dụng của mình từ 'Ứng dụng gần đây', HĐH sẽ hoàn tất quy trình ứng dụng trong tương lai gần.
- Khi bạn vuốt ứng dụng của mình từ 'Ứng dụng gần đây' trong khi chạy dịch vụ nền trước, ứng dụng sẽ tồn tại.
- Khi bạn dừng dịch vụ tiền cảnh trước khi vuốt ứng dụng của bạn từ 'Ứng dụng gần đây', bạn sẽ nhận được tương tự như đối với 1).
Điều gì làm tôi bối rối
Khi bạn dừng dịch vụ nền trước trong khi không có hoạt động nào ở nền trước (ứng dụng KHÔNG xuất hiện trong 'Ứng dụng gần đây'), tôi sẽ hy vọng ứng dụng sẽ bị giết ngay bây giờ.
Tuy nhiên, điều này không xảy ra, quá trình ứng dụng vẫn còn sống.
Thí dụ
Tôi đã tạo ra một ví dụ tối thiểu cho thấy hành vi này.
Dịch vụ tiền cảnh:
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 dừng dịch vụ:
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)
}
}
Hoạt động:
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))
}
}
Tệp kê khai:
<?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>
Hãy thử các cách sau:
- Bắt đầu ứng dụng, dừng dịch vụ tiền cảnh, xóa ứng dụng khỏi 'Ứng dụng gần đây'
- Bắt đầu ứng dụng, xóa ứng dụng khỏi 'Ứng dụng gần đây', dừng dịch vụ tiền cảnh
Bạn có thể thấy trong LogCat của Android Studio rằng quy trình ứng dụng được đánh dấu [DEAD] cho trường hợp 1 nhưng không phải cho trường hợp 2.
Vì nó khá dễ tái tạo nên nó có thể là một hành vi có chủ đích, nhưng tôi không tìm thấy bất kỳ đề cập thực sự nào về điều này trong các tài liệu.
Có ai biết những gì đang xảy ra ở đây?
onDestroy
(Dịch vụ) được gọi, nhưng quá trình này vẫn tồn tại lâu sau khi mọi thứ biến mất. Ngay cả khi HĐH giữ cho quá trình tồn tại trong trường hợp dịch vụ được khởi động lại, tôi không hiểu tại sao nó không làm điều tương tự khi bạn dừng dịch vụ trước, sau đó xóa ứng dụng khỏi khoảng cách. Hành vi được hiển thị có vẻ không trực quan, đặc biệt là đã có những thay đổi gần đây đối với giới hạn thực hiện nền, vì vậy thật tuyệt khi biết cách đảm bảo quá trình được dừng lại