Skip to content

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 → onResume

add 第二个 Fragment(不移除第一个)

kotlin
supportFragmentManager.commit {
    add(R.id.container, FragmentB())
}
// FragmentA: 无变化(仍然 RESUMED,只是被遮挡)
// FragmentB: onAttach → onCreate → onCreateView → onViewCreated → onStart → onResume

replace

kotlin
supportFragmentManager.commit {
    replace(R.id.container, FragmentB())
}
// FragmentA: onPause → onStop → onDestroyView → onDestroy → onDetach(完全销毁)
// FragmentB: onAttach → onCreate → onCreateView → onViewCreated → onStart → onResume

replace + 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()
    }
}