Chat SDKs Android v3
Chat SDKs Android
Chat SDKs
Android
Version 3
Sendbird Chat SDK v3 for Android is no longer supported as a new version is released. Check out our latest Chat SDK v4

Caching data

Copy link

Storing chat data locally within devices helps users retrieve their channels and messages even while offline. It can also prevent the inefficiency of repeating queries upon each connection or when device state changes, as well as provide a desirable user experience by reducing data loading delays.

In this File caching: Basic page and Database caching: Advanced page, you can see how to build a local cache by using object serialization and deserialization, which is provided through the Chat SDK. In the page, we provide instructions on how to build a simple cache that stores the most recent messages and channels in a file. In the Database caching: Advanced page, you can find instructions on caching chat data in an internal database, which enables you to store structured and queryable data.


Caching with Sendbird SyncManager

Copy link

Sendbird SyncManager is a library for chat data synchronization, which allows you to cache channels and messages of those channels in your client app reliably with a little effort. It listens to the events which happen on the channels in real-time and executes the background tasks for updating the cached data accordingly. You can use the cached data for a better user experience, such as retrieving old messages in a channel view without requesting to Sendbird server.

If you want a simple and fast caching implementation, download the SyncManager from our repository on GitHub and see the guide on how to add to your client app.

Note: The SyncManager includes SQLite as an internal database and operates based on it, which saves and stores the chat data synced with Sendbird server for caching.


File caching: Basic

Copy link

This page shows you how to build a simple cache that stores a user's most recent channels and messages. A cache can be used to load data when an offline user attempts to view a list of channels, or enters a channel to view their chat history. Implementing just a basic cache like the following can improve user experience, as users get to see empty lists of channels or messages due to their unstable connection.

In the steps described below, we create a file per channel in your client app's cache directory, write serialized data into the file to store a set amount of recent messages, configure the app to first load messages from the cache, and then finally replace them when the newest results are successfully fetched from Sendbird server.


Serialize and deserialize Sendbird objects

Copy link

In order to enable you to store Sendbird objects such as messages, channels, and users in a local storage, we provide serialization and deserialization methods through our Chat SDK.

By using the serialize() method to convert a Sendbird object to binary data like the following, you can store the data natively in a file.

byte[] data = baseMessage.serialize();
BaseMessage deserializedMessage = BaseMessage.buildFromSerializedData(data);

Save serialized messages

Copy link

With serialization, you can store a channel and its most recent messages in a file. In this case, we are encoding the binary serialized data into a Base64 string. then storing each item in a new line. Normally, save data when onStop() is called in your user's chat screen.

Note: To keep your local database in sync with Sendbird server’s data, your app should regularly check for changes made to messages in the server and apply those changes to the local cache accordingly. Because the getMessageChangeLogsByToken() and getMessageChangeLogsByTimestamp() methods are deprecated as of August 2021, you can manage local database updates by retrieving change logs of messages using the getMessageChangeLogsSinceToken() or getMessageChangeLogsSinceTimestamp() methods.

// Saving serialized messages.
public void save() {
    try {
        StringBuilder sb = new StringBuilder();
        if (mChannel != null) {
            // Convert current channel instance into a string.
            sb.append(Base64.encodeToString(mChannel.serialize(), Base64.DEFAULT | Base64.NO_WRAP));

            // Convert up to 100 messages within the channel into a string.
            BaseMessage message = null;
            for (int i = 0; i < Math.min(mMessageList.size(), 100); i++) {
                message = mMessageList.get(i);
                sb.append("\n");
                sb.append(Base64.encodeToString(message.serialize(), Base64.DEFAULT | Base64.NO_WRAP));
            }

            String data = sb.toString();
            String md5 = TextUtils.generateMD5(data);

            // Create a file within the app's cache directory.
            File appDir = new File(mContext.getCacheDir(), SendBird.getApplicationId());
            appDir.mkdirs();

            // Create a data file and a hash file within the directory.
            File dataFile = new File(appDir, TextUtils.generateMD5(SendBird.getCurrentUser().getUserId() + mChannel.getUrl()) + ".data");
            File hashFile = new File(appDir, TextUtils.generateMD5(SendBird.getCurrentUser().getUserId() + mChannel.getUrl()) + ".hash");

            try {
                String content = FileUtils.loadFromFile(hashFile);
                // If data has not been changed, do not save.
                if (md5.equals(content)) {
                    return;
                }
            } catch(IOException e) {
                // File not found. Save the data.
            }

            FileUtils.saveToFile(dataFile, data);
            FileUtils.saveToFile(hashFile, md5);
        }
    } catch(Exception e) {
        e.printStackTrace();
    }
}

Note: In this case, MD5 hashing is used to generate a hash file for each stored data file. Using this hash file, you can check if the newly generated data differs from the corresponding one already stored in the cache, preventing an unnecessary overwriting.


Load messages with deserialization

Copy link

When your user enters a chat to view their message history, load saved messages from the cache.

// Loading messages with deserialization
public void load(String channelUrl) {
    try {
        File appDir = new File(mContext.getCacheDir(), SendBird.getApplicationId());
        appDir.mkdirs();

        File dataFile = new File(appDir, TextUtils.generateMD5(SendBird.getCurrentUser().getUserId() + channelUrl) + ".data");

        String content = FileUtils.loadFromFile(dataFile);
        String [] dataArray = content.split("\n");

        // Load the channel instance.
        mChannel = (GroupChannel) GroupChannel.buildFromSerializedData(Base64.decode(dataArray[0], Base64.DEFAULT | Base64.NO_WRAP));

        // Add the loaded messages to the currently displayed message list.
        for(int i = 1; i < dataArray.length; i++) {
            mMessageList.add(BaseMessage.buildFromSerializedData(Base64.decode(dataArray[i], Base64.DEFAULT | Base64.NO_WRAP)));
        }

        notifyDataSetChanged();
    } catch(Exception e) {
        // Nothing to load.
    }
}

After receiving an updated message list from Sendbird server, clear the current message list and replace it with the updated list. In effect, messages from the cache are overwritten almost instantly if the user's connection is normal.


Save and load channels

Copy link

We recommend that you only cache group channels in a local file rather than open channels. The property values and participant status of open channels can be frequently changed depending on your use case, and you might go through difficulty in syncing the local file with the changes.

The process of caching channels is similar to caching messages. For the sake of brevity, the following code is provided without additional explanations.

Note: In group channels, information associated with them can be updated or the current user might leave them anytime. To keep your cache synced with data in Sendbird server, your client app should check changes to the channels regularly and apply the changes to the cache. You can retrieve change logs of the current user's group channels by using getMyGroupChannelChangeLogsByToken() or getMyGroupChannelChangeLogsByTimestamp() method, with which you can manage cache updates.

// Saving serialized group channels
public void save() {
    try {
        StringBuilder sb = new StringBuilder();
        if (mChannelList != null && mChannelList.size() > 0) {
            // Convert current channel into a String.
            GroupChannel channel = null;
            for (int i = 0; i < Math.min(mChannelList.size(), 100); i++) {
                channel = mChannelList.get(i);
                sb.append("\n");
                sb.append(Base64.encodeToString(channel.serialize(), Base64.DEFAULT | Base64.NO_WRAP));
            }
            // Remove first newline.
            sb.delete(0, 1);

            String data = sb.toString();
            String md5 = TextUtils.generateMD5(data);

            // Save the data into file.
            File appDir = new File(mContext.getCacheDir(), SendBird.getApplicationId());
            appDir.mkdirs();

            File hashFile = new File(appDir, TextUtils.generateMD5(SendBird.getCurrentUser().getUserId() + "channel_list") + ".hash");
            File dataFile = new File(appDir, TextUtils.generateMD5(SendBird.getCurrentUser().getUserId() + "channel_list") + ".data");

            try {
                String content = FileUtils.loadFromFile(hashFile);
                // If data has not been changed, do not save.
                if (md5.equals(content)) {
                    return;
                }
            } catch(IOException e) {
                // File not found. Save the data.
            }

            FileUtils.saveToFile(dataFile, data);
            FileUtils.saveToFile(hashFile, md5);
        }
    } catch(Exception e) {
        e.printStackTrace();
    }
}

// Loading group channels with deserialization.
public void load() {
    try {
        File appDir = new File(mContext.getCacheDir(), SendBird.getApplicationId());
        appDir.mkdirs();

        File dataFile = new File(appDir, TextUtils.generateMD5(SendBird.getCurrentUser().getUserId() + "channel_list") + ".data");

        String content = FileUtils.loadFromFile(dataFile);
        String [] dataArray = content.split("\n");

        // Add the loaded channels to the currently displayed channel list.
        for(int i = 0; i < dataArray.length; i++) {
            mChannelList.add((GroupChannel) BaseChannel.buildFromSerializedData(Base64.decode(dataArray[i], Base64.DEFAULT | Base64.NO_WRAP)));
        }

        notifyDataSetChanged();
    } catch(Exception e) {
        // Nothing to load.
    }
}