第14章 Android系统服务深度解析¶
学习目标:深入理解Android系统服务机制,掌握Service、BroadcastReceiver、ContentProvider等核心组件。
预计学习时间:5-7天 实践时间:2-3天
目录¶
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 中被废弃。官方推荐使用SharedFlow、LiveData或其他可观察数据模式替代应用内广播通信。以下代码仅供了解历史用法。
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下执行 - 失败自动重试
本章小结¶
核心要点¶
- Service用于后台任务,前台Service优先级更高
- BroadcastReceiver用于监听系统/应用事件
- ContentProvider用于跨应用数据共享
- WorkManager是推荐的后台任务调度方案
- Notification是与用户交互的重要手段
下一步¶
完成本章学习后,请进入第15章:自定义View与高级绘制。
本章完成时间:预计5-7天