【问题标题】:W/RecyclerView: No adapter attached; skipping layoutW/RecyclerView:没有附加适配器;跳过布局
【发布时间】:2021-11-04 09:12:00
【问题描述】:

我制作了一个基本的购物清单应用程序,它利用回收站视图来显示清单项目。我正在尝试使用带有片段的导航来添加设置屏幕。当我打开应用程序时,我遇到了我的 recyclerview 和数据显示的问题,但是当我转到设置菜单然后返回主屏幕时,没有 recyclerview。 Logcat 显示错误“W/RecyclerView:未连接适配器;跳过布局”

MainActivity.kt

package com.example.shoppinglist

import android.app.Dialog
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.findNavController
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.floatingactionbutton.FloatingActionButton

class MainActivity : AppCompatActivity(), RVAdapter.ListItemClickInterface {
lateinit var itemsRV: RecyclerView
lateinit var addFAB: FloatingActionButton
lateinit var list: List<ListItems>
lateinit var RVAdapter: RVAdapter
lateinit var viewModel: ViewModel

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    setupActionBarWithNavController(findNavController(R.id.fragment_main))
    itemsRV = findViewById(R.id.recyclerView)
    addFAB = findViewById(R.id.idFABAdd)
    list = ArrayList<ListItems>()
    RVAdapter = RVAdapter(list, this)
    itemsRV.layoutManager = LinearLayoutManager(this)
    itemsRV.adapter = RVAdapter
    val repository = Repository(Database(this))
    val factory = ViewModelFactory(repository)
    viewModel = ViewModelProvider(this, factory).get(ViewModel::class.java)
    viewModel.getAllListItems().observe(this, Observer {
        RVAdapter.list = it
        RVAdapter.notifyDataSetChanged()
    })

    addFAB.setOnClickListener {
        openDialog()
    }

}

override fun onSupportNavigateUp(): Boolean {
    val navController = findNavController(R.id.fragment_main)
    return navController.navigateUp() || super.onSupportNavigateUp()
}

fun openDialog() {
    val dialog = Dialog(this)
    dialog.setContentView(R.layout.add_dialog)
    val cancelButton = dialog.findViewById<Button>(R.id.idBtnCancel)
    val addButton = dialog.findViewById<Button>(R.id.idBtnAdd)
    val itemEdt = dialog.findViewById<EditText>(R.id.idEditItemName)
    val itemQuantityEdt = dialog.findViewById<EditText>(R.id.idEditItemQuantity)

    cancelButton.setOnClickListener {
        dialog.dismiss()
    }
    addButton.setOnClickListener {
        val itemName: String = itemEdt.text.toString()
        val itemQuantity: String = itemQuantityEdt.text.toString()
        if (itemName.isNotBlank() && itemQuantity.isNotBlank()) {
            val items = ListItems(itemName, itemQuantity)
            viewModel.insert(items)
            Toast.makeText(applicationContext, "Item Added", Toast.LENGTH_SHORT).show()
            RVAdapter.notifyDataSetChanged()
            dialog.dismiss()
        } else {
            Toast.makeText(applicationContext, "Enter All Info To Add Item", 

Toast.LENGTH_SHORT)
                    .show()
            }
        }
        dialog.show()
    }

    override fun onItemClick(listItems: ListItems) {
        viewModel.delete(listItems)
        RVAdapter.notifyDataSetChanged()
        Toast.makeText(applicationContext, "Item Deleted", Toast.LENGTH_SHORT).show()
    }
}

HomeFragment.kt

package com.example.shoppinglist

import android.os.Build
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.RequiresApi
import androidx.navigation.fragment.findNavController
import androidx.preference.PreferenceManager
import kotlinx.android.synthetic.main.fragment_home.*

class HomeFragment : Fragment()  {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_home, container, false)
    }

    @RequiresApi(Build.VERSION_CODES.N)
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        idFABSettings.setOnClickListener {
            findNavController().navigate(R.id.action_homeFragment_to_settingsFragment)
        }

        loadSettings()
    }

    @RequiresApi(Build.VERSION_CODES.N)
    private fun loadSettings(){
        val sp = PreferenceManager.getDefaultSharedPreferences(context)

        val theme = sp.getBoolean("theme_switch",false)

    }

}

SettingsFragment.kt

package com.example.shoppinglist

import android.os.Bundle
import androidx.preference.PreferenceFragmentCompat

class SettingsFragment : PreferenceFragmentCompat() {

    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        setPreferencesFromResource(R.xml.root_preferences, rootKey)
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout 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="match_parent"
    tools:context=".MainActivity">

    <fragment
        android:id="@+id/fragment_main"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/navigation"
        />

</RelativeLayout>

fragment_home.xml

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:background="?attr/colorPrimary"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:listitem="@layout/list_rv_item"/>

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/idFABAdd"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_alignParentBottom="true"
        android:layout_marginStart="20dp"
        android:layout_marginTop="20dp"
        android:layout_marginEnd="20dp"
        android:layout_marginBottom="20dp"
        android:backgroundTint="?attr/colorSecondary"
        android:contentDescription="Add Item Button"
        android:src="@drawable/ic_add"
        android:tint="@android:color/white" />

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/idFABSettings"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:layout_alignParentBottom="true"
        android:layout_marginStart="20dp"
        android:layout_marginTop="20dp"
        android:layout_marginEnd="20dp"
        android:layout_marginBottom="20dp"
        android:backgroundTint="?attr/colorSecondary"
        android:contentDescription="Add Item Button"
        android:src="@drawable/ic_settings"
        android:tint="@android:color/white" />

</RelativeLayout>

导航.xml

<?xml version="1.0" encoding="utf-8"?>
<navigation 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:id="@+id/navigation"
    app:startDestination="@id/homeFragment">

    <fragment
        android:id="@+id/settingsFragment"
        android:name="com.example.shoppinglist.SettingsFragment"
        android:label="Settings" >
        <action
            android:id="@+id/action_settingsFragment_to_homeFragment"
            app:destination="@id/homeFragment" />
    </fragment>
    <fragment
        android:id="@+id/homeFragment"
        android:name="com.example.shoppinglist.HomeFragment"
        android:label="Shopping List"
        tools:layout="@layout/fragment_home" >
        <action
            android:id="@+id/action_homeFragment_to_settingsFragment"
            app:destination="@id/settingsFragment" />
    </fragment>
</navigation>

不确定是否需要更多信息。提前道歉 - 我是 android studio 和 kotlin 的新手。

【问题讨论】:

  • lateinit 与它无关,因为该适配器在 onCreate() 中初始化。 @Tokorae,您在哪里托管这些片段?如果您在 MainActivity 中托管您的 Fragment,那么在您的 MainActivity 中有一个 RecyclerView 会很奇怪。如果屏幕上也有 RecyclerView,那么如何有空间显示您正在导航的所有片段?
  • 通常,如果您使用 Fragments,托管 Activity 中的代码将是最少的。可能有一个布局会显示一些小的持久性内容,例如共享操作栏和可能的侧边抽屉菜单,以及占据大部分屏幕的片段容器。但由 Fragments 来显示应用程序的主要内容。
  • activity_main.xml中的fragment,包含androidx.navigation.fragment.NavHostFragment,就是你说的那个吗?

标签: android-studio kotlin android-recyclerview


【解决方案1】:

您正在尝试通过 MainActivity 使用特定于 HomeFragment 布局的视图。这将无法正常工作。第一次启动活动时,在onCreate 中使用findViewById 查找ID 为recyclerView 的视图,它成功找到它,因为那时视图是布局中的HomeFragment 的一部分。

但是,当您更改片段时,原始片段视图将被分离并删除。当您返回到第一个片段时,Android 会创建您的 HomeFragment 及其布局的新实例。 MainActivity 仍然从 HomeFragment 的第一个实例引用原始 RecyclerView,因此它将更新不再出现在屏幕上的视图,并且不会触及新视图。您实际上已经创建了内存泄漏,MainActivity 正在阻止第一个片段的视图被破坏。

您尚未发现的另一个问题可能是,如果您在 SettingsFragment 打开时旋转屏幕,您将因 NullPointerException 而崩溃。这是因为屏幕旋转会导致创建一个新的Activity,所以onCreate()会被再次调用,当HomeFragment不在布局中的情况下尝试查找recyclerView时会失败。

从托管 Activity 处理 Fragment 的特定视图是没有意义的。 Activity 不必知道 Fragment 中的内容以及如何处理该 Fragment 的内容的任何细节。所有与 RecyclerView 相关的代码都应该在 HomeFragment 中。

【讨论】:

  • 好的,所以我需要重新配置代码,以便 RV 元素位于 HomeFragment.kt 而不是 MainActivity.kt 中,有没有一种简单的方法可以做到这一点,或者需要我重新- 编码整个事情?为简单的问题道歉,我还是新手,我的课程导师不是很有帮助。我仍然必须删除 SQLite 功能并将其替换为本地 XML 数据库存储。
  • 我希望通过剪切/粘贴传输相关代码会相当快。 Activity 的 onCreate() 中的内容应该在 Fragment 的 onViewCreated() 中。从技术上讲,您应该为任何在片段中保存对视图的引用的属性使用可空类型,并在onDetach 中将它们设置回空。如果您使用 ViewBinding,那么您只需对单个属性执行此操作,因为它在内部保存对您所有视图的引用。
猜你喜欢
  • 2018-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-15
  • 2019-04-07
  • 2020-01-09
  • 2017-12-01
  • 2021-06-19
相关资源
最近更新 更多