跳转至

第14章 Android系统服务深度解析

Android系统服务深度解析图

学习目标:深入理解Android系统服务机制,掌握Service、BroadcastReceiver、ContentProvider等核心组件。

预计学习时间:5-7天 实践时间:2-3天


目录

  1. Service服务
  2. BroadcastReceiver广播
  3. ContentProvider内容提供器
  4. WorkManager后台任务
  5. Notification通知
  6. 实践练习

1. Service服务

1.1 Service类型

Kotlin
// 前台Service(用户可见,优先级高)
class MusicPlayerService : Service() {
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        val notification = createNotification()
        startForeground(1, notification)
        return START_STICKY
    }

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

// 后台Service(限制较多,Android 8+)
class DataSyncService : Service() {
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        // 执行同步任务
        return START_NOT_STICKY
    }

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

// 绑定Service(组件间通信)
class CalculatorService : Service() {
    private val binder = LocalBinder()

    inner class LocalBinder : Binder() {
        fun getService(): CalculatorService = this@CalculatorService
    }

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

    fun add(a: Int, b: Int): Int = a + b
}

1.2 Service生命周期

Text Only
启动Service:        绑定Service:
  onCreate()           onCreate()
     ↓                    ↓
  onStartCommand()    onBind() → 返回IBinder
     ↓                    ↓
  运行中              客户端通过IBinder通信
     ↓                    ↓
  onDestroy()         onUnbind() → onDestroy()

2. BroadcastReceiver广播

2.1 广播类型

Kotlin
// 标准广播(异步,同时接收)
// 有序广播(同步,按优先级接收)
// 粘性广播(已废弃)

// 定义Receiver
class NetworkChangeReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        when (intent.action) {
            ConnectivityManager.CONNECTIVITY_ACTION -> {
                val isConnected = checkNetworkState(context)
                // 处理网络变化
            }
        }
    }
}

// 动态注册
val receiver = NetworkChangeReceiver()
val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
registerReceiver(receiver, filter)

// 静态注册(AndroidManifest.xml)
<receiver android:name=".NetworkChangeReceiver">
    <intent-filter>
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
    </intent-filter>
</receiver>

2.2 本地广播(更安全)

注意LocalBroadcastManager 已在 AndroidX 1.1.0 中被废弃。官方推荐使用 SharedFlowLiveData 或其他可观察数据模式替代应用内广播通信。以下代码仅供了解历史用法。

Kotlin
val localBroadcastManager = LocalBroadcastManager.getInstance(this)

// 发送广播
val intent = Intent("custom-event")
localBroadcastManager.sendBroadcast(intent)

// 接收广播
val receiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        // 处理广播
    }
}
localBroadcastManager.registerReceiver(receiver, IntentFilter("custom-event"))

3. ContentProvider内容提供器

3.1 自定义ContentProvider

Kotlin
class NoteProvider : ContentProvider() {
    companion object {
        const val AUTHORITY = "com.example.provider"
        val NOTE_URI: Uri = Uri.parse("content://$AUTHORITY/notes")

        const val NOTES = 1
        const val NOTE_ID = 2

        val uriMatcher = UriMatcher(UriMatcher.NO_MATCH).apply {
            addURI(AUTHORITY, "notes", NOTES)
            addURI(AUTHORITY, "notes/#", NOTE_ID)
        }
    }

    private lateinit var db: SQLiteDatabase

    override fun onCreate(): Boolean {
        val helper = NoteDbHelper(context!!)
        db = helper.writableDatabase
        return true
    }

    override fun query(
        uri: Uri,
        projection: Array<String>?,
        selection: String?,
        selectionArgs: Array<String>?,
        sortOrder: String?
    ): Cursor? {
        return when (uriMatcher.match(uri)) {
            NOTES -> db.query("notes", projection, selection, selectionArgs, null, null, sortOrder)
            NOTE_ID -> {
                val id = ContentUris.parseId(uri)
                db.query("notes", projection, "id=?", arrayOf(id.toString()), null, null, sortOrder)
            }
            else -> throw IllegalArgumentException("Unknown URI: $uri")
        }
    }

    override fun insert(uri: Uri, values: ContentValues?): Uri? {
        val id = db.insert("notes", null, values)
        return ContentUris.withAppendedId(NOTE_URI, id)
    }

    override fun getType(uri: Uri): String? = null
    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int = 0
    override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array<String>?): Int = 0
}

3.2 使用ContentProvider

Kotlin
// 查询数据
val cursor = contentResolver.query(
    NoteProvider.NOTE_URI,
    arrayOf("id", "title", "content"),
    null, null, null
)

cursor?.use {
    while (it.moveToNext()) {
        val id = it.getLong(it.getColumnIndexOrThrow("id"))
        val title = it.getString(it.getColumnIndexOrThrow("title"))
        // 处理数据
    }
}

// 插入数据
val values = ContentValues().apply {
    put("title", "New Note")
    put("content", "Note content")
}
val uri = contentResolver.insert(NoteProvider.NOTE_URI, values)

4. WorkManager后台任务

4.1 定义Worker

Kotlin
// 简单任务
class UploadWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
    override fun doWork(): Result {
        val imageUri = inputData.getString("IMAGE_URI")

        return try {  // try/catch捕获异常
            uploadImage(imageUri)
            Result.success()
        } catch (e: Exception) {
            Result.failure()
        }
    }
}

// 协程任务
class CoroutineUploadWorker(
    context: Context,
    params: WorkerParameters
) : CoroutineWorker(context, params) {
    override suspend fun doWork(): Result {
        return try {
            uploadData()
            Result.success()
        } catch (e: Exception) {
            Result.retry()
        }
    }
}

4.2 调度任务

Kotlin
// 一次性任务
val uploadWorkRequest = OneTimeWorkRequestBuilder<UploadWorker>()
    .setInputData(workDataOf("IMAGE_URI" to imageUri))
    .setConstraints(
        Constraints.Builder()
            .setRequiredNetworkType(NetworkType.CONNECTED)
            .setRequiresBatteryNotLow(true)
            .build()
    )
    .build()

WorkManager.getInstance(context).enqueue(uploadWorkRequest)

// 周期性任务
val periodicWorkRequest = PeriodicWorkRequestBuilder<SyncWorker>(15, TimeUnit.MINUTES)
    .build()

WorkManager.getInstance(context).enqueueUniquePeriodicWork(
    "sync_work",
    ExistingPeriodicWorkPolicy.KEEP,
    periodicWorkRequest
)

// 链式任务
val workA = OneTimeWorkRequestBuilder<WorkerA>().build()
val workB = OneTimeWorkRequestBuilder<WorkerB>().build()
val workC = OneTimeWorkRequestBuilder<WorkerC>().build()

WorkManager.getInstance(context)
    .beginWith(workA)
    .then(workB)
    .then(workC)
    .enqueue()

5. Notification通知

5.1 创建通知

Kotlin
// 创建通知渠道(Android 8+)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    val channel = NotificationChannel(
        "channel_id",
        "Channel Name",
        NotificationManager.IMPORTANCE_DEFAULT
    ).apply {
        description = "Channel description"
    }

    val notificationManager = getSystemService(NotificationManager::class.java)
    notificationManager.createNotificationChannel(channel)
}

// 构建通知
val notification = NotificationCompat.Builder(this, "channel_id")
    .setSmallIcon(R.drawable.notification_icon)
    .setContentTitle("Title")
    .setContentText("Content")
    .setPriority(NotificationCompat.PRIORITY_DEFAULT)
    .setAutoCancel(true)
    .setContentIntent(pendingIntent)
    .addAction(R.drawable.ic_reply, "Reply", replyPendingIntent)
    .build()

// 显示通知
NotificationManagerCompat.from(this).notify(notificationId, notification)

5.2 富媒体通知

Kotlin
// 大文本通知
val bigTextStyle = NotificationCompat.BigTextStyle()
    .bigText("Long text content...")
    .setBigContentTitle("Big Title")

// 图片通知
val bigPictureStyle = NotificationCompat.BigPictureStyle()
    .bigPicture(bitmap)
    .setBigContentTitle("Picture Title")

// 消息通知
val messagingStyle = NotificationCompat.MessagingStyle("Me")
    .addMessage("Hello", System.currentTimeMillis(), "Sender")

6. 实践练习

练习1:音乐播放器Service

任务:实现后台音乐播放Service

要求: - 前台Service显示播放控制 - 支持播放/暂停/下一首 - 通知栏控制

练习2:数据同步WorkManager

任务:实现定期数据同步

要求: - 每6小时同步一次 - 仅在WiFi下执行 - 失败自动重试


本章小结

核心要点

  1. Service用于后台任务,前台Service优先级更高
  2. BroadcastReceiver用于监听系统/应用事件
  3. ContentProvider用于跨应用数据共享
  4. WorkManager是推荐的后台任务调度方案
  5. Notification是与用户交互的重要手段

下一步

完成本章学习后,请进入第15章:自定义View与高级绘制


本章完成时间:预计5-7天