Skip to content

Migration Guide

Rafal Adasiewicz edited this page Sep 5, 2020 · 4 revisions

Updating Android SDK for Stream Chat dependency

Open the application build.gradle script and update stream-chat-android dependency to the newest available version:

    implementation 'com.github.GetStream:stream-chat-android:4.2.11-beta11'

Updated dependency requires one more change - add META-INF/*.kotlin_module exclusion to packagingOptions:

    android {
    //...
    packagingOptions {
        exclude 'META-INF/*.kotlin_module'
    }
    //...
}

Make sure that the project is synced.

Chat initialization

StreamChat is now replaced with Chat interface which exposes Builder which is responsible for the initialization process:

   Chat.Builder(apiKey = "apiKey", context = applicationContext).build()

You can also configure multiple initialization parameters before building Chat - e.g. style or notificationConfig. Chat instance is automatically created after calling build() and you can always access it using:

   Chat.getInstance()

You can set current user by calling setUser() method on Chat instance. Moreover, setUser() allows you to pass InitConnectionListener which might be helpful for indicating if the connection is correctly established:

        val user = User("userID").apply {
            extraData["name"] = "Paranoid Android"
            extraData["image"] = "https://bit.ly/2TIt8NR"
        }

        Chat.getInstance().setUser(
            user = user,
            token = "token",
            callbacks = object : InitConnectionListener() {
                override fun onSuccess(data: ConnectionData) {
                }

                override fun onError(error: ChatError) {
                }
            }
        )

Chat logger

ChatLogger exposes Builder which might be used to set and configure logs across SDK:

         ChatLogger.Builder(ChatLogger.Config(level = ChatLogLevel.ALL, handler = null)).build()

It's worth to notice that the second ChatLogger.Builder parameter - ChatLoggerHandler is optional and allows you to perform some actions after reporting logs. By default, ChatLogger is initialized with a silent logger which will skip all logs.

Channels list

ChannelListView is now replaced with ChannelsView:

    <com.getstream.sdk.chat.view.channels.ChannelsView
        android:id="@+id/channelsView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:streamChannelPreviewLayout="@layout/stream_item_channel"
        app:streamReadStateAvatarHeight="15dp"
        app:streamReadStateAvatarWidth="15dp"
        app:streamReadStateTextSize="9sp"
        app:streamShowReadState="true" />

You can now obtain channels using ChannelsViewModelImpl class. Setting filters and sorting channels it's much simpler and can be done by passing FilterObject and QuerySort parameters to ViewModel constructor (ChannelsViewModelImpl comes with default ones, but you can always change them if needed). Last but not least - you can now bind ChannelsView with ChannelsViewModel by calling bindView() extension method:

    private val viewModel by lazy { ChannelsViewModelImpl() }
    //...
    viewModel.bindView(channelsView, lifecycleOwner)

Channel list

ChannelViewModel was divided into three separate view models - MessageListViewModel, ChannelHeaderViewModel, MessageInputViewModel which are responsible for interacting with the corresponding channel list components:

  • MessageListViewModel - responsible for getting and displaying messages. It also provides useful information about the current state of messages
  • ChannelHeaderViewModel - cooperates with ChannelHeaderView to show useful information about the channel
  • MessageInputViewModel - responsible for sending new messages Just like in case of ChannelsViewMode - you need to bind view models with corresponding views and then implement logic responsible for passing messages and entering/exiting from a thread from MessageInputViewModel to _MessageListViewModel:
        val messagesViewModel = MessageListViewModel(cid)
            .apply {
                bindView(messageListView, this@ChannelActivity)
                state.observe(
                    this@ChannelActivity,
                    {
                        when (it) {
                            is MessageListViewModel.State.Loading -> progressBar.visible(true)
                            is MessageListViewModel.State.Result -> progressBar.visible(false)
                            is MessageListViewModel.State.NavigateUp -> finish()
                        }
                    }
                )
            }

        ChannelHeaderViewModel(cid).bindView(channelHeaderView, this)

        MessageInputViewModel(cid).apply {
            bindView(messageInputView, this@ChannelActivity)
            messagesViewModel.mode.observe(
                this@ChannelActivity,
                {
                    when (it) {
                        is MessageListViewModel.Mode.Thread -> setActiveThread(it.parentMessage)
                        is MessageListViewModel.Mode.Normal -> resetThread()
                    }
                }
            )
            messageListView.setOnMessageEditHandler {
                editMessage.postValue(it)
            }
        }

If you want to handle back button press properly - pass MessageListViewModel.Event.BackButtonPressed to MessageListViewModel in proper method:

        val backButtonHandler = {
            messagesViewModel.onEvent(MessageListViewModel.Event.BackButtonPressed)
        }
        onBackPressedDispatcher.addCallback(
            this,
            object : OnBackPressedCallback(true) {
                override fun handleOnBackPressed() {
                    backButtonHandler()
                }
            }
        )

Last but not least - you don't have to be worried about requesting Camera/Storage permissions. They are now automatically handled by MessageInputView 🎉

Attachment view holder

There is a slight difference when extending from BaseAttachmentViewHolder in the current version. Second parameter type - MessageListItem is now replaced with MessageListItem.MessageItem:

    public abstract void bind(@NonNull Context context,
                              @NonNull MessageListItem.MessageItem messageListItem,
                              @NonNull Message message,
                              @NonNull Attachment attachment,
                              @NonNull MessageListViewStyle style,
                              @NonNull MessageListView.BubbleHelper bubbleHelper,
                              @Nullable MessageListView.AttachmentClickListener clickListener,
                              @Nullable MessageListView.MessageLongClickListener longClickListener);

Channel controller

The low-level client enables you to talk directly to Stream's API. This gives you the flexibility to implement any messaging/chat UI that you want. If you want to listen for events that comes in the particular channel - use ChannelController which can be obtained from ChatClient instance:

val channelController = ChatClient.instance().channel(cid)
channelController.events().subscribe {
}