From 17f43e8b42cee666601ee9573087b40173f4be52 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Fri, 21 Feb 2025 12:35:20 +0100 Subject: [PATCH] avoid Npe for adapter. A NPE was reported for ConversationsListActivity.kt:537 Adapter is accessed with !! while it is not safe to access in term of lifecycle. So there could have been a race condition. The overall problem is not solved and may even have to wait for migration to Compose. This is just a quickfix for v21.0.0 Reported crash was : Exception java.lang.NullPointerException: at com.nextcloud.talk.conversationlist.ConversationsListActivity.filterConversation (ConversationsListActivity.kt:537) at com.nextcloud.talk.conversationlist.ConversationsListActivity.setConversationList (ConversationsListActivity.kt:472) at com.nextcloud.talk.conversationlist.ConversationsListActivity.access$setConversationList (ConversationsListActivity.kt:158) at com.nextcloud.talk.conversationlist.ConversationsListActivity$initObservers$5$1.invokeSuspend (ConversationsListActivity.kt:398) at com.nextcloud.talk.conversationlist.ConversationsListActivity$initObservers$5$1.invoke (Unknown Source:8) at com.nextcloud.talk.conversationlist.ConversationsListActivity$initObservers$5$1.invoke (Unknown Source:4) at kotlinx.coroutines.flow.FlowKt__TransformKt$onEach$$inlined$unsafeTransform$1$2.emit (Emitters.kt:219) at kotlinx.coroutines.flow.FlowKt__ErrorsKt$catchImpl$2.emit (Errors.kt:154) at kotlinx.coroutines.flow.FlowKt__TransformKt$onEach$$inlined$unsafeTransform$1$2.emit (Emitters.kt:220) at kotlinx.coroutines.flow.SharedFlowImpl.collect$suspendImpl (SharedFlow.kt:392) at kotlinx.coroutines.flow.SharedFlowImpl.collect (Unknown Source) at kotlinx.coroutines.flow.FlowKt__TransformKt$onEach$$inlined$unsafeTransform$1.collect (SafeCollector.common.kt:112) at kotlinx.coroutines.flow.FlowKt__ErrorsKt.catchImpl (Errors.kt:152) at kotlinx.coroutines.flow.FlowKt.catchImpl (Unknown Source:1) at kotlinx.coroutines.flow.FlowKt__ErrorsKt$catch$$inlined$unsafeFlow$1.collect (SafeCollector.common.kt:112) at kotlinx.coroutines.flow.FlowKt__TransformKt$onEach$$inlined$unsafeTransform$1.collect (SafeCollector.common.kt:112) at kotlinx.coroutines.flow.FlowKt__CollectKt.collect (Collect.kt:26) at kotlinx.coroutines.flow.FlowKt.collect (Unknown Source:1) at com.nextcloud.talk.conversationlist.ConversationsListActivity$initObservers$5.invokeSuspend (ConversationsListActivity.kt:399) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:33) at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith (DispatchedContinuation.kt:363) at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable (Cancellable.kt:26) at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default (Cancellable.kt:21) at kotlinx.coroutines.CoroutineStart.invoke (CoroutineStart.kt:88) at kotlinx.coroutines.AbstractCoroutine.start (AbstractCoroutine.kt:123) at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch (Builders.common.kt:52) at kotlinx.coroutines.BuildersKt.launch (Unknown Source:1) at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default (Builders.common.kt:43) at kotlinx.coroutines.BuildersKt.launch$default (Unknown Source:1) at com.nextcloud.talk.conversationlist.ConversationsListActivity.initObservers (ConversationsListActivity.kt:395) at com.nextcloud.talk.conversationlist.ConversationsListActivity.onCreate (ConversationsListActivity.kt:261) at android.app.Activity.performCreate (Activity.java:9149) at android.app.Activity.performCreate (Activity.java:9127) at android.app.Instrumentation.callActivityOnCreate (Instrumentation.java:1526) at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:4152) at android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:4361) at android.app.ActivityThread.handleRelaunchActivityInner (ActivityThread.java:6446) at android.app.ActivityThread.handleRelaunchActivity (ActivityThread.java:6329) at android.app.servertransaction.ActivityRelaunchItem.execute (ActivityRelaunchItem.java:82) at android.app.servertransaction.ActivityTransactionItem.execute (ActivityTransactionItem.java:60) at android.app.servertransaction.TransactionExecutor.executeNonLifecycleItem (TransactionExecutor.java:174) at android.app.servertransaction.TransactionExecutor.executeTransactionItems (TransactionExecutor.java:109) at android.app.servertransaction.TransactionExecutor.execute (TransactionExecutor.java:81) at android.app.ActivityThread$H.handleMessage (ActivityThread.java:2747) at android.os.Handler.dispatchMessage (Handler.java:112) at android.os.Looper.loopOnce (Looper.java:268) at android.os.Looper.loop (Looper.java:384) at android.app.ActivityThread.main (ActivityThread.java:8921) at java.lang.reflect.Method.invoke at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:580) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:907) Signed-off-by: Marcel Hibbe --- .../ConversationsListActivity.kt | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt index 40a487ef97..3fafc116b8 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt @@ -470,7 +470,7 @@ class ConversationsListActivity : // Filter Conversations if (!hasFilterEnabled()) filterableConversationItems = conversationItems filterConversation() - adapter!!.updateDataSet(filterableConversationItems, false) + adapter?.updateDataSet(filterableConversationItems, false) Handler().postDelayed({ checkToShowUnreadBubble() }, UNREAD_BUBBLE_DELAY.toLong()) // Fetch Open Conversations @@ -534,7 +534,7 @@ class ConversationsListActivity : binding.noArchivedConversationLayout.visibility = View.GONE } - adapter!!.updateDataSet(newItems, true) + adapter?.updateDataSet(newItems, true) setFilterableItems(newItems) if (archiveFilterOn) { // Never a notification from archived conversations @@ -735,9 +735,9 @@ class ConversationsListActivity : supportActionBar?.setTitle(R.string.nc_forward_to_three_dots) } else { searchItem!!.isVisible = conversationItems.size > 0 - if (adapter!!.hasFilter()) { + if (adapter?.hasFilter() == true) { showSearchView(searchView, searchItem) - searchView!!.setQuery(adapter!!.getFilter(String::class.java), false) + searchView!!.setQuery(adapter?.getFilter(String::class.java), false) } binding.searchText.setOnClickListener { showSearchView(searchView, searchItem) @@ -768,20 +768,20 @@ class ConversationsListActivity : searchItem!!.setOnActionExpandListener(object : MenuItem.OnActionExpandListener { override fun onMenuItemActionExpand(item: MenuItem): Boolean { initSearchDisposable() - adapter!!.setHeadersShown(true) + adapter?.setHeadersShown(true) if (!hasFilterEnabled()) filterableConversationItems = searchableConversationItems - adapter!!.updateDataSet(filterableConversationItems, false) - adapter!!.showAllHeaders() + adapter?.updateDataSet(filterableConversationItems, false) + adapter?.showAllHeaders() binding.swipeRefreshLayoutView?.isEnabled = false searchBehaviorSubject.onNext(true) return true } override fun onMenuItemActionCollapse(item: MenuItem): Boolean { - adapter!!.setHeadersShown(false) + adapter?.setHeadersShown(false) if (!hasFilterEnabled()) filterableConversationItems = conversationItemsWithHeader - adapter!!.updateDataSet(filterableConversationItems, false) - adapter!!.hideAllHeaders() + adapter?.updateDataSet(filterableConversationItems, false) + adapter?.hideAllHeaders() if (searchHelper != null) { // cancel any pending searches searchHelper!!.cancelSearch() @@ -1158,8 +1158,8 @@ class ConversationsListActivity : val lastVisibleItem = layoutManager!!.findLastCompletelyVisibleItemPosition() for (flexItem in conversationItems) { val conversation: ConversationModel = (flexItem as ConversationItem).model - val position = adapter!!.getGlobalPositionOf(flexItem) - if (hasUnreadItems(conversation) && position > lastVisibleItem) { + val position = adapter?.getGlobalPositionOf(flexItem) + if (position != null && hasUnreadItems(conversation) && position > lastVisibleItem) { nextUnreadConversationScrollPosition = position if (!binding.newMentionPopupBubble.isShown) { binding.newMentionPopupBubble.visibility = View.VISIBLE @@ -1239,7 +1239,7 @@ class ConversationsListActivity : val filter = searchQuery searchQuery = "" performFilterAndSearch(filter) - } else if (adapter!!.hasNewFilter(newText)) { + } else if (adapter?.hasNewFilter(newText) == true) { performFilterAndSearch(newText) } } @@ -1250,12 +1250,12 @@ class ConversationsListActivity : if (hasFilterEnabled()) { adapter?.updateDataSet(conversationItems) - adapter!!.setFilter(filter) - adapter!!.filterItems() + adapter?.setFilter(filter) + adapter?.filterItems() adapter?.updateDataSet(filterableConversationItems) } else { - adapter!!.setFilter(filter) - adapter!!.filterItems() + adapter?.setFilter(filter) + adapter?.filterItems() } if (isUnifiedSearchAvailable(currentUser!!.capabilities!!.spreedCapability!!)) { @@ -1268,18 +1268,18 @@ class ConversationsListActivity : private fun resetSearchResults() { clearMessageSearchResults() - adapter!!.setFilter("") - adapter!!.filterItems() + adapter?.setFilter("") + adapter?.filterItems() } private fun clearMessageSearchResults() { - val firstHeader = adapter!!.getSectionHeader(0) + val firstHeader = adapter?.getSectionHeader(0) if (firstHeader != null && firstHeader.itemViewType == MessagesTextHeaderItem.VIEW_TYPE) { - adapter!!.removeSection(firstHeader) + adapter?.removeSection(firstHeader) } else { - adapter!!.removeItemsOfType(MessageResultItem.VIEW_TYPE) + adapter?.removeItemsOfType(MessageResultItem.VIEW_TYPE) } - adapter!!.removeItemsOfType(LoadMoreResultsItem.VIEW_TYPE) + adapter?.removeItemsOfType(LoadMoreResultsItem.VIEW_TYPE) } @SuppressLint("CheckResult") // handled by helper @@ -1308,7 +1308,7 @@ class ConversationsListActivity : } override fun onItemClick(view: View, position: Int): Boolean { - val item = adapter!!.getItem(position) + val item = adapter?.getItem(position) if (item != null) { when (item.itemViewType) { MessageResultItem.VIEW_TYPE -> { @@ -1461,7 +1461,7 @@ class ConversationsListActivity : if (showShareToScreen || !networkMonitor.isOnline.value) { Log.d(TAG, "sharing to multiple rooms not yet implemented. onItemLongClick is ignored.") } else { - val clickedItem: Any? = adapter!!.getItem(position) + val clickedItem: Any? = adapter?.getItem(position) if (clickedItem != null && clickedItem is ConversationItem) { val conversation = clickedItem.model conversationsListBottomDialog = ConversationsListBottomDialog( @@ -2012,7 +2012,7 @@ class ConversationsListActivity : adapterItems.add(LoadMoreResultsItem) } - adapter!!.addItems(0, adapterItems) + adapter?.addItems(0, adapterItems) binding.recyclerView?.scrollToPosition(0) } }