Android:ViewPager中Fragment加载完成后执行代码的解决方案
解决ViewPager中Fragment调用InkView.loadInk初始化崩溃的问题
核心问题分析
你的崩溃本质是InkView的drawCanvas在onSizeChanged执行后才会初始化,但Fragment的onCreateView、onResume都早于这个时机,直接调用loadInk会访问未初始化的变量。下面是几个可靠的解决方法:
方案1:给InkView添加初始化完成回调(推荐)
让自定义View自己通知外部何时准备就绪,这是最精准的方式,因为只有View本身知道drawCanvas何时初始化完成。
修改InkView代码:
class InkView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : View(context, attrs, defStyleAttr) { private lateinit var drawCanvas: Canvas private var onReadyCallback: (() -> Unit)? = null // 暴露给外部的回调设置方法 fun setOnReadyCallback(callback: () -> Unit) { this.onReadyCallback = callback // 如果已经初始化过,直接触发回调 if (::drawCanvas.isInitialized) { callback.invoke() } } override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { super.onSizeChanged(w, h, oldw, oldh) // 这里是drawCanvas初始化的逻辑 drawCanvas = Canvas(...) // 通知外部View已准备好 onReadyCallback?.invoke() } fun loadInk(brushes: List<Brush>) { // 依赖drawCanvas的业务逻辑 } }
在Fragment的onViewCreated中设置回调:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val inkView = view.findViewById<InkView>(R.id.ink_view) inkView.setOnReadyCallback { // 此时drawCanvas已初始化,安全调用loadInk inkView.loadInk(yourBrushList) } }
方案2:监听Fragment视图布局完成
利用ViewTreeObserver监听视图的全局布局事件,布局完成后onSizeChanged必然已经执行,此时可以安全调用方法。
代码示例:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val inkView = view.findViewById<InkView>(R.id.ink_view) inkView.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { override fun onGlobalLayout() { // 移除监听,避免重复触发 inkView.viewTreeObserver.removeOnGlobalLayoutListener(this) // 双重校验确保安全 if (::inkView.drawCanvas.isInitialized) { inkView.loadInk(yourBrushList) } } }) }
方案3:结合ViewPager2页面可见性监听
因为你用的是FragmentCollectionAdapter(对应ViewPager2),旧的setUserVisibleHint已失效,需要通过ViewPager2的页面切换回调监听当前Fragment,再结合视图状态调用方法。
在ViewPager2所在的页面添加监听:
viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { override fun onPageSelected(position: Int) { super.onPageSelected(position) // 获取当前选中的Fragment(ViewPager2默认标签格式为"f${position}") val currentFragment = supportFragmentManager.findFragmentByTag("f$position") as? YourInkFragment currentFragment?.let { // 确保视图已创建且InkView初始化完成 if (it.view != null && ::it.inkView.drawCanvas.isInitialized) { it.loadInkData() } } } })
在Fragment中封装调用逻辑:
class YourInkFragment : Fragment() { lateinit var inkView: InkView private val yourBrushList: List<Brush> = ... override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) inkView = view.findViewById(R.id.ink_view) } fun loadInkData() { inkView.loadInk(yourBrushList) } }
内容的提问来源于stack exchange,提问作者Pete Williamson
相关产品推荐
相关产品推荐

