首页 > 解决方案 > 使用领域和侦听器时应用程序崩溃

问题描述

我目前遇到了一个烦人的问题,我不知道这是一个错误还是我实现了错误。这会导致我的应用程序偶尔崩溃而没有明显的错误消息。我一直在 Stackoverflow 和其他页面上搜索,但到目前为止还没有解决方案。错误本身很长发布,所以如果不是问题,我会发布第一行。

错误信息:

2021-11-06 21:19:55.269 31533-31533/com.example.test A/ple.test: java_vm_ext.cc:577] JNI DETECTED ERROR IN APPLICATION: JNI NewLocalRef called with pending exception java.lang.NullPointerException: 
    java_vm_ext.cc:577] (Throwable with no stack trace)
    java_vm_ext.cc:577] 
    java_vm_ext.cc:577]     in call to NewLocalRef
    java_vm_ext.cc:577]     from void android.os.MessageQueue.nativePollOnce(long, int)

2021-11-06 21:19:55.455 31533-31533/com.example.test A/ple.test: runtime.cc:655] Runtime aborting...
    runtime.cc:655] Dumping all threads without mutator lock held
    runtime.cc:655] All threads:
    runtime.cc:655] DALVIK THREADS (40):
    runtime.cc:655] "main" prio=10 tid=1 Runnable
…

我今天整天都在进行故障排除,以发现问题出在 BottomSheetDialogFragment 和 RealmDB 中。因此,当我启动函数“updateContactChat”时,一切正常,没有错误。一旦我再次打开相同的 BottomSheetDialogFragment 并启动函数“updateContactChat”,应用程序就会完全崩溃并出现上述错误。

是代码。

 class ChatAdd : BottomSheetDialogFragment() {

    private val appRealm = Realm.getInstance(General.secureDB())
    private var binding: FragmentChatsAddBinding? = null
    
    override fun getTheme(): Int = R.style.BottomSheetDialogTheme
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        super.onCreateView(inflater, container, savedInstanceState)
    
        binding = FragmentChatsAddBinding.inflate(inflater, container, false)
    
    
        return binding!!.root
    }
    
    override fun onStart() {
        super.onStart()
        BottomSheetBehavior.from(requireView().parent as View).apply {
            state = BottomSheetBehavior.STATE_EXPANDED
        }
    }
    
    
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        R.style.DialogAnimation.also { dialog!!.window?.attributes?.windowAnimations = it }
    
        binding!!.contactListContainer.layoutManager = LinearLayoutManager(activity)
        binding!!.contactListContainer.setHasFixedSize(true)
        binding!!.contactListContainer.addItemDecoration(ContactsList.ItemDecoration())
    
        showList()
    }
    
    
    private fun showList() {
    
        var contacts: RealmResults<SchemeContacts>? = null
    
        binding!!.contactListContainer.adapter = ContactsAdapter(contacts, true, object :
            ContactsAdapter.ContactItemClickListener {
            override fun onClick(contact: SchemeContacts?) {
    
                contact?.contact_id?.let {
                    CoroutineScope(Dispatchers.IO).launch {
                        try {
                            updateContactChat(it)
                        }catch(e:Exception){
                            Log.d("log", "catch error: "+e)
                        }
                    }
                }
    
            }
        })
    
    }
    
    
    private fun updateContactChat(contactId: String) {
    
        val updateRealm = Realm.getInstance(General.secureDB())
    
        updateRealm.executeTransaction { bgRealm ->
    
            val user =
                bgRealm.where<SchemeContacts>().equalTo("contact_id", contactId).findFirst()!!
            user.contact_chat = true
            user.contact_chatupdated = LocalDateTime.now().toString()
            user.contact_chatnew = 0
            user.contact_chatstatus = 0
    
        }
    
        updateRealm.close()
        dialog!!.dismiss()
    
    }
    
    
    
    override fun onDestroy() {
        super.onDestroy()
        appRealm.close()
        binding = null
    }
}

我也尝试了几种使用 Realm DB 的解决方案,但不幸的是无济于事。我希望这里有人能指出我正确的方向。

更新:

我有一个更改侦听器,它在数据库中进行更改时触发。此代码在我的父片段中,而不是在我的底页片段中。因此,当我选择一个联系人时,数据库会更新,这会触发父片段中的侦听器(您将被发送到该特定的联系人片段)。这是监听器的代码。

 fun runListener(){
contacts?.addChangeListener(OrderedRealmCollectionChangeListener { contacts, changeSet ->
                if (contacts.size > 0) {
                    binding!!.notfound.root.visibility = View.GONE
                } else {
                    binding!!.notfound.root.visibility = View.VISIBLE
                }
    })
}


override fun onDestroy() {
    super.onDestroy()
    binding = null
    appRealm.close()
}

所以第一次什么都没有发生,因为绑定存在并且它将运行没有错误并且Android将运行“onDestroy”,该绑定和数据库正在关闭/为空。因为我从未关闭过监听器,所以会继续收听。当我重复我的动作并启动一个新的监听器时,两个监听器都被调用了。第一个侦听器将查找不存在的“绑定”,因为我在 Android 第一次销毁片段时“取消”了它。所以这就是为什么我得到一个空异常。第一个侦听器的绑定不再存在。

将代码更改为此后,一切正常,没有崩溃或错误:

fun runListener(){
        
contacts?.addChangeListener(OrderedRealmCollectionChangeListener { 
  contacts, changeSet ->
    try {
            if(binding != null) {
                if (contacts.size > 0) {
                    binding!!.notfound.root.visibility = View.GONE
                } else {
                    binding!!.notfound.root.visibility = View.VISIBLE
                }
            }
    }catch(e:Exception){
      Log.d("error","Try Catch error: "+e.toString())
    }
  })
}
      
        
override fun onDestroy() {
  super.onDestroy()
  if(contacts != null){
        contacts!!.removeAllChangeListeners()
  }
  binding = null
  appRealm.close()
}

我希望它很清楚,这确实是初学者的一个漫长的错误,也是非常重要的一课。关闭你开始的一切。

标签: androidkotlinrealmbottom-sheet

解决方案


问题是绑定到元素的父片段上的领域侦听器。它显然会导致错误。


推荐阅读