You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 00:01:16