RecyclerView选择与对话框一起导致崩溃空对象上的getAdapterPostion 编辑:

如何解决RecyclerView选择与对话框一起导致崩溃空对象上的getAdapterPostion 编辑:

在我当前正在开发的应用程序中,我在viewpager中有一个片段,其中显示了RecyclerView,其中填充了数据库中的一些数据。在此RecyclerView中,我已使用recyclerview-selection库以及一个actionmode实现了ItemSelection。仅此一项就可以了。但是,我还有一个FloatingActionButton,它会打开一个对话框,用户可以在其中向数据库添加新入口,该入口也将显示在recyclerview中。对话框成功打开,但是当用户单击edittext时,它崩溃并显示以下错误消息:

2020-08-16 16:45:36.413 12939-12939/com.nilswinking.kochbuch2 E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.me.myapp,PID: 12939
    java.lang.NullPointerException: Attempt to invoke virtual method 'int androidx.recyclerview.widget.RecyclerView$ViewHolder.getAdapterPosition()' on a null object reference
        at androidx.recyclerview.selection.StableIdKeyProvider.onDetached(StableIdKeyProvider.java:90)
        at androidx.recyclerview.selection.StableIdKeyProvider$1.onChildViewDetachedFromWindow(StableIdKeyProvider.java:69)
        at androidx.recyclerview.widget.RecyclerView.dispatchChildDetached(RecyclerView.java:7546)
        at androidx.recyclerview.widget.RecyclerView.removeDetachedView(RecyclerView.java:4349)
        at androidx.recyclerview.widget.RecyclerView$LayoutManager.removeAndRecycleScrapInt(RecyclerView.java:9243)
        at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep3(RecyclerView.java:4207)
        at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3862)
        at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4404)
        at android.view.View.layout(View.java:22844)
        at android.view.ViewGroup.layout(ViewGroup.java:6389)
        at androidx.constraintlayout.widget.ConstraintLayout.onLayout(ConstraintLayout.java:1915)
        at android.view.View.layout(View.java:22844)
        at android.view.ViewGroup.layout(ViewGroup.java:6389)
        at androidx.viewpager.widget.ViewPager.onLayout(ViewPager.java:1775)
        at android.view.View.layout(View.java:22844)
        at android.view.ViewGroup.layout(ViewGroup.java:6389)
        at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829)
        at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1673)
        at android.widget.LinearLayout.onLayout(LinearLayout.java:1582)
        at android.view.View.layout(View.java:22844)
        at android.view.ViewGroup.layout(ViewGroup.java:6389)
        at androidx.coordinatorlayout.widget.CoordinatorLayout.layoutChild(CoordinatorLayout.java:1213)
        at androidx.coordinatorlayout.widget.CoordinatorLayout.onLayoutChild(CoordinatorLayout.java:899)
        at androidx.coordinatorlayout.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:919)
        at android.view.View.layout(View.java:22844)
        at android.view.ViewGroup.layout(ViewGroup.java:6389)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
        at android.view.View.layout(View.java:22844)
        at android.view.ViewGroup.layout(ViewGroup.java:6389)
        at androidx.coordinatorlayout.widget.CoordinatorLayout.layoutChild(CoordinatorLayout.java:1213)
        at androidx.coordinatorlayout.widget.CoordinatorLayout.onLayoutChild(CoordinatorLayout.java:899)
        at androidx.coordinatorlayout.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:919)
        at android.view.View.layout(View.java:22844)
        at android.view.ViewGroup.layout(ViewGroup.java:6389)
        at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829)
        at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1673)
        at android.widget.LinearLayout.onLayout(LinearLayout.java:1582)
        at android.view.View.layout(View.java:22844)
        at android.view.ViewGroup.layout(ViewGroup.java:6389)
        at androidx.coordinatorlayout.widget.CoordinatorLayout.layoutChild(CoordinatorLayout.java:1213)
        at androidx.coordinatorlayout.widget.CoordinatorLayout.onLayoutChild(CoordinatorLayout.java:899)
        at androidx.coordinatorlayout.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:919)
        at android.view.View.layout(View.java:22844)
        at android.view.ViewGroup.layout(ViewGroup.java:6389)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
        at android.view.View.layout(View.java:22844)
        at android.view.ViewGroup.layout(ViewGroup.java:6389)
        at androidx.appcompat.widget.ActionBarOverlayLayout.onLayout(ActionBarOverlayLayout.java:446)
        at android.view.View.layout(View.java:22844)
        at android.view.ViewGroup.layout(ViewGroup.java:6389)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
2020-08-16 16:45:36.416 12939-12939/com.me.myapp E/AndroidRuntime:     at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
        at android.view.View.layout(View.java:22844)
        at android.view.ViewGroup.layout(ViewGroup.java:6389)
        at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829)
        at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1673)
        at android.widget.LinearLayout.onLayout(LinearLayout.java:1582)
        at android.view.View.layout(View.java:22844)
        at android.view.ViewGroup.layout(ViewGroup.java:6389)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
        at com.android.internal.policy.DecorView.onLayout(DecorView.java:784)
        at android.view.View.layout(View.java:22844)
        at android.view.ViewGroup.layout(ViewGroup.java:6389)
        at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:3470)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2938)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1952)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:8171)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:972)
        at android.view.Choreographer.doCallbacks(Choreographer.java:796)
        at android.view.Choreographer.doFrame(Choreographer.java:731)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:957)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)

对话框:

class AddBookDialog : DialogFragment() {

    private val TAG = AddBookDialog::class.java.simpleName

    private lateinit var listener: AddBookDialogInterface

    private lateinit var editTextName: EditText
    private lateinit var title: TextView

    private var id: String? = null

    interface AddBookDialogInterface {
        fun addKochbuch(name: String,id: String? = null): Boolean
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        return activity?.let {
            // Use the Builder class for convenient dialog construction
            val builder = AlertDialog.Builder(it,R.style.AppTheme_AlertDialog)
            val inflater = requireActivity().layoutInflater;

            val view = inflater.inflate(R.layout.add_book_dialog,null)

            editTextName = view.findViewById(R.id.editTextName)
//            editTextNameLayout = view.findViewById(R.id.editTextNameLayout)
            title = view.findViewById(R.id.title)

            arguments?.let {
                it.getString(nameParam).let {
                    editTextName.setText(it)
                }
                id = it.getString(idParam)
            }

            editTextName.setOnKeyListener(View.OnKeyListener { v,keyCode,event ->
                if (keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_UP) {
                    add()
                    return@OnKeyListener true
                }
                false
            })


            builder.setView(view)
                .setPositiveButton(
                    "Hinzufügen"
                ) { dialog,id ->
                    add()
                }
                .setNegativeButton(
                    "Abbrechen"
                ) { dialog,id ->
                    // User cancelled the dialog
                }
            // Create the AlertDialog object and return it
            val dialog: AlertDialog = builder.create()
            dialog.setOnShowListener {
                val button: Button = dialog.getButton(AlertDialog.BUTTON_POSITIVE)
                button.setOnClickListener {add()}
            }

            dialog
        } ?: throw IllegalStateException("Activity cannot be null")
    }


    override fun onAttach(context: Context) {
        super.onAttach(context)
        // Verify that the host activity implements the callback interface
        try {
            // Instantiate the NoticeDialogListener so we can send events to the host
            listener = context as AddBookDialogInterface
        } catch (e: ClassCastException) {
            // The activity doesn't implement the interface,throw exception
            throw ClassCastException((context.toString() +
                    " must implement AddBookDialogInterface"))
        }
    }

    private fun add() {
        val name = editTextName.text.toString()
        listener.addKochbuch(name,id).let {
            if (it)
                dismiss()
        }
    }

    companion object {
        fun newInstance(kochbuch: Kochbuch? = null) =
            AddBookDialog().apply {
                arguments = Bundle().apply {
                    putString(nameParam,kochbuch?.name)
                    putString(idParam,kochbuch?.id)
                }
            }

    }
}

对话框布局:

<?xml version="1.0" encoding="utf-8"?>
<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/title"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:text="Erstelle ein neues Kochbuch"
        android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"
        android:textColor="@color/material_on_background_emphasis_high_type"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/editTextNameLayout"
        style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginBottom="16dp"
        android:hint="Name deines Kochbuches"
        android:textColorHint="@color/input_outline_color"
        app:boxStrokeColor="@color/input_outline_color"
        app:hintTextColor="@color/input_outline_color"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/title">

        <com.google.android.material.textfield.TextInputEditText
            android:id="@+id/editTextName"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:singleLine="true"
            android:textColor="@color/material_on_background_emphasis_high_type" />

    </com.google.android.material.textfield.TextInputLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

片段:

class HomeBooksFragment : Fragment(),OnActionItemClickListener {

    private val TAG = HomeBooksFragment::class.java.simpleName

    private lateinit var realm: Realm
    private val adapter = ItemAdapterCookingBooks()

    private lateinit var result: RealmResults<Kochbuch>

    private lateinit var tracker: SelectionTracker<Long>

    private var actionmode: SelectionActionModeCallback? = null

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

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

        realm = Realm.getDefaultInstance()

        result = realm.where<Kochbuch>().sort("name").findAll()
        result.addChangeListener { t,_ ->
            updateUI(t)
        }
        adapter.data = ArrayList()
        rv.layoutManager = GridLayoutManager(context,2)
        rv.adapter = adapter

        tracker = SelectionTracker.Builder<Long>(
            "mySelection",rv,StableIdKeyProvider(rv),ItemDetailLookup(rv),StorageStrategy.createLongStorage()
        ).withSelectionPredicate(
            SelectionPredicates.createSelectAnything()
        ).build()

        tracker.addObserver(
            object : SelectionTracker.SelectionObserver<Long>() {
                override fun onSelectionChanged() {
                    super.onSelectionChanged()
                    tracker.selection.size().let { i ->
                        when {
                            i >= 2 -> actionmode?.setEditEnabled(false)
                            i == 1 -> actionmode?.setEditEnabled(true)
                            i == 0 -> Log.d(TAG,"onSelectionChanged: zero items selected")
                            else -> null
                        }

                        if (tracker.hasSelection() && actionmode == null) {
                            actionmode = SelectionActionModeCallback()
                            view?.let { actionmode?.startActionMode(it,R.menu.selection_action_mode_menu,tracker,"$i Ausgwählt") }
                            actionmode?.setListener(this@HomeBooksFragment)
                        } else if (!tracker.hasSelection() && actionmode != null) {
                            actionmode?.finishActionMode()
                            actionmode = null
                        } else {
                            actionmode?.setTitle("$i Ausgewählt")
                        }
                    }
                }
            }
        )

        adapter.tracker = tracker

        updateUI(result)
    }
}

ItemDetailLookup没问题,因为我将所有内容都放入了try-catch块中,并且错误仍然出现。

进一步的调试显示,只有在对话框后面显示和项目时才会发生调试(在我的屏幕上显示7个项目时)。但是,当对话框打开而我的viewpager中显示另一个片段时,也会发生这种情况。由此,我怀疑单击事件是通过对话框以某种方式传递到底层片段的。

任何帮助将不胜感激。

编辑:

在显示其他对话框时也会发生

解决方法

由于某种原因,选择跟踪器试图获取一个不存在或不在recyclerview中且产生了空指针实例的视图持有者的itemdetails。在我的ViewHolder中,我有此方法可返回有关该Viewholder的所有必要信息,以使选择跟踪器正常工作,在这里使用正确的实现是无效的:

fun getItemDetails(): ItemDetailsLookup.ItemDetails<Long> =
            object : ItemDetailsLookup.ItemDetails<Long>() {
                override fun getPosition(): Int {
                    try {
                        return adapterPosition
                    } catch (e: Exception) {
                        return -1
                    }
                }
                override fun getSelectionKey(): Long? = itemId
            }

为比较起见,请问我以前发布的实现的问题。

,

可能有点晚了,但是我最近遇到了同样的问题,并找到了对我有用的解决方案。创建一个自定义ItemKeyProvider为我解决了NPE问题。我使用了我在网上找到的这篇文章:A guide to recyclerview selection

class LongItemKeyProvider(private val recyclerView: RecyclerView) :
    ItemKeyProvider<Long>(SCOPE_MAPPED) {

    override fun getKey(position: Int): Long? {
        return recyclerView.adapter?.getItemId(position)
    }

    override fun getPosition(key: Long): Int {
        return recyclerView.findViewHolderForItemId(key)?.layoutPosition ?: 
            RecyclerView.NO_POSITION
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-