某日,Android王国举办Kotlin主题派对。Activity穿着Jetpack Compose定制礼服,Service戴着协程手表,BroadcastReceiver拿着Flow喇叭,ContentProvider抱着Room数据库入场。它们正愁如何交流,Intent举着"邮差"牌子跳出来:"嘿伙计们,这次我用Kotlin语法糖寄快递!"
一、Activity:前台明星的优雅社交
Activity作为门面担当,现在有了新绝活——用Kotlin的简洁语法处理生命周期(再也不用写冗长的onSaveInstanceState了!)
启动Activity的三种优雅姿势:
// 1. 标准快递(带lambda的快递单)
startActivity(Intent(this, DetailActivity::class.java).apply {
putExtra("order_id", "KT2023_888")
}
// 2. 专属VIP通道(避免重复创建)
val intent = Intent(this, SingleTopActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
}
startActivity(intent)
// 3. 协程风格带回执(等待对方签收)
val resultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == RESULT_OK) {
result.data?.getStringExtra("result")?.let {
toast("收到回信:$it")
}
}
}
resultLauncher.launch(Intent(this, FeedbackActivity::class.java))
Kotlin参数传递魔法:
// 发送方使用apply作用域函数
Intent(this, OrderActivity::class.java).apply {
putExtra("order_id", "KT2023_888")
putExtra("items", parcelableItemList) // 传递Parcelable集合
putExtra("discount", 0.8f)
}.also { startActivity(it) }
// 接收方使用kotlin扩展函数
class OrderActivity : AppCompatActivity() {
private val orderId by lazy { intent.getStringExtra("order_id") ?: "" }
private val discount by lazy { intent.getFloatExtra("discount", 1.0f) }
private val items by lazy {
intent.getParcelableArrayListExtra<Item>("items") ?: arrayListOf()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 直接使用属性访问
Log.d("Order", "处理订单:$orderId 折扣:$discount")
}
}
Kotlin版Intent参数速记表
操作 | Kotlin优雅写法 |
---|---|
创建Intent | Intent(context, Target::class.java) |
添加参数 | apply { putExtra(key, value) } |
安全获取String | intent.getStringExtra(key) ?: "" |
安全获取集合 | intent.getParcelableArrayListExtra<T>(key) ?: arrayListOf() |
启动Activity | also { startActivity(it) } |
二、Service:后台协程大师
Service现在学会用协程处理后台任务:"我再也不怕ANR了!"(但要注意:Android 12+限制前台服务启动)
方式一:StartService(协程版后台任务)
// Activity发送启动命令
val serviceIntent = Intent(this, DownloadService::class.java).apply {
putExtra("url", "https://example.com/kotlin_video.mp4")
}
ContextCompat.startForegroundService(this, serviceIntent)
// Service使用协程处理
class DownloadService : Service() {
private val job = SupervisorJob()
private val scope = CoroutineScope(Dispatchers.IO + job)
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
intent?.getStringExtra("url")?.let { url ->
scope.launch {
downloadFile(url) // 协程中执行耗时操作
stopSelf()
}
}
return START_STICKY
}
private suspend fun downloadFile(url: String) {
// 协程下载逻辑
}
override fun onDestroy() {
job.cancel()
super.onDestroy()
}
}
方式二:BindService(Kotlin接口双向通话)
// Activity绑定服务
val connection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
(service as? MusicService.LocalBinder)?.getService()?.let { musicService ->
musicService.apply {
play() // 直接调用
setOnProgressListener { progress ->
updateProgress(progress)
}
}
}
}
}
bindService(Intent(this, MusicService::class.java), connection, Context.BIND_AUTO_CREATE)
// Service提供Flow接口
class MusicService : Service() {
private val _progress = MutableStateFlow(0)
val progress: StateFlow<Int> = _progress
inner class LocalBinder : Binder() {
fun getService() = this@MusicService
}
fun play() {
CoroutineScope(Dispatchers.Default).launch {
while (isPlaying) {
delay(1000)
_progress.update { it + 1 }
}
}
}
}
Kotlin版Service对比
特性 | 协程优势 |
---|---|
生命周期 | 通过CoroutineScope管理 |
线程切换 | 使用Dispatchers.IO/Main |
状态更新 | 通过StateFlow自动更新UI |
错误处理 | 协程异常处理器统一捕获 |
三、BroadcastReceiver:Flow化广播站
BroadcastReceiver扔掉大喇叭:"我现在用Flow收集广播,环保又高效!"
案例:协程监听网络变化
// 使用Flow包装广播
class NetworkStateFlow(context: Context) : Flow<Boolean> {
private val contextRef = WeakReference(context)
override suspend fun collect(collector: FlowCollector<Boolean>) {
val context = contextRef.get() ?: return
val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val isConnected = context?.let { ctx ->
(ctx.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager)
.activeNetworkInfo?.isConnected == true
} ?: false
collector.emit(isConnected)
}
}
context.registerReceiver(receiver, IntentFilter(CONNECTIVITY_ACTION))
try {
awaitCancellation() // 等待流取消
} finally {
context.unregisterReceiver(receiver)
}
}
}
// Activity中优雅收集
lifecycleScope.launch {
NetworkStateFlow(this@MainActivity).collect { isConnected ->
binding.networkStatus.text = if (isConnected) "在线" else "离线"
}
}
四、ContentProvider:Room数据库管家
ContentProvider举着Room牌咖啡:"我现在用Kotlin符号查询数据,香醇又高效!"
案例:使用Room进行组件通讯
// 定义数据库
@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
// DAO接口使用Kotlin协程
@Dao
interface UserDao {
@Insert
suspend fun insert(user: User)
@Query("SELECT * FROM user")
fun getAll(): Flow<List<User>>
}
// Activity中观察数据变化
class UserActivity : AppCompatActivity() {
private val db by lazy {
Room.databaseBuilder(applicationContext, AppDatabase::class.java, "user.db").build()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleScope.launch {
db.userDao().getAll().collect { users ->
// 自动更新UI
binding.userList.adapter = UserAdapter(users)
}
}
// Service更新数据
Intent(this, SyncService::class.java).also {
startService(it)
}
}
}
// Service更新数据
class SyncService : Service() {
private val db by lazy {
Room.databaseBuilder(applicationContext, AppDatabase::class.java, "user.db").build()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
CoroutineScope(Dispatchers.IO).launch {
val newUser = User(name = "Kotlin开发者")
db.userDao().insert(newUser)
}
return START_NOT_STICKY
}
}
组件协作实战:新闻阅读App
// 场景:Activity启动Service获取新闻,Service保存到数据库,广播通知更新,ContentProvider提供数据
// 1. Activity启动服务
val serviceIntent = Intent(this, NewsService::class.java).apply {
putExtra("category", "technology")
}
ContextCompat.startForegroundService(this, serviceIntent)
// 2. Service获取数据并保存
class NewsService : Service() {
private val db by lazy { NewsDatabase.get(applicationContext) }
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val category = intent?.getStringExtra("category") ?: "general"
CoroutineScope(Dispatchers.IO).launch {
val news = NewsApi.fetch(category) // 网络请求
db.newsDao().insertAll(news)
// 发送粘性广播通知更新
sendBroadcast(Intent("NEWS_UPDATED").apply {
putExtra("count", news.size)
})
}
return START_STICKY
}
}
// 3. Activity接收广播更新UI
private val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent?.action == "NEWS_UPDATED") {
val count = intent.getIntExtra("count", 0)
binding.newsCount.text = "更新了${count}条新闻"
// 从ContentProvider加载数据
lifecycleScope.launch {
db.newsDao().getLatest().collect { news ->
binding.newsList.adapter = NewsAdapter(news)
}
}
}
}
}
override fun onStart() {
super.onStart()
registerReceiver(receiver, IntentFilter("NEWS_UPDATED"))
}
组件通讯黄金法则:Kotlin版
Intent快递法则:用
apply{}
打包数据,用let{}
安全拆包协程管理法则:Service用
CoroutineScope
管理任务,Activity用lifecycleScope
收集数据Flow更新法则:用
StateFlow
替代回调,用collect
自动更新UIRoom数据库法则:DAO返回Flow,实现跨组件实时同步
广播进化法则:用Flow包装传统广播,实现响应式接收