【问题标题】:Android Kotlin: Custom view causing crash on changing fragmentsAndroid Kotlin:自定义视图导致更改片段时崩溃
【发布时间】:2020-11-07 13:17:04
【问题描述】:

在我的项目中,我将三个片段附加到一个活动,其中一个片段再次使用自定义视图显示文本。所以它们基本上是片段中的片段。

在主片段中,我将这些代码用于在文本显示片段之间切换。它在其子片段传递的代码上触发。

private fun diagCommence(target: Fragment) {
    val transaction = activity?.supportFragmentManager?.beginTransaction()
    if (transaction != null) {
        transaction.replace(R.id.ig1_Diag_Layout, target)
        transaction.disallowAddToBackStack()
        transaction.commit()
    }
}

文本显示片段具有自定义视图 - AppCompatTextView - 显示文本。

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    return inflater.inflate(R.layout.layoutx2, container, false)
}
override fun onStart() {
    super.onStart()
    val scene = getString(R.string.sceneX2)
    tv01.commenceOnLifecycle(SceneX2(), scene, textanimspeed.toLong(), textanim) // the custom view that displays texts, triggers NPE
}

我现在有三个相同的文本显示片段,第一个文本显示片段显示正常。但是当我尝试将值传递给主片段并触发 diagCommence() 时,应用程序崩溃了。奇怪的是,当我尝试访问第二个文本显示片段时,它给了我空指针异常。

根据日志,在 beginOnLifecycle() 方法中调用了错误,该方法调用了我制作的 AppCompatTextView。将其移动到不同的生命周期,例如 onCreate()、onViewCreated() 似乎无助于解决这个问题。我想知道我错过了什么?

编辑:SceneX2的布局XML,是一个文本显示片段:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/x2Layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

<com.example.textia1.TypeWriterView
    android:id="@+id/x2Twv01"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textColor="@color/colorAccent" />

<TextView
    android:id="@+id/x2Choice01"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@string/X2toX1" />

<TextView
    android:id="@+id/x2Choice02"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@string/X2toX3" />

</LinearLayout>

以及使用打字动画显示文本的自定义 TextView:

class TypeWriterView: AppCompatTextView {
  constructor(context: Context) : super(context)
  constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)

  suspend fun commence(txt: CharSequence?, delay: Long, animOnOff: Boolean) {
    if (txt != null) {
        if(animOnOff) {
            var index = 0
            while (index < txt.length) {
                text = txt.subSequence(0, ++index)
                delay(delay)
            }
        } else {text = txt}
    } else return
  }
  fun commenceOnLifecycle(owner: LifecycleOwner, txt: CharSequence?, delay: Long, animOnOff: Boolean): Job =
    owner.lifecycleScope.launch { commence(txt, delay, animOnOff) }
}

【问题讨论】:

    标签: android kotlin


    【解决方案1】:

    尝试将您的diagCommence 功能代码替换为

    activity?.supportFragmentManager?.beginTransaction()
            ?.replace(R.id.ig1_Diag_Layout, target)
            ?.addToBackStack(null)
            ?.commit()
    

    另外,您应该在onCreateView 中初始化您的 tv01 视图。首先,声明一个全局变量

    private var tv01: TypeWriterView? = null
    

    并编辑您的 onCreateView 方法

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.layoutx2, container, false)
        
        tv01 = view.findViewById(R.id.x2Twv01)
    
        val scene = requireActivity().getString(R.string.sceneX2)
        tv01?.commenceOnLifecycle(SceneX2(), scene, textanimspeed.toLong(), textanim) // the custom view that displays texts
        
        return view
    }
    

    编辑

    将您的TypeWriterView 声明修改为

    class TypeWriterView(
        context: Context,
        attrs: AttributeSet
    ) : AppCompatTextView(context, attrs) {
    

    【讨论】:

    • 感谢您的帮助。我将第二个代码用作:private var tv01: AppCompatTextView? = null 我做对了吗?下一个也变成了这样:tv01 = view?.findViewById(R.id.Sc_X2_tv01) 在没有安全调用的情况下出现错误。正如您所说,我替换了 diagCommence 并将 onStart 中的代码移至 onCreate ,但它仍然无法正常工作并给我 NPE。
    • 尝试在编辑后的答案中移动onCreateView 中的代码,还要注意我调用requireActivity() 来从资源中获取字符串。您的片段中有textanimspeedtextanim 全局变量吗?
    • 是的,我修改了代码,但是将 AppCompatTextView 放入 &lt;&gt; 会在 @987654337 上出现错误“需要属性获取器或设置器”和“没有足够的信息来推断类型变量 T” @。而且tv01?.commenceOnLifecycle() 也犯了“未解决的参考”错误,所以我不得不让它成为(Tv01.commenceOnLifecycle 但这里的 Tv01 是布局 ID)。该应用程序在调用 commenceOnLifecycle() 时仍会引发 NPE。
    • 我忘记删除 &lt;&gt; 包装 AppCompatTextView。你能发布你的 layoutx2 XML 吗?
    • 好的,把它和appcompat textview贴出来,以防万一。
    【解决方案2】:

    如果你在活动,你应该使用 fragmentManager。请更改此行

        val nextScene = activity?.supportFragmentManager?.beginTransaction()
    

        val nextScene = fragmentManager?.beginTransaction()
    

    【讨论】:

      【解决方案3】:

      确保使用childFragmentManager,因为childFragmentManagerfragments 相关联,就像supportFragmentManageractivity 相关联

      private fun diagCommence(target: Fragment) {
          val transaction = childFragmentManager.beginTransaction()
          if (transaction != null) {
              transaction.replace(R.id.ig1_Diag_Layout, target)
              transaction.disallowAddToBackStack()
              transaction.commit()
          }
      }
      

      【讨论】:

      • 抱歉,它完成了所有工作,包括显示下一个片段,根本无法点击...
      猜你喜欢
      • 2011-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-21
      • 2015-03-09
      • 1970-01-01
      相关资源
      最近更新 更多