我在使用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>
最后,我得到了帮助,以找到更好的答案。
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)
}
}
}
在你的回答中思考我已经实现了一个补丁。我不太喜欢,但我认为它应该比现在更好。你怎么想呢?
我将扩展我想从这个类中检查的每个片段:
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
}
}
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新手,我不明白为什么表达式抛出异常和函数组合必须与运算符一起应用-它右边的表达式不需要进一步计算,因为它只是一个。编译它的另一种方法是将在括号中,但是与,那么为什么把它放在括号中可以编译表达式呢?