Mediamtx HLS 优化指南:3 步解决移动端首帧慢、卡顿、延迟高
2026/9/8 18:15:21
本文整理 Android 开发中常见技术点对应的设计模式,并给出简化伪代码、典型源码/原理使用位置。伪代码用于理解模式结构,不等同于源码实现。
| 设计模式 | Android 常见技术点 | 典型使用位置 |
|---|---|---|
| 单例模式 | 全局管理器、系统服务、数据库实例 | WorkManager.getInstance()、Room.databaseBuilder()后的数据库单例、SystemServiceRegistry |
| Builder 模式 | 复杂对象构建 | AlertDialog.Builder、NotificationCompat.Builder、Room.databaseBuilder() |
| 工厂模式 | 对象创建解耦 | LayoutInflater.Factory2、FragmentFactory、ViewModelProvider.Factory |
| 观察者模式 | 数据变化通知、生命周期感知 | LiveData.observe()、LifecycleObserver、Flow.collect |
| 适配器模式 | 数据和 UI 解耦 | RecyclerView.Adapter、ListAdapter、CursorAdapter |
| 代理模式 | IPC、远程服务、本地接口代理 | Binder 的Stub/Proxy、AIDL |
| 装饰器模式 | 包装并增强能力 | ContextWrapper、ContextThemeWrapper、InputStream包装链 |
| 外观模式 | 简化复杂子系统访问 | Context、CameraX、Glide.with() |
| 模板方法模式 | 固定流程中暴露可重写步骤 | Activity生命周期、View.draw()、ViewGroup.dispatchDraw() |
| 策略模式 | 可替换算法或行为 | RecyclerView.LayoutManager、ItemAnimator、DiffUtil.ItemCallback |
| 责任链模式 | 事件分发、拦截链 | 触摸事件分发、OkHttp Interceptor |
| 状态模式 | 对象行为随状态变化 | Lifecycle.State、播放器状态、登录状态 |
| 命令模式 | 把操作封装为对象 | Runnable+Handler、PendingIntent、点击事件回调 |
| MVC / MVP / MVVM | 应用架构分层 | Activity/Fragment、ViewModel、LiveData/StateFlow、Repository |
WorkManager.getInstance(context)RoomDatabase通常在应用层做单例封装SystemServiceRegistry管理系统服务实例Application全局生命周期入口classAppDatabaseprivateconstructor(){companionobject{@Volatileprivatevarinstance:AppDatabase?=nullfungetInstance():AppDatabase{returninstance?:synchronized(this){instance?:AppDatabase().also{instance=it}}}}}Context.getSystemService()背后会从系统服务注册表中按名称获取服务。WorkManager通过getInstance()对外提供统一入口,内部保证调度组件可被全局访问。build()或create()生成目标对象。AlertDialog.BuilderNotificationCompat.BuilderRoom.databaseBuilder(context, AppDatabase::class.java, "db").build()WorkRequest.BuilderclassDialogprivateconstructor(valtitle:String?,valmessage:String?,valcancelable:Boolean){classBuilder{privatevartitle:String?=nullprivatevarmessage:String?=nullprivatevarcancelable:Boolean=truefunsetTitle(value:String)=apply{title=value}funsetMessage(value:String)=apply{message=value}funsetCancelable(value:Boolean)=apply{cancelable=value}funbuild():Dialog{returnDialog(title,message,cancelable)}}}AlertDialog.Builder先收集标题、按钮、布局等配置,最后调用create()构建AlertDialog。NotificationCompat.Builder把通知图标、标题、内容、渠道等复杂参数集中封装,降低构造复杂度。LayoutInflater.Factory2创建 ViewFragmentFactory创建 FragmentViewModelProvider.Factory创建 ViewModelServiceLoader或依赖注入框架中的对象创建interfaceViewModelFactory{fun<T:ViewModel>create(modelClass:Class<T>):T}classUserViewModelFactory(privatevalrepository:UserRepository):ViewModelFactory{overridefun<T:ViewModel>create(modelClass:Class<T>):T{if(modelClass==UserViewModel::class.java){returnUserViewModel(repository)asT}error("Unknown ViewModel")}}ViewModelProvider不知道业务ViewModel如何构造,于是通过Factory把创建过程交给调用方。LayoutInflater解析 XML 时,需要把标签名转换成具体View对象,这就是典型的创建型模式场景。FragmentFactory允许 Fragment 使用带参数构造或依赖注入方式创建,避免框架只能调用空构造。LiveData.observe(owner, observer)Lifecycle.addObserver(observer)StateFlow/SharedFlowTextWatcher、BroadcastReceiverclassObservableData<T>{privatevalobservers=mutableListOf<(T)->Unit>()privatevarvalue:T?=nullfunobserve(observer:(T)->Unit){observers+=observer value?.let(observer)}funsetValue(newValue:T){value=newValue observers.forEach{it(newValue)}}}LiveData保存观察者列表,数据变化后分发给活跃生命周期状态下的观察者。LifecycleRegistry内部维护观察者,并在Activity/Fragment生命周期变化时派发生命周期事件。BroadcastReceiver可以理解为系统级发布订阅机制,发送广播后匹配的接收者会收到通知。RecyclerView.AdapterListAdapterCursorAdapterPagerAdapterclassUserAdapter(privatevalusers:List<User>):RecyclerView.Adapter<UserViewHolder>(){overridefungetItemCount():Int{returnusers.size}overridefunonCreateViewHolder(parent:ViewGroup,viewType:Int):UserViewHolder{returnUserViewHolder(parent.inflate("item_user"))}overridefunonBindViewHolder(holder:UserViewHolder,position:Int){holder.bind(users[position])}}RecyclerView不关心数据来源,只依赖Adapter提供数量、创建 ViewHolder、绑定数据。CursorAdapter把数据库查询结果Cursor适配成列表项视图。ListAdapter在适配器基础上加入DiffUtil,让列表更新更高效。Stub和ProxyActivityManager、PackageManagerinterfaceIUserService{fungetUserName(id:Long):String}classUserServiceProxy(privatevalremoteBinder:Binder):IUserService{overridefungetUserName(id:Long):String{valdata=Parcel.obtain()valreply=Parcel.obtain()data.writeLong(id)remoteBinder.transact(CODE_GET_USER,data,reply,0)returnreply.readString()}}Stub和Proxy:本地进程调用接口方法,实际由Proxy封装参数并通过 Binder 发送到远端。Proxy屏蔽了进程边界,让跨进程调用看起来像普通方法调用。ContextWrapperContextThemeWrapperBufferedInputStream(InputStream)Context和View的包装增强openclassBaseContext{openfungetThemeName():String="Default"}openclassContextWrapper(privatevalbase:BaseContext):BaseContext(){overridefungetThemeName():String{returnbase.getThemeName()}}classThemeContextWrapper(base:BaseContext,privatevaltheme:String):ContextWrapper(base){overridefungetThemeName():String{returntheme}}ContextWrapper内部持有一个base Context,默认把大部分调用委托给它。ContextThemeWrapper在原有Context基础上叠加主题能力。Activity本身也继承自ContextThemeWrapper,因此具备上下文和主题相关能力。Context封装资源、文件、服务、启动组件等能力Glide.with(context).load(url).into(imageView)CameraX相比 Camera2 提供更简单的相机 APINavController封装 Fragment 事务和回退栈classImageLoaderFacade(privatevalcache:ImageCache,privatevalnetwork:ImageNetwork,privatevaldecoder:ImageDecoder){funload(url:String,imageView:ImageView){valbytes=cache.get(url)?:network.download(url)valbitmap=decoder.decode(bytes)imageView.setImageBitmap(bitmap)}}Context是 Android 应用访问系统能力的重要外观,调用方无需知道资源管理器、包管理器、服务管理器的内部细节。CameraX把 Camera2 中复杂的设备枚举、Session、CaptureRequest 封装成更容易使用的用例 API。NavController把导航图、参数、Fragment 切换、返回栈管理封装成统一入口。Activity.onCreate()、onStart()、onResume()Fragment生命周期View.draw()中的测量、绘制、子 View 绘制流程BaseAdapter.getView()abstractclassBaseActivity{funperformCreate(){attachBaseContext()onCreate()restoreState()}protectedopenfunattachBaseContext(){}protectedabstractfunonCreate()protectedopenfunrestoreState(){}}classMainActivity:BaseActivity(){overridefunonCreate(){setContentView("activity_main")}}View.draw()内部大致按背景、内容、子 View、前景等步骤绘制,子类可重写onDraw()填充自定义绘制。if else。RecyclerView.LayoutManagerRecyclerView.ItemAnimatorDiffUtil.ItemCallbackInterpolatorinterfaceSortStrategy{funsort(items:List<Item>):List<Item>}classTimeSortStrategy:SortStrategy{overridefunsort(items:List<Item>)=items.sortedBy{it.time}}classNameSortStrategy:SortStrategy{overridefunsort(items:List<Item>)=items.sortedBy{it.name}}classItemController(privatevarstrategy:SortStrategy){funrender(items:List<Item>){show(strategy.sort(items))}}RecyclerView通过替换LinearLayoutManager、GridLayoutManager、StaggeredGridLayoutManager改变布局策略。Interpolator决定动画数值随时间变化的策略,例如线性、加速、减速。DiffUtil.ItemCallback把“如何判断两个 item 是否相同”的策略交给业务层。Activity->Window->DecorView->ViewGroup->ViewViewGroup.dispatchTouchEvent()、onInterceptTouchEvent()、onTouchEvent()OkHttp Interceptor拦截器链abstractclassEventNode{varnext:EventNode?=nullfundispatch(event:MotionEvent):Boolean{if(handle(event)){returntrue}returnnext?.dispatch(event)?:false}protectedabstractfunhandle(event:MotionEvent):Boolean}Activity.dispatchTouchEvent(),再进入Window和根 View。ViewGroup可以通过onInterceptTouchEvent()决定是否拦截事件。onTouchEvent()继续处理。Lifecycle.StateinterfacePlayerState{funplay(player:Player)funpause(player:Player)}classIdleState:PlayerState{overridefunplay(player:Player){player.prepare()player.state=PlayingState()}overridefunpause(player:Player){// Idle 状态下无需处理}}classPlayingState:PlayerState{overridefunplay(player:Player){}overridefunpause(player:Player){player.pauseInternal()player.state=PausedState()}}LifecycleRegistry会在生命周期事件发生时推进内部状态,例如INITIALIZED、CREATED、STARTED、RESUMED。Runnable投递到HandlerPendingIntentView.OnClickListenerWorkRequestinterfaceCommand{funexecute()}classSaveUserCommand(privatevalrepository:UserRepository,privatevaluser:User):Command{overridefunexecute(){repository.save(user)}}classCommandQueue{privatevalcommands=ArrayDeque<Command>()funenqueue(command:Command){commands.addLast(command)}funrunNext(){commands.removeFirstOrNull()?.execute()}}Handler.post(Runnable)把一段逻辑封装为Runnable,放入消息队列等待主线程或工作线程执行。PendingIntent把未来要执行的启动 Activity、Service、Broadcast 操作交给系统保存并触发。WorkRequest把后台任务的执行条件、输入数据、调度要求封装起来,由 WorkManager 统一执行。Activity同时承担 Controller 和部分 View 职责。Activity/Fragment作为 View,Presenter 处理业务逻辑。ViewModel暴露状态,Activity/Fragment/Compose负责渲染。classUserViewModel(privatevalrepository:UserRepository):ViewModel(){privateval_uiState=MutableStateFlow<UserUiState>(UserUiState.Loading)valuiState:StateFlow<UserUiState>=_uiStatefunloadUser(id:Long){viewModelScope.launch{_uiState.value=UserUiState.Loading _uiState.value=runCatching{repository.getUser(id)}.fold(onSuccess={UserUiState.Content(it)},onFailure={UserUiState.Error(it.message.orEmpty())})}}}classUserFragment:Fragment(){privatevalviewModel:UserViewModelbyviewModels()funrender(){collect(viewModel.uiState){state->when(state){isUserUiState.Loading->showLoading()isUserUiState.Content->showUser(state.user)isUserUiState.Error->showError(state.message)}}}}ViewModel生命周期长于配置变化后的Activity/Fragment重建,适合保存 UI 状态。LiveData/StateFlow让 View 观察状态变化,体现观察者模式。State -> UI思路也是 MVVM / 单向数据流思想的延伸。View和ViewGroupMenu/MenuItemabstractclassUiNode{abstractfundraw()}classTextNode:UiNode(){overridefundraw(){drawText()}}classContainerNode:UiNode(){privatevalchildren=mutableListOf<UiNode>()funadd(child:UiNode){children+=child}overridefundraw(){children.forEach{it.draw()}}}ViewGroup继承自View,因此容器本身也是一个 View。ViewGroup内部持有子 View 列表,测量、布局、绘制时会递归处理子节点。Bitmap缓存RecyclerView复用ViewHolderDrawable、ColorStateList等资源数据classBitmapPool{privatevalcache=mutableMapOf<String,Bitmap>()funget(key:String,loader:()->Bitmap):Bitmap{returncache[key]?:loader().also{bitmap->cache[key]=bitmap}}}RecyclerView通过回收池复用 ViewHolder,避免列表滑动时频繁创建 View。| 你在做什么 | 常见模式 |
|---|---|
| 创建复杂对象 | Builder |
| 控制对象唯一 | Singleton |
| 把创建权交出去 | Factory |
| 数据变了通知 UI | Observer |
| 数据接到列表控件 | Adapter |
| 跨进程像本地调用 | Proxy |
| 包一层增强功能 | Decorator |
| 给复杂系统一个简单入口 | Facade |
| 框架定流程,业务填步骤 | Template Method |
| 替换算法或行为 | Strategy |
| 请求一路传递 | Chain of Responsibility |
| 不同状态不同行为 | State |
| 操作排队或延迟执行 | Command |
| 树形 UI 统一处理 | Composite |
| 大量对象共享复用 | Flyweight |