Fragment 与 Service 深入详解
更新: 5/15/2026 字数: 0 字 时长: 0 分钟
1. Fragment 生命周期详解
1.1 Fragment 与 Activity 生命周期同步
Activity.onCreate()
→ Fragment.onAttach()
→ Fragment.onCreate()
→ Fragment.onCreateView()
→ Fragment.onViewCreated()
→ Fragment.onActivityCreated() // 已废弃,用 onViewCreated 替代
→ Fragment.onStart()
Activity.onStart()
→ Fragment.onStart()
Activity.onResume()
→ Fragment.onResume()
Activity.onPause()
→ Fragment.onPause()
Activity.onStop()
→ Fragment.onStop()
Activity.onDestroy()
→ Fragment.onDestroyView()
→ Fragment.onDestroy()
→ Fragment.onDetach()1.2 Fragment 的两个生命周期
Fragment 有两个独立的生命周期:
Fragment 自身生命周期:onAttach → onCreate → ... → onDestroy → onDetach
Fragment View 生命周期:onCreateView → onViewCreated → ... → onDestroyView为什么要区分?因为 Fragment 可以在 View 销毁后仍然存活(如加入 back stack):
kotlin
// replace + addToBackStack
supportFragmentManager.commit {
replace(R.id.container, FragmentB())
addToBackStack(null)
}
// FragmentA 的生命周期:
// onPause → onStop → onDestroyView ← View 销毁了
// 但 Fragment 实例还在 back stack 中,onCreate/onDestroy 没有调用
// 用户按返回键,FragmentA 恢复:
// onCreateView → onViewCreated → onStart → onResume ← 重新创建 View这就是为什么在 Fragment 中观察 LiveData 要用 viewLifecycleOwner 而不是 this:
kotlin
// ❌ 使用 Fragment 生命周期:Fragment 在 back stack 中时 Observer 仍然活跃
// 恢复后又注册新的 Observer,导致重复观察
viewModel.data.observe(this) { ... }
// ✅ 使用 View 生命周期:View 销毁时 Observer 自动移除
viewModel.data.observe(viewLifecycleOwner) { ... }1.3 add/replace/hide/show 对生命周期的影响
add:
kotlin
supportFragmentManager.commit {
add(R.id.container, FragmentA())
}
// FragmentA: onAttach → onCreate → onCreateView → onViewCreated → onStart → onResumeadd 第二个 Fragment(不移除第一个):
kotlin
supportFragmentManager.commit {
add(R.id.container, FragmentB())
}
// FragmentA: 无变化(仍然 RESUMED,只是被遮挡)
// FragmentB: onAttach → onCreate → onCreateView → onViewCreated → onStart → onResumereplace:
kotlin
supportFragmentManager.commit {
replace(R.id.container, FragmentB())
}
// FragmentA: onPause → onStop → onDestroyView → onDestroy → onDetach(完全销毁)
// FragmentB: onAttach → onCreate → onCreateView → onViewCreated → onStart → onResumereplace + addToBackStack:
kotlin
supportFragmentManager.commit {
replace(R.id.container, FragmentB())
addToBackStack(null)
}
// FragmentA: onPause → onStop → onDestroyView(View 销毁,Fragment 保留)
// FragmentB: onAttach → onCreate → onCreateView → onViewCreated → onStart → onResume
// 按返回键:
// FragmentB: onPause → onStop → onDestroyView → onDestroy → onDetach
// FragmentA: onCreateView → onViewCreated → onStart → onResume(重建 View)hide/show:
kotlin
supportFragmentManager.commit {
hide(fragmentA)
show(fragmentB)
}
// 不触发任何生命周期回调!
// 只是改变 View 的 visibility
// 可以通过 onHiddenChanged(hidden: Boolean) 监听1.4 Fragment 通信
kotlin
// 方案1:Fragment Result API(Jetpack 推荐)
// 发送方
parentFragmentManager.setFragmentResult("requestKey", bundleOf("data" to "value"))
// 接收方
parentFragmentManager.setFragmentResultListener("requestKey", viewLifecycleOwner) { _, bundle ->
val data = bundle.getString("data")
}
// 方案2:共享 ViewModel
// 两个 Fragment 共享 Activity 级别的 ViewModel
class SharedViewModel : ViewModel() {
val selectedItem = MutableLiveData<Item>()
}
// FragmentA
class FragmentA : Fragment() {
private val sharedViewModel: SharedViewModel by activityViewModels()
fun onItemSelected(item: Item) {
sharedViewModel.selectedItem.value = item
}
}
// FragmentB
class FragmentB : Fragment() {
private val sharedViewModel: SharedViewModel by activityViewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
sharedViewModel.selectedItem.observe(viewLifecycleOwner) { item ->
displayItem(item)
}
}
}1.5 Fragment 常见坑
kotlin
// 坑1:getActivity() 返回 null
// Fragment detach 后 getActivity() 返回 null
// 解决:在使用前判空,或使用 requireActivity()
// 坑2:重叠问题
// 配置变更时 Activity 重建,FragmentManager 自动恢复 Fragment
// 如果在 onCreate 中无条件 add Fragment,会导致重叠
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState == null) { // ← 只在首次创建时添加
supportFragmentManager.commit {
add(R.id.container, MyFragment())
}
}
}
// 坑3:commit 时机
// onSaveInstanceState 之后不能 commit(会丢失状态)
// 解决:使用 commitAllowingStateLoss()(接受可能丢失状态)
// 或确保在 onResume 之前 commit
// 坑4:嵌套 Fragment 使用 childFragmentManager
// 子 Fragment 应该用 childFragmentManager,不是 parentFragmentManager
childFragmentManager.commit {
add(R.id.child_container, ChildFragment())
}2. Service 深入
2.1 两种启动方式的生命周期
startService:
startService()
→ onCreate()(首次创建)
→ onStartCommand()(每次 startService 都调用)
→ 服务运行中...
→ stopSelf() 或 stopService()
→ onDestroy()bindService:
bindService()
→ onCreate()(首次创建)
→ onBind()(返回 IBinder)
→ 客户端通过 IBinder 调用服务方法
→ unbindService()(所有客户端都解绑后)
→ onUnbind()
→ onDestroy()混合使用:
startService() → onCreate → onStartCommand
bindService() → onBind
unbindService() → onUnbind
// 此时服务不会销毁,因为还有 startService 保活
stopService() → onDestroy
// 必须同时 stop + 所有 client unbind 才会销毁2.2 onStartCommand 返回值
kotlin
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return START_STICKY
}
// START_NOT_STICKY:被杀后不重建。适合可以重新触发的任务
// START_STICKY:被杀后重建,但 intent 为 null。适合音乐播放器等
// START_REDELIVER_INTENT:被杀后重建,重新传递最后一个 intent。适合必须完成的任务2.3 前台 Service
Android 8.0+ 后台 Service 限制严格,长时间运行的服务必须前台化:
kotlin
class MusicService : Service() {
override fun onCreate() {
super.onCreate()
// 创建通知渠道(Android 8.0+)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
"music_channel",
"音乐播放",
NotificationManager.IMPORTANCE_LOW
)
getSystemService(NotificationManager::class.java).createNotificationChannel(channel)
}
// 构建通知
val notification = NotificationCompat.Builder(this, "music_channel")
.setContentTitle("正在播放")
.setContentText("歌曲名称")
.setSmallIcon(R.drawable.ic_music)
.build()
// 前台化(必须在 onCreate 后 5 秒内调用)
startForeground(1, notification)
}
override fun onBind(intent: Intent?): IBinder? = null
}
// 启动前台 Service
// Android 8.0+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(Intent(this, MusicService::class.java))
} else {
startService(Intent(this, MusicService::class.java))
}
// Android 12+ 需要在 Manifest 声明前台服务类型
// <service android:name=".MusicService"
// android:foregroundServiceType="mediaPlayback" />2.4 IntentService → WorkManager
kotlin
// IntentService(已废弃)
// 内部使用 HandlerThread,串行处理每个 Intent
class MyIntentService : IntentService("MyIntentService") {
override fun onHandleIntent(intent: Intent?) {
// 在子线程中执行
// 所有 Intent 处理完后自动 stopSelf
}
}
// 替代方案:WorkManager
class MyWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
// 在后台执行
return Result.success()
}
}
// 一次性任务
val request = OneTimeWorkRequestBuilder<MyWorker>()
.setConstraints(Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build())
.build()
WorkManager.getInstance(context).enqueue(request)
// 周期任务(最小 15 分钟)
val periodicRequest = PeriodicWorkRequestBuilder<MyWorker>(15, TimeUnit.MINUTES)
.build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
"sync_work",
ExistingPeriodicWorkPolicy.KEEP,
periodicRequest
)2.5 Bound Service 与 AIDL
kotlin
// 同进程绑定(Binder 直接调用)
class LocalService : Service() {
inner class LocalBinder : Binder() {
fun getService(): LocalService = this@LocalService
}
private val binder = LocalBinder()
override fun onBind(intent: Intent): IBinder = binder
fun doSomething(): String = "result"
}
// 客户端
class MyActivity : AppCompatActivity() {
private var service: LocalService? = null
private val connection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, binder: IBinder) {
service = (binder as LocalService.LocalBinder).getService()
service?.doSomething()
}
override fun onServiceDisconnected(name: ComponentName) {
service = null
}
}
override fun onStart() {
super.onStart()
bindService(Intent(this, LocalService::class.java), connection, BIND_AUTO_CREATE)
}
override fun onStop() {
super.onStop()
unbindService(connection)
}
}kotlin
// 跨进程绑定(AIDL)
// IRemoteService.aidl
interface IRemoteService {
int calculate(int a, int b);
void registerCallback(ICallback callback);
}
// Server 端
class RemoteService : Service() {
// 使用 RemoteCallbackList 管理跨进程回调(自动处理死亡通知)
private val callbacks = RemoteCallbackList<ICallback>()
private val binder = object : IRemoteService.Stub() {
override fun calculate(a: Int, b: Int): Int {
return a + b // 在 Binder 线程池中执行,注意线程安全
}
override fun registerCallback(callback: ICallback) {
callbacks.register(callback)
}
}
override fun onBind(intent: Intent): IBinder = binder
// 通知所有客户端
private fun notifyClients(result: String) {
val count = callbacks.beginBroadcast()
for (i in 0 until count) {
try {
callbacks.getBroadcastItem(i).onResult(result)
} catch (e: RemoteException) {
// 客户端进程已死
}
}
callbacks.finishBroadcast()
}
}