Error: lateinit property recyclerViewAdapter has not been initialized

Error: lateinit property recyclerViewAdapter has not been initialized

我尝试在 onCreate 片段中初始化 recyclerView 和 ViewModel 并得到错误 lateinit property recyclerViewAdapter has not been initialized

class ListFragment : Fragment() {

    private val recyclerView: RecyclerView? = activity?.findViewById(R.id.recyclerView)

    private lateinit var recyclerViewAdapter: RecyclerViewAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        initRecyclerView()
        initViewModel()
    }

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

    private fun initRecyclerView() {
        recyclerView?.apply {
            layoutManager = LinearLayoutManager(context)
            val decoration = DividerItemDecoration(context, DividerItemDecoration.VERTICAL)
            addItemDecoration(decoration)
            recyclerViewAdapter = RecyclerViewAdapter()
            adapter = recyclerViewAdapter
        }
    }

    private fun initViewModel() {
        val viewModel = ViewModelProvider(this)[MainActivityViewModel::class.java]
        lifecycleScope.launchWhenCreated {
            viewModel.getListData().collectLatest {
                recyclerViewAdapter.submitData(it)
            }
        }
    }
}

这是你出错的地方:

private val recyclerView: RecyclerView? = activity?.findViewById(R.id.recyclerView)

上面的 属性 将为空,因为 activity 在 Fragment 的实例化时为空,而您正在使用 activity?. 所以您将其初始化为 null .

然后在 initRecyclerView() 中,您使用的是 recyclerView?.apply,因此不会执行 lambda 中的任何内容,因为 recyclerView 为空。因此,属性 recyclerViewAdapter 永远不会被设置,所以当它第一次访问时(在 initViewModel() 中),它会抛出 UnitializedPropertAccessException 并崩溃。

您不得在声明站点初始化 Fragment 的视图属性,因为 Fragment 在具有任何视图或附加到任何视图之前就已初始化 Activity。此外,同一个 Fragment 实例可能会被重复使用,但有一个新的视图和 Activity 实例,所以你应该确保每次有一个新视图时你都是 re-assigning 这些属性。

此外,不要在 onCreate() 中初始化视图,因为它发生在您的 onCreateView() 之前,因此将找不到视图。您应该很少需要在片段中使用 onCreate()。请改用 onViewCreated()

如果回收站视图在您的 Fragment 布局中,您应该在 Fragment 的视图中搜索 RecyclerView,而不是在 Activity 中向上搜索。 Activity 仍然不包含片段在 onViewCreated() 中的视图,因此它将无法找到视图。

修复代码的方法如下:

class ListFragment : Fragment() {

    private lateinit var recyclerView: RecyclerView

    private lateinit var recyclerViewAdapter: RecyclerViewAdapter

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

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onCreate(view, savedInstanceState)

        recyclerView = view.findViewById(R.id.recyclerView)

        initRecyclerView()
        initViewModel()
    }

    private fun initRecyclerView() {
        recyclerView.apply {
            layoutManager = LinearLayoutManager(context)
            val decoration = DividerItemDecoration(context, DividerItemDecoration.VERTICAL)
            addItemDecoration(decoration)
            recyclerViewAdapter = RecyclerViewAdapter()
            adapter = recyclerViewAdapter 
        }
    }

    private fun initViewModel() {
        //...
    }
}

从技术上讲,当片段分离时,上面的内容泄露了您的观点。您可以通过使用自定义 getter 来避免这种情况,这样您就不会缓存对视图的引用。此外,您可以通过将布局 ID 直接传递给片段 super-constructor 来消除 onCreateView。所以我会这样写 class:

class ListFragment : Fragment(R.layout.fragment_list) {

    private val recyclerView: RecyclerView
        get() = requireView().findViewById(R.id.recyclerView)

    private val recyclerViewAdapter: RecyclerViewAdapter
        get() = recyclerView.adapter as RecyclerViewAdapter

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onCreate(view, savedInstanceState)

        initRecyclerView()
        initViewModel()
    }

    private fun initRecyclerView() {
        recyclerView.apply {
            layoutManager = LinearLayoutManager(context)
            val decoration = DividerItemDecoration(context, DividerItemDecoration.VERTICAL)
            addItemDecoration(decoration)
            adapter = RecyclerViewAdapter()
        }
    }

    private fun initViewModel() {
        //...
    }
}