Android SBUIKIT collection.loadMore() takes infinite time

Hi,

I’m using the latest version of Sendbird UIkit. UIKit is initialised successfully, and SendbirdUIKit.connect returns a successful connection. After a successful connection, I run the following code in my Activity

conversationsFragment = ChannelListFragment.Builder()
            .setUseHeader(false)
            .build()

        supportFragmentManager.beginTransaction()
            .replace(R.id.fragment_container, conversationsFragment, TAG_CHAT_CONVERSATIONS_FRAGMENT)
            .commit()

It creates the ChannelListFragment, and loadMoreBlocking() method is called eventually for loading the channel list. Within this method, the collection.loadMore() method is called, and the GroupChannelsCallbackHandler supplied to it is never triggered. On the UI I get a continuous loader which never goes away.

I have not customised the UIKit classes and using the ChannelListFragment.Builder() with the params as mentioned above. How can I fix this issue?

Here are the log messages from sendbird

D/SBUIKIT: [08:36:11.609 ChannelListFragment:onBeforeReady():86] >> ChannelListFragment::initModule()
        D/SBUIKIT: [08:36:11.700 ChannelListFragment:onBindHeaderComponent():115] >> ChannelListFragment::setupHeaderComponent()
        D/SBUIKIT: [08:36:11.788 ChannelListFragment:onBindChannelListComponent():128] >> ChannelListFragment::setupChannelListComponent()
        D/SBUIKIT: [08:36:11.850 ChannelListFragment:onBindStatusComponent():142] >> ChannelListFragment::setupStatusComponent()
        D/SBUIKIT: [08:36:11.881 ChannelListFragment:onReady():98] >> ChannelListFragment::onReady status=READY
        D/SBUIKIT: [08:36:13.562 ChannelListViewModel:initChannelCollection():83] >> ChannelListViewModel::initChannelCollection()

After this last Log message, nothing else is triggered, and an infinite loader shows up on screen.

@Gunho_Cho Could you please help with this query? This is the only issue blocking sendbird adoption from our side.

Hi @Abhilash_D,
I can’t reproduce the problem.
Can you share the reproducible project I can check?

Here are the complete logs for log level LogLevel.ALL

2022-08-22 11:54:38.854 11166-11166/com.locus.lotr D/SBUIKIT: [11:54:38.853 SendbirdUIKit$2:onResultForUiThread():497] ++ user=User(userId='tour-testing/abhilash2', nickname='Abhilash2', plainProfileImageUrl='', friendDiscoveryKey=null, friendName='null', metaData={}, connectionStatus=NON_AVAILABLE, lastSeenAt=0, isActive=true, preferredLanguages=[], requireAuth=false), error=null
2022-08-22 11:54:38.872 11166-11166/com.locus.lotr D/SBUIKIT: [11:54:38.872 SendbirdUIKit$2:onResultForUiThread():497] ++ user=User(userId='tour-testing/abhilash2', nickname='Abhilash2', plainProfileImageUrl='', friendDiscoveryKey=null, friendName='null', metaData={}, connectionStatus=NON_AVAILABLE, lastSeenAt=0, isActive=true, preferredLanguages=[], requireAuth=false), error=null
2022-08-22 11:54:38.872 11166-11166/com.locus.lotr D/SBUIKIT: [11:54:38.872 ChannelListFragment:onBeforeReady():84] >> ChannelListFragment::initModule()
2022-08-22 11:54:38.872 11166-11166/com.locus.lotr D/SBUIKIT: [11:54:38.872 ChannelListFragment:onBindHeaderComponent():113] >> ChannelListFragment::setupHeaderComponent()
2022-08-22 11:54:38.872 11166-11166/com.locus.lotr D/SBUIKIT: [11:54:38.872 ChannelListFragment:onBindChannelListComponent():126] >> ChannelListFragment::setupChannelListComponent()
2022-08-22 11:54:38.872 11166-11166/com.locus.lotr D/SBUIKIT: [11:54:38.872 ChannelListFragment:onBindStatusComponent():140] >> ChannelListFragment::setupStatusComponent()
2022-08-22 11:54:38.872 11166-11166/com.locus.lotr D/SBUIKIT: [11:54:38.872 ChannelListFragment:onReady():96] >> ChannelListFragment::onReady status=READY
2022-08-22 11:54:38.872 11166-11166/com.locus.lotr D/SBUIKIT: [11:54:38.872 ChannelListViewModel:initChannelCollection():83] >> ChannelListViewModel::initChannelCollection()

The order of operations is as follows

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

            SendbirdUIKit.connect { _, exception ->
        
                    if (exception != null) {
                        showConnectionErrorDialog()
                        return@connect
                    }
        
                    val conversationsFragment = SendbirdUIKit.getFragmentFactory().newChannelListFragment(Bundle())

                    supportFragmentManager.beginTransaction()
                        .replace(R.id.fragment_container, conversationsFragment, TAG_CHAT_CONVERSATIONS_FRAGMENT)
                        .commit()
                }
}

I have also tried using

val params = GroupChannelListQueryParams()
        params.includeEmpty = true
        val query = GroupChannel.createMyGroupChannelListQuery(params)

        val conversationsFragment = ChannelListFragment.Builder()
            .setUseHeader(false)
            .setGroupChannelListQuery(query)
            .build()

But the result is the same.

Here is the video of the UI
sendbird

There are no more logs recorderd after this, and the loader keeps running infinitely

What is the parent of the activity, UIKit’s ChannelListActivity or app’s custom AppCompatActivity?

  1. onCreate does not do setContentView(). Its parent does? (it will if the super is ChannelListActivity)
  2. where does R.id.fragment_container come from? (it’s not UIKit default layout, R.id.sb_fragment_container)
    1 and 2 contradict.
    1 suggests that the parent is UIKit class
    2 implies that the activity is app’s custom class
    It’s confusing. Can you share the entire class file?

The activity whose onCreate I shared, is the corresponding GroupChannelMainActivity from the sample code. It extends AppCompatActivity, and has its own view layout. R.id.fragment_container is a FrameLayout element below the blue coloured toolbar, which is where the fragments are displayed.

class ChatActivity : AppCompatActivity(){

override fun onCreate(savedInstanceState: Bundle?) { 

       super.onCreate(savedInstanceState)

        val binding = ActivityChatBinding.inflate(layoutInflater)

        setContentView(binding.root)

            SendbirdUIKit.connect { _, exception ->
        
                    if (exception != null) {
                        showConnectionErrorDialog()
                        return@connect
                    }
        
                    val conversationsFragment = SendbirdUIKit.getFragmentFactory().newChannelListFragment(Bundle())

                    supportFragmentManager.beginTransaction()
                        .replace(R.id.fragment_container, conversationsFragment, TAG_CHAT_CONVERSATIONS_FRAGMENT)
                        .commit()
                }
        }
}

Hi @Abhilash_D ,
Looks like a connection problem.
App is not supposed to directly manage connection. UIKit will handle the connection internally on demand. You don’t need to explicitly call SendbirdUIKit.connect().

Can you try this sample and see if the problem persists?
You can change connection info from BaseApplication.

@Gunho_Cho I have tried with this sample app. Facing the same issue. Here is a screen recording from the same.

Here are the logs


2022-08-23 12:01:20.626 10011-10011/com.example.uikitkotlin D/SBUIKIT: [12:01:20.626 SendbirdUIKit$2:onResultForUiThread():497] ++ user=User(userId='tour-testing/c-1', nickname='c-1', plainProfileImageUrl='https://assets-devo.locus-api-devo.com/v1/client/tour-testing/photos/05834c3b945c4fe8af9a8cda00786a05.png', friendDiscoveryKey=null, friendName='null', metaData={}, connectionStatus=NON_AVAILABLE, lastSeenAt=0, isActive=true, preferredLanguages=[], requireAuth=false), error=null
2022-08-23 12:01:20.627 10011-10011/com.example.uikitkotlin D/SBUIKIT: [12:01:20.627 ChannelListFragment:onBeforeReady():84] >> ChannelListFragment::initModule()
2022-08-23 12:01:20.627 10011-10011/com.example.uikitkotlin D/SBUIKIT: [12:01:20.627 ChannelListFragment:onBindHeaderComponent():113] >> ChannelListFragment::setupHeaderComponent()
2022-08-23 12:01:20.627 10011-10011/com.example.uikitkotlin D/SBUIKIT: [12:01:20.627 ChannelListFragment:onBindChannelListComponent():126] >> ChannelListFragment::setupChannelListComponent()
2022-08-23 12:01:20.628 10011-10011/com.example.uikitkotlin D/SBUIKIT: [12:01:20.628 ChannelListFragment:onBindStatusComponent():140] >> ChannelListFragment::setupStatusComponent()
2022-08-23 12:01:20.628 10011-10011/com.example.uikitkotlin D/SBUIKIT: [12:01:20.628 ChannelListFragment:onReady():96] >> ChannelListFragment::onReady status=READY
2022-08-23 12:01:20.628 10011-10011/com.example.uikitkotlin D/SBUIKIT: [12:01:20.628 ChannelListViewModel:initChannelCollection():83] >> ChannelListViewModel::initChannelCollection()

In the sample app code hosted here, SendbirdUIKit.connect() is called from the application after user logs in. Also, from our previous conversations, and what I have read from the documentation, I was under the impression that the app can call connect() when a server connection is needed to be established. Please let me know if my assumptions are incorrect…

Point being, we don’t want a connection to server throughout the lifetime of the application. SendbirdUIKit should be initialised only after a user logs in and the chat feature is enabled for the particular user (which the app will know by calling one of our APIs after the user logs in), and a connection to server should only exist when the user in within the ChatActivity mentioned in my previous reply. We don’t want to maintain a server connection otherwise.

@Gunho_Cho I did some experimentation and found that the issue is resolved when I created a different application on the sendbird dashboard and connected using users in the new application. Maybe some configuration issue or corrupt data on our exisiting applicationID is causing this?

That’s weird.
Can you share your app IDs, both working and problematic? @Abhilash_D
I think our server platform team needs to dig deep in the problem.
Meanwhile, is there no difference between users in 2 Sendbird applications? Like ID-only login(no auth) vs. access token authentication?
Or the user’s session token has expired?

And you’re right. App can control connection by explicitly connecting as in the uikit sample.
However to better handle connection savings, you’d better not call connect explicitly too early. In your sample, if connection is only needed when ChatActivity is activated, app moreover needs not to call connect. (UIKit sample calls connect in order to get online as soon as a user logs in)
Instead, you will want to call disconnect when ChatActivity is unloaded.

@Gunho_Cho

Working app ID : 107D6D1E-53A9-466E-8645-F835C4FF37AA
Problematic app ID : 81679A5E-A58B-48FC-BAE8-5B7F6AC168A5

  • Both applications have ID-only login. (Settings > Security > Access Token Permission :: Allow users without access token to : “Read & Write”)
  • User’s session token was generated freshly in both cases, so tokens have not expired.

And you’re right. App can control connection by explicitly connecting as in the uikit sample.
However to better handle connection savings, you’d better not call connect explicitly too early. In your sample, if connection is only needed when ChatActivity is activated, app moreover needs not to call connect. (UIKit sample calls connect in order to get online as soon as a user logs in)
Instead, you will want to call disconnect when ChatActivity is unloaded.

Thanks! Have tested this and this works. On a side note, is there a way for us to Log when a sendbird server connection is established and closed? LogLevel.ALL does not log server connection status.

Hi Abhilash,
Our product team will investigate into the issue.
And I’m internally checking if there’re dedicated logs for connection status. I’ll get you posted on any update soon. Thanks.

Hi, @Abhilash_D, is it always the case?
I sometimes see there being a wide delay(~= 30s) between initChannelCollection and notifyDataSetChanged usually when the app connects for the first time in long disconnection.
If I reconnect(restart), the delay drops to almost 0.
Curious what it’s like on your end?

And regarding logging on connection status, there turns out to be no special path to logging the state. Looks like apps need to do it for itself if it’s needed.

@Gunho_Cho In my case, notifyDatasetchanged() never gets triggered.

I am facing the same issue with the new application ID I mentioned as well. With an emoty deployment. The moment even a single channel gets created on the sendbird application, the mobile app malfunctions.

I did a bunch of testing with the sample app and my app. I even initialised sendbirdUiKit in the application onCreate() method like it is done in the sample app. The problem still persists.