当前位置: 首页 > 知识库问答 >
问题:

使用合成函数的片段中的空指针

齐俊达
2023-03-14

我在使用synthetic的片段中的视图上(有时)得到空指针。我不知道哪里出错了,因为我在XML中声明了片段,我认为当我从活动中调用< code>populate方法时,根视图已经创建好了

无论如何,我不相信是正确的检查这个每次我打电话给填充...

我编写了一个示例代码来说明发生了什么(空指针将位于tv):

片段:

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import kotlinx.android.synthetic.main.fragment_foo.*

class FooFragment : Fragment() {

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_foo, container, false)
    }

    fun populate(fooName: String) {
        tv.text = fooName
    }
}

与活动相关的XML内的XML相关

<fragment
android:id="@+id/fFoo"
android:name="com.foo.FooFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:layout="@layout/fragment_foo"/>

这将与活动相关:

class FooActivity : AppCompatActivity() {
    private lateinit var fooFragment: FooFragment

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_foo)
        fooFragment = fFoo as FooFragment
    }

    private fun loadDataProductionInfo(productionId: Long) {
        FooAPIParser().getFoo {
            initFoo(it.fooName)
        }
    }

    private fun initFoo(fooName: String) {
        fooFragment.populate(fooName)
    }
}

最后是特定片段的XML:

 <androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

        <TextView
            android:id="@+id/tvFoo"
            style="@style/Tv"/>

</androidx.constraintlayout.widget.ConstraintLayout>

共有3个答案

林项明
2023-03-14

最后,我得到了帮助,以找到更好的答案。

open class BaseFooFragment : Fragment() {

    private var listener: VoidListener? = null
    private var viewCreated = false

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewCreated = true
        listener?.let {
            it.invoke()
            listener = null
        }
    }

    override fun onDestroyView() {
        viewCreated = false
        super.onDestroyView()
    }

    fun doWhenViewCreated(success: VoidListener) {
        if (viewCreated) {
            success()
        } else {
            listener = success
        }
    }
}

VoidListener就是这样:

typealias VoidListener = () -> Unit

执行此操作的一种更通用的方法(例如,当您想要使用多个侦听器时)可能是这样的:

open class BaseFooFragment : Fragment() {

    private val listeners: MutableList<VoidListener> = mutableListOf()
    private var viewCreated = false

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewCreated = true
        listeners.forEach { it() }
        listeners.clear()
    }

    override fun onDestroyView() {
        viewCreated = false
        super.onDestroyView()
    }

    fun doWhenViewCreated(success: VoidListener) {
        if (viewCreated) {
            success()
        } else {
            listeners.add(success)
        }
    }
}
郎伟兆
2023-03-14

在你的回答中思考我已经实现了一个补丁。我不太喜欢,但我认为它应该比现在更好。你怎么想呢?

我将扩展我想从这个类中检查的每个片段:

import android.os.Bundle
import android.os.Handler
import android.view.View
import androidx.fragment.app.Fragment

open class BaseFooFragment : Fragment() {

    private var viewCreated = false
    private var attempt = 0

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewCreated = true
    }

    fun checkViewCreated(success: () -> Unit) {
        if (viewCreated) {
            success()
        } else {
            initLoop(success)
        }
    }

    private fun initLoop(success: () -> Unit) {
        attempt++
        Handler().postDelayed({
            if (viewCreated) {
                success()
            } else {
                if (attempt > 3) {
                    return@postDelayed
                }
                checkViewCreated(success)
            }
        }, 500)
    }
}

片段中的调用或多或少是干净的:

fun populate(fooName: String) {
    checkViewCreated {
        tv.text = fooName
    }
}
师向文
2023-03-14

Kotlin的合成特性并不是神奇的,而是以一种非常简单的方式工作的。当您访问btn_K时,它调用getView().findviewbyd(R.id.tv)

问题是您访问它太快了getView()onCreateView中返回null。尝试在onViewCreated方法中执行:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    //Here
    }
}

使用 onViewCreated 外部的视图。

tv?.text = "kotlin safe call"

如果您要使用片段,则需要扩展片段活动

 类似资料:
  • 我试图在列表视图的onItemClick中用另一个片段替换片段,我想将所选项目名称从列表片段发送到另一个片段,但它显示空指针异常 @覆盖onItemClick上的公共无效(AdapterView ar0,视图,int位置,长id){ 但是同样的概念在下面的按钮点击中工作

  • 我在一个片段中制作了一个listview列表视图的适配器有一个空指针异常,但Arraylist和适配器不为空。 错误:lvElevator不能为null 错误是针对以下行的 电梯。适配器=EAdapter

  • 在JavaScript中,该代码如下所示: 正如您所看到的,函数组合与JavaScript中的链接方法非常相似。我真的很喜欢链接方法从左到右读取的方式。在Haskell中,我可以使用中的函数和反向函数应用程序执行类似的操作,如下所示: 现在我想用点自由样式来写这个函数。使用函数组合,我将把它写如下: 函数组合的美妙之处在于它可以与自身组合,形成如上所示的“高阶函数组合”。因此,尽管它的类型签名直观

  • 最近在review代码的时候发现,使用了空指针调用成员函数,并且成员函数内部有使用到成员变量,居然没有出错。很是奇怪,就用一篇博客把关于空指针调用成员函数相关的内容总结起来。 空指针调用成员函数 调用普通成员函数 如果空指针调用普通成员函数,看该函数体中是否使用到了this指针(是否访问非静态成员变量)。如果使用到了this指针,程序会崩溃;如果没有使用到this指针,程序不会崩溃。当然,如果访问

  • 公共视图onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState){View v=inflater.inflate(r.layout.fragment_main,container,false); fragment.xml null

  • 作为一个Haskell新手,我不明白为什么表达式抛出异常和函数组合必须与运算符一起应用-它右边的表达式不需要进一步计算,因为它只是一个。编译它的另一种方法是将在括号中,但是与,那么为什么把它放在括号中可以编译表达式呢?