Crash implementing CustomChannelSettings

Hi all,

I’m using Android UIKit version 2.2.4 with Android 10, and I’m trying to implement a CustomChannelSettings.

With the fallowing implementation:

override fun createChannelSettingsFragment(channelUrl: String): ChannelSettingsFragment? {
        return ChannelSettingsFragment
            .Builder(channelUrl)
            .setCustomChannelSettingsFragment(CustomChannelSettingsFragment())
            .setUseHeader(true)
            .setUseHeaderRightButton(false)
            .setHeaderLeftButtonListener(null)
            .setOnSettingMenuClickListener(null) 
            .build()
    }

I have a crash:
NullPointerException: Parameter specified as non-null is null on setOnMenuItemClickListener

To avoid this situation, I added .setOnSettingMenuClickListener { _, _, _ -> false } instead of .setOnSettingMenuClickListener(null) , now I can open the settings page.

But when I click on Leave chat only the settings page is finished, the CustomChannelActivity, with the chat that I left, is still present, I would like that both activities will be finished after a leaving action.

Any help? Thank you.

Hi @Barros,

Calling leaveChannel() should finish the channel activity. Can you please share the code blob that calls leaveChannel() so that we can check and investigate further.

Meanwhile, if you have any other questions please let us know.

Best,
Dhaval.

Thank you, @Dhaval_Patel

First, I would like to ask if the solution to avoid the crash is it correct?

Of course, in CustomChannelSettingsFragment I had:

class CustomChannelSettingsFragment : ChannelSettingsFragment(),
    OnMenuItemClickListener<ChannelSettingMenu?, GroupChannel> {

    override fun onMenuItemClicked(view: View, menu: ChannelSettingMenu?, data: GroupChannel): Boolean {
        when (menu) {
            ChannelSettingMenu.MODERATIONS -> {}
            ChannelSettingMenu.MEMBERS -> {
                createCustomMemberListActivity(data.url)
                return true
            }
            ChannelSettingMenu.NOTIFICATIONS -> {}
            ChannelSettingMenu.LEAVE_CHANNEL -> {
                leaveChannel(data.url)
                return true
            }
            else -> {}
        }
        return false
    }

    private fun leaveChannel(channelUrl: String) {
        runCatching {
            GroupChannel.getChannel(channelUrl) { groupChannel, exception ->
                if (exception != null) {
                    Timber.e(exception)
                    return@getChannel
                }

                if (!groupChannel.isDistinct && groupChannel.memberCount == 1) {
                    showErrorDialog()
                } else {
                    groupChannel.leave { Timber.e(it) }
                }
            }
        }.onFailure {
            Timber.e(it)
        }
    }

    override fun leaveChannel() {
        // do nothing
    }

    override fun setOnMenuItemClickListener(listener: OnMenuItemClickListener<ChannelSettingMenu?, GroupChannel>) {
        super.setOnMenuItemClickListener(this)
    }
}

Hi @Barros

If you refer to our custom sample, you can see same codes.

I am not sure why NullPointerException has been invoked. Could you let us know more details?

  • I recommend to use our super.leaveChannel() to leave the channel. I think you need to check data.url is correct with your target channel.

Yes, I checked channelUrl and it’s correct.
I’m trying to call super.leaveChannel() but I have the same result, only CustomChannelSettingsActivity is finished:

private fun leaveChannel(channelUrl: String) {
        runCatching {
            GroupChannel.getChannel(channelUrl) { groupChannel, exception ->
                if (exception != null) {
                    Timber.e(exception)
                    return@getChannel
                }

                if (!groupChannel.isDistinct && groupChannel.memberCount == 1) {
                    showErrorDialog()
                } else {
                   super.leaveChannel()
                }
            }
        }.onFailure {
            Timber.e(it)
        }
    }

Talking about NullPointerException, I can reproduce this issue easily, my code is:

class CustomChannelSettingsActivity : ChannelSettingsActivity() {

    private var channelUrl: String? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        channelUrl = intent.extras?.getString(StringSet.KEY_CHANNEL_URL)
    }

    override fun createChannelSettingsFragment(channelUrl: String): ChannelSettingsFragment? {
        return ChannelSettingsFragment
            .Builder(channelUrl)
            .setCustomChannelSettingsFragment(CustomChannelSettingsFragment())
            .setUseHeader(true)
            .setUseHeaderRightButton(false)
            .setHeaderLeftButtonListener(null)
            .setOnSettingMenuClickListener(null)
            .build()
    }
}

with the error:

 Caused by: java.lang.NullPointerException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkNotNullParameter, parameter listener
        at com.healthyvirtuoso.android.presentation.ui.chat.customchannelsettings.CustomChannelSettingsFragment.setOnMenuItemClickListener(Unknown Source:2)
        at com.sendbird.uikit.fragments.ChannelSettingsFragment$Builder.build(ChannelSettingsFragment.java:737)
        at com.healthyvirtuoso.android.presentation.ui.chat.customchannelsettings.CustomChannelSettingsActivity.createChannelSettingsFragment(CustomChannelSettingsActivity.kt:46)
        at com.sendbird.uikit.activities.ChannelSettingsActivity.onCreate(ChannelSettingsActivity.java:59)
        at com.healthyvirtuoso.android.presentation.ui.chat.customchannelsettings.CustomChannelSettingsActivity.onCreate(CustomChannelSettingsActivity.kt:23)

Hi, @Barros
You overrode our setOnMenuItemClickListener() and changed the listener parameter to non-null type. It invoked NullPointerException.

How did you start an activity that includes CustomSettingsFragment?

You overrode our setOnMenuItemClickListener() and changed the listener parameter to non-null type. It invoked NullPointerException.

Thank you, I didn’t notice, now I don’t have the exception.

How did you start an activity that includes CustomSettingsFragment ?

This is how I created a CustomChannel and started a CustomChannelSettingsActivity

class CustomChannelActivity : ChannelActivity() {

    private var channelUrl: String? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        channelUrl = intent.extras?.getString(KEY_CHANNEL_URL)
    }

    override fun createChannelFragment(channelUrl: String): ChannelFragment {
        return ChannelFragment
            .Builder(channelUrl)
            .setCustomChannelFragment(CustomChannelFragment())
            .setUseHeader(true)
            .setUseInputLeftButton(false)
            .setHeaderRightButtonListener { createCustomChannelSettings(channelUrl) }
            .build()
    }

    private fun createCustomChannelSettings(channelUrl: String) {
        startActivity(Intent(this, CustomChannelSettingsActivity::class.java).apply {
            putExtra(KEY_CHANNEL_URL, channelUrl)
        })
    }
}

Hi @Barros, Why your CustomChanneSettignsActivity is java file?

I’m sorry @Doo_Rim, but I didn’t get it your question, could you explain to me that exactly?

I am sorry I misunderstood it.
I think we need to check CustomChannelFragment code.
Did you override finish() method in your CustomChannelFragment?

If user left the channel, channel handler invoke onChannelDeleted(). Then, ChannelFragment will be finished.

Did you override finish() method in your CustomChannelFragment ?

Nope, I didn’t.

CustomChannelFragment overrides nothing, it’s just that with no methods:

class CustomChannelFragment : ChannelFragment()

And CustomChannelActivity is:

class CustomChannelActivity : ChannelActivity() {

    private var channelUrl: String? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        channelUrl = intent.extras?.getString(KEY_CHANNEL_URL)
    }

    override fun createChannelFragment(channelUrl: String): ChannelFragment {
        return ChannelFragment
            .Builder(channelUrl)
            .setCustomChannelFragment(CustomChannelFragment())
            .setUseHeader(true)
            .setUseInputLeftButton(false)
            .setHeaderRightButtonListener { createCustomChannelSettings(channelUrl) }
            .build()
    }

    private fun createCustomChannelSettings(channelUrl: String) {
        startActivity(Intent(this, CustomChannelSettingsActivity::class.java).apply {
            putExtra(KEY_CHANNEL_URL, channelUrl)
        })
    }
}

Could you record the video?

I don’t know why the channel remains…

Of course, here the video:

You can notice that it left the channel correctly, but just the last activity is destroyed.

Did you run our custom-sample? It worked well…
I don’t what the difference is.

How do you start CustomChannelActivity?

Yes, I ran your custom-sample, and it works perfectly.

How do you start CustomChannelActivity ?

context.startActivity(Intent(context, CustomChannelActivity::class.java).apply {
        putExtra(StringSet.KEY_CHANNEL_URL, channelUrl)
    })

Also, others considerations:

  • I didn’t have android:launchMode="singleTop" on AndroidManifest, I added, but the result is always the same
  • after clicked on “Leave Chat”, I see the following logs
I/SBUIKIT: [09:03:19.100 ChannelSettingsFragment:lambda$leaveChannel$9$ChannelSettingsFragment():496] ++ leave channel
I/SBUIKIT: [09:03:19.179 ChannelSettingsFragment$1:onUserLeft():104] >> ChannelSettingsFragment::onUserLeft()

But no log like >> ChannelSettingsFragment::onChannelDeleted()

  • custom-sample uses newIntentFromCustomActivity to start an Activity, instead startActivity, maybe is there anything different?

I know how to reproduce the issue, I have two type of channels in my app, one of them has GroupChannelParams().setPublic(false).setDistinct(true) and the second one has GroupChannelParams().setPublic(true).setDistinct(false).

The first one works correctly, I can leave a channel and all activities are destroyed, but in the second one I have the issue, like in the screen recorder.

I reproduce that on your custom-sample, in CustomCreateChannelFragment I add the params setPublic(true) and setDistinct(false) false:

    @Override
    protected void onBeforeCreateGroupChannel(@NonNull GroupChannelParams params) {
        super.onBeforeCreateGroupChannel(params);
        params.addUserIds(userIds).setPublic(true).setDistinct(false);
    }

@Barros Thank you for reporting! I reproduced it. I will discuss it with our team and let you know!

@Barros This issue will be fixed next release! If we release it, I will let you know!

1 Like