امکانات پیشرفته چت - قسمت اول

دقت کنید که این مستند مخصوص نیازمندی‌های چت است و برای رقابت آنلاین هیچ کاربردی ندارد.

در اتصال ساده و ارسال پیام دیدیم که چگونه می‌توانیم به یک کاربر پیام ارسال کنیم و پیام‌هایی که توسط کاربران دیگر به دست ما می‌رسد را نمایش دهیم. در این مستند خواهیم دید که چگونه می‌توانیم به اپلیکیشن چت خود امکانات پیشرفته، مانند ساخت چت گروهی، دعوت کاربران به گروه خود، حذف کاربران از گروه، دریافت پیام‌های آفلاین و … را اضافه کنیم.

پیش‌نیازها

  1. در صورتی که با سرویس بلادرنگ آشنایی ندارید، به معرفی سرویس بلادرنگ مراجعه کنید.
  2. در صورتی که هنوز با تنظیمات پنل سرویس بلادرنگ آشنا نشده اید، به تنظیمات پنل سرویس بلادرنگ مراجعه کنید.
  3. اگر هنوز SDK اندروید را راه‌اندازی نکرده‌اید، به راه‌اندازی SDK اندروید مراجعه کنید.
  4. در صورتی که با نحوه ایجاد یک چت ساده به کمک سرویس بلادرنگ آشنایی ندارید، مستند اتصال ساده و ارسال پیام را حتما مطالعه کنید.

نکات مهم

توجه کنید که برای آنکه بتوانید هر یک از سرویس‌های گفته شده در ادامه این مستند را به درستی فراخوانی کنید، و کار مورد انتظار شما را انجام دهد، باید نکات زیر را دقت کنید:

  1. کاربر خود را مطابق با مستند اتصال ساده و ارسال پیام به سرویس بلادرنگ بکتوری وصل کرده باشید. زیرا تمامی پیام‌های عضویت، ساخت گروه و … بر روی ارتباط بازی که بکتوری برقرار است کار می‌کنند و بدون آن خطا می‌دهند.
  2. برخی اعمال فقط توسط Owner گروه امکان‌پذیر است، که بر روی هر سرویسی که از این نوع باشد، این نکته یادآوری شده است.
  3. در قسمت اول از امکانات پیشرفته چت، ما تمام کارهایی که کاربر شما می‌تواند انجام دهد و در واقع محرک آن کاربر شماست، را بیان کرده‌ایم. برای مثال دعوت کردن یک عضو به گروهی که کاربر شما Owner آن است. حالت برعکس که کاربر شما خود کسی باشد که دعوت شده، در مستند بعدی که قسمت دوم چت پیشرفته است، پوشش داده شده است.
  4. همه اتفاقاتی که برای کاربر CurrentUser در SDK در گروه‌هایی که عضویت دارد، می‌افتد، از طریق Listener به شما خبر داده می‌شود که در قسمت دوم این مستند می‌توانید آنها را مشاهده کنید.

ساخت گروه چت

اولین نیاز برای یک اپلیکیشن چت جدی، امکان ساخت گروه برای چت است. یک گروه چت به تعدادی کاربر گفته می‌شود، که همگی اعضا همه پیام‌های دریافتی و ارسالی را می‌بییند. گروه توسط یک کاربر ساخته می‌شود و کاربر سازنده به عنوان صاحب (Owner) گروه می‌باشد. امکان Owner بودن می‌تواند به افراد دیگر انتقال یابد که در ادامه گفته خواهد شد.

برای ساخت یک گروه، در اپلیکیشن اندروید خود کافیست کد زیر را اجرا کنید:

// Get Realtime api
BacktoryRealtimeAndroidApi backtoryApi = BacktoryRealtimeAndroidApi.getInstance();

// Create the group
backtoryApi.createChatGroupAsync("MyGroup", ChatGroupType.Private,
        new BacktoryCallBack<ChatGroupCreationResponse>() {
    @Override
    public void onResponse(BacktoryResponse<ChatGroupCreationResponse> response) {
        // Check if creation was successful or not
        if (response.isSuccessful()) {
            Log.d("TAG", "Group created Successfully with id: "
                    + response.body().getGroupName());
        } else {
            Log.d("TAG", "Group create failed with code: "
                    + response.code()
                    + " and message: "
                    + response.message());
        }
    }
});

در مثال بالا ما گروه Private ساختیم. گروه‌ها بر دو نوع هستند:

مهم: محدودیت تعداد اعضای گروه در حال حاضر ۵۰ نفر است.

لیست گروه‌های من

در اپلیکیشن‌های چت مانند Telegram، اولین کاری که با باز شدن اپلیکیشن انجام می‌شود، این است که لیست گروه‌های شما نمایش داده می‌شود. بنابر این لازم است به طریقی بتوانید لیست گروه‌های کاربران را دریافت کنید.

نمونه کد زیر به شما اجازه می‌دهد این لیست را دریافت کرده و log کنید:

// Get realtime api
BacktoryRealtimeAndroidApi backtoryApi = BacktoryRealtimeAndroidApi.getInstance();

// Get list of groups
backtoryApi.requestListOfChatGroupsAsync(new BacktoryCallBack<ChatGroupsListResponse>() {
    @Override
    public void onResponse(BacktoryResponse<ChatGroupsListResponse> response) {
        // Check if list is retrieved successfully
        if (response.isSuccessful()) {
            Log.d("TAG", "List of my groups is:");
            List<ChatGroupInfo> groups = response.body().getGroupInfoList();
            for (int i = 0; i < groups.size(); i++) {
                Log.d("TAG", i + ". " + groups.get(i).getGroupId() + " -> "
                        + groups.get(i).getGroupName());
            }
        } else {
            Log.d("TAG", "Fetching list of groups failed with code: "
                    + response.code()
                    + " and message: "
                    + response.message());
        }
    }
});

دریافت لیست اعضای گروه

اگر با اپلیکیشن‌های چت مانند تلگرام یا WhatsApp کار کرده باشید و در گروهی عضو باشید، می‌بینید که با کلیک بر روی نام یا آیکون گروه، می‌توانید لیست اعضای گروه را مشاهده کنید. برای این کار در بکتوری کافیست با داشتن شناسه GroupId لیست اعضای گروه را درخواست دهید.

کد زیر با فرض اینکه شناسه گروه را به کمک سرویس لیست گروه‌ها مطابق مثال قبل به دست آورده‌اید، لیست اعضای آن گروه را از بکتوری دریافت می‌کند:

// Get realtime api
BacktoryRealtimeAndroidApi backtoryApi = BacktoryRealtimeAndroidApi.getInstance();

// Get group members after connection is Successful
backtoryApi.requestListOfChatGroupMembersAsync("<YOUR-GROUP-ID-HERE>",
        new BacktoryCallBack<ChatGroupMembersListResponse>() {
    @Override
    public void onResponse(BacktoryResponse<ChatGroupMembersListResponse> response) {
        // Check if list is retrieved successfully
        if (response.isSuccessful()) {
            Log.d("TAG", "Group id is " + response.body().getGroupId());
            List<ChatGroupMember> members = response.body().getGroupMemberList();
            for (int i = 0; i < members.size(); i++) {
                Log.d("TAG", i + ". " + members.get(i).getUserId() + " -> "
                        + members.get(i).getRole());
            }
        } else {
            Log.d("TAG", "Fetching list of group failed with code: "
                    + response.code()
                    + " and message: "
                    + response.message());
        }
    }
});

همانطور که در کد دیده می‌شود، جواب لیست اعضای گروه فیلدی به نام GroupMembers دارد که هر عضو یک شناسه UserId و یک نقش (Role) دارد. مقادیری که برای نقش وجود دارد دو حالت است:

افزودن عضو به گروه

جهت فراخوانی این سرویس، یا گروه مورد نظر شما باید Public باشد و یا کاربر CurrentUser ادمین آن گروه باشد.

از آنجایی که گروه بدون کاربران عضو بی‌معنی است، شما باید بتوانید عضوی به گروه خود اضافه کنید. برای این کار نیاز است تا شناسه GroupId و UserId را بدانید.

// Get realtime api
BacktoryRealtimeAndroidApi backtoryApi = BacktoryRealtimeAndroidApi.getInstance();

// Adding a user to a group after connection is Successful
backtoryApi.addMemberToChatGroupAsync("<YOUR-GROUP-ID-HERE>", "<MEMBER-USER-ID-HERE>",
        new BacktoryCallBack<Void>() {
            @Override
            public void onResponse(BacktoryResponse<Void> response) {
                // Check if addition is done successfully
                if (response.isSuccessful()) {
                    Log.d("TAG", "Added Successfully.");
                } else {
                    Log.d("TAG", "Operation failed with code: "
                            + response.code()
                            + " and message: "
                            + response.message());
                }
            }
        });

حذف یک کاربر از یک گروه

این امکان فقط برای مدیر یک گروه Private وجود دارد، و از آنجایی که در یک گروه Public همه کاربران می‌توانند دوباره عضو شوند، حذف کردن آنها معنی ندارد.

جهت حذف یک کاربر، در صورتی که کاربر فعلی SDK صاحب (Owner) گروه باشد، می‌تواند با دادن شناسه UserId یک کاربر را از گروه دلخواه خود حذف کند. نمونه کد زیر یک کاربر فرضی را از یک گروه فرضی حذف می‌کند:

// Get realtime api
BacktoryRealtimeAndroidApi backtoryApi = BacktoryRealtimeAndroidApi.getInstance();

// Removing a user from a group after connection is Successful
backtoryApi.removeMemberFromChatGroupAsync("<YOUR-GROUP-ID-HERE>",
        "<MEMBER-USER-ID-HERE>", new BacktoryCallBack<Void>() {
            @Override
            public void onResponse(BacktoryResponse<Void> response) {
                // Check if removal is done successfully
                if (response.isSuccessful()) {
                    Log.d("TAG", "Removed Successfully.");
                } else {
                    Log.d("TAG", "Operation failed with code: "
                            + response.code()
                            + " and message: "
                            + response.message());
                }
            }
        });

ارسال پیام در گروه

در صورتی که می‌خواهید از طریق کاربر فعلی دستگاه (CurrentUser) به یک گروه پیامی ارسال کنید، کافیست تابع SendMessage را فراخوانی کنید. این تابع از ورودی شناسه GroupId و متن پیام را دریافت می‌کند. نمونه کد ساده‌ای که این کار را انجام دهد به صورت زیر است:

// Get realtime api
BacktoryRealtimeAndroidApi backtoryApi = BacktoryRealtimeAndroidApi.getInstance();

// Removing a user from a group after connection is Successful
backtoryApi.sendChatToGroupAsync("<YOUR-GROUP-ID-HERE>", "Hello everybody",
        new BacktoryCallBack<Void>() {
            @Override
            public void onResponse(BacktoryResponse<Void> response) {
                // Check if message is sent successfully
                if (response.isSuccessful()) {
                    Log.d("TAG", "Message Sent Successfully.");
                } else {
                    Log.d("TAG", "Operation failed with code: "
                            + response.code()
                            + " and message: "
                            + response.message());
                }
            }
        });

دادن دسترسی Owner به کاربر عضو

این سرویس فقط برای Owner فعلی سیستم قابل استفاده است. یعنی CurrentUser در SDK باید ادمین گروه مورد نظر باشد.

گاهی نیاز دارید که دسترسی ادمین گروه (Owner) را به بیش از یک نفر بدهید. در صورتی که کاربر فعلی یعنی CurrentUser ادمین گروه باشد می‌تواند با کدی شبیه زیر دسترسی ادمین گروه به کاربر دیگری بدهد.

// Get realtime api
BacktoryRealtimeAndroidApi backtoryApi = BacktoryRealtimeAndroidApi.getInstance();

// Add a new admin after connection is Successful
backtoryApi.addOwnerToChatGroupAsync("<YOUR-GROUP-ID-HERE>", "<YOUR-USER-ID-HERE>",
        new BacktoryCallBack<Void>() {
            @Override
            public void onResponse(BacktoryResponse<Void> response) {
                // Check if addition is done successfully
                if (response.isSuccessful()) {
                    Log.d("TAG", "User is set as new admin successfully.");
                } else {
                    Log.d("TAG", "Operation failed with code: "
                            + response.code()
                            + " and message: "
                            + response.message());
                }
            }
        });

دعوت کاربران به یک گروه (Invite)

جهت فراخوانی این سرویس، یا گروه مورد نظر شما باید Public باشد و یا کاربر CurrentUser ادمین آن گروه باشد.

سرویس دعوت کردن کاربران، پیامی مبنی بر دعوت شدن به یک گروه را برای کاربر مورد نظر شما ارسال خواهد کرد. کاربر دعوت شده باید دعوت اتفاق افتاده را بپذیرد و در صورت پذیرش، آن کاربر به گروه اضافه خواهد شد.

تفاوت این عمل با افزودن کاربر آن است که در حالت افزودن، کاربر حق انتخاب ندارد و بعد از آنکه وارد گروه می‌شود، باید آن را ترک کند و تا زمانی که اقدام به ترک کردن نکند، همه پیام‌های گروه به دست او خواهد رسید. در حالت دعوت، کاربر تا زمانی که دعوت را نپذیرد پیامی از گروه به دست او نخواهد رسید. لازم به ذکر است که از هر دعوت تنها یک بار می‌توان استفاده کرد و در صورتی که کاربر بعد از عضویت در گروه Private از آن خارج شود، برای عضویت مجدد باید دوباره دعوت شود.

نمونه کد زیر یک کاربر را به یک گروه دعوت می‌کند:

// Get Realtime api
BacktoryRealtimeAndroidApi backtoryApi = BacktoryRealtimeAndroidApi.getInstance();

// Add a new admin after connection is Successful
backtoryApi.inviteUserToChatGroupAsync("<YOUR-GROUP-ID-HERE>", "<YOUR-USER-ID-HERE>",
        new BacktoryCallBack<Void>() {
            @Override
            public void onResponse(BacktoryResponse<Void> response) {
                // Check if invitation is sent successfully
                if (response.isSuccessful()) {
                    Log.d("TAG", "Invitation is sent to backtory successfully.");
                } else {
                    Log.d("TAG", "Operation failed with code: "
                            + response.code()
                            + " and message: "
                            + response.message());
                }
            }
        });

عضویت در گروه دیگران

برای آنکه بتوانید در یک گروه عضو شوید باید یکی از دو حالت زیر درست باشد:

در صورتی که درخواست Invite برای اپلیکیشن (کاربر CurrentUser) ارسال شود، SDK بکتوری آن را از طریق مکانیزم Listener به شما اعلام خواهد کرد و می‌توانید اقدام مقتضی را انجام دهید. برای آشنایی دقیق با Listener های مربوط به چت به امکانات پیشرفته چت - بخش دوم مراجعه کنید.

در نهایت شما یک شناسه GroupId دارید که می‌خواهید در آن عضو شوید. به کمک تکه کد زیر می‌توانید در هر جای برنامه‌ی خود که هستید درخواست عضویت در یک گروه را بدهید:

// Get realtime api
BacktoryRealtimeAndroidApi backtoryApi = BacktoryRealtimeAndroidApi.getInstance();

// Join the group
backtoryApi.joinChatGroupAsync("<YOUR-GROUP-ID-HERE>", new BacktoryCallBack<Void>() {
    @Override
    public void onResponse(BacktoryResponse<Void> response) {
        // Check if join was successful or not
        if (response.isSuccessful()) {
            Log.d("TAG", "You joined the group successfully.");
        } else {
            Log.d("TAG", "Operation failed with code: "
                    + response.code()
                    + " and message: "
                    + response.message());
        }
    }
});

ترک یک گروه (Leave)

در صورتی که قصد خروج از یک گروه را دارید باید از این سرویس استفاده کنید. به محض خروج از یک گروه، دیگر پیام‌های آن گروه به دست شما نخواهد رسید. برای خروج از یک گروه باید شناسه GroupId را داشته باشید. با داشتن این شناسه، کافیست تکه کدی مانند زیر را اجرا کنید:

// Get Realtime api
BacktoryRealtimeAndroidApi backtoryApi = BacktoryRealtimeAndroidApi.getInstance();

// Leave the group
backtoryApi.leaveChatGroupAsync("<YOUR-GROUP-ID-HERE>", new BacktoryCallBack<Void>() {
    @Override
    public void onResponse(BacktoryResponse<Void> response) {
        // Check if leave was successful or not
        if (response.isSuccessful()) {
            Log.d("TAG", "You left the group successfully.");
        } else {
            Log.d("TAG", "Operation failed with code: "
                    + response.code()
                    + " and message: "
                    + response.message());
        }
    }
});

Owner گروهی که تنها یک owner دارد نمی‌تواند گروه را ترک کند و لذا در صورت تمایل به ترک گروه، باید پیش از انجام این کار فرد یا افراد دیگری را به عنوان owner گروه تعیین کند.

تاریخچه چت‌های یک گروه

زمانی که عضو یک گروه هستید، یکی از کارهای رایجی که می‌خواهید انجام دهید، این است که تاریخچه‌ی چت‌های آن گروه را ببینید. فرض بر این است که GroupId گروه مورد نظر را دانسته و پیام‌های آن گروه را از «تاریخ و ساعت» مشخصی به بعد دارید؛ به عنوان مثال، اگر هیچ پیامی از آن گروه را ندارید، منظور از این «تاریخ و ساعت» مشخص همان زمان حال می‌شود! در این صورت، کدی مانند زیر به شما بسته‌ای از پیام‌های گروه را که به ترتیب و بلافاصله قبل از آن تاریخ و ساعت قرار دارند، در اختیار شما قرار می‌دهد. در مورد این بسته جلوتر صحبت می‌کنیم.

// Get Realtime api
BacktoryRealtimeAndroidApi backtoryApi = BacktoryRealtimeAndroidApi.getInstance();

// Request group history
backtoryApi.requestGroupChatHistoryAsync("<YOUR-GROUP-ID-HERE>",
    Calendar.getInstance().getTimeInMillis(),
    new BacktoryCallBack<GroupChatHistoryResponse>() {
        @Override
        public void onResponse(BacktoryResponse<GroupChatHistoryResponse> response) {
            // Check if request was successful or not
            if (response.isSuccessful()) {
                List<ChatMessage> chatMessages = response.body().getChatMessageList();
                for(ChatMessage message : chatMessages) {
                    if (message instanceof SimpleChatMessage) {
                        SimpleChatMessage msg = (SimpleChatMessage) message;
                        Log.d("TAG", "Group message from " + msg.getSenderId() + ": "
                                + msg.getMessage());
                    }
                    else if (message instanceof UserAddedMessage) {
                        UserAddedMessage msg = (UserAddedMessage) message;
                        Log.d("TAG", "User " + msg.getAddedUserId()
                            + " is added to group by " + msg.getAdderUserId());
                    }
                    else if (message instanceof UserJoinedMessage) {
                        UserJoinedMessage msg = (UserJoinedMessage) message;
                        Log.d("TAG", "User " + msg.getUserId() + " joined the group.");
                    }
                    else if (message instanceof UserLeftMessage) {
                        UserLeftMessage msg = (UserLeftMessage) message;
                        Log.d("TAG", "User " + msg.getUserId() + " left the group.");
                    }
                    else if (message instanceof UserRemovedMessage) {
                        UserRemovedMessage msg = (UserRemovedMessage) message;
                        Log.d("TAG", "User " + msg.getRemovedUserId()
                            + " is removed by " + msg.getRemoverUserId());
                    }
                }
            } else {
                Log.d("TAG", "Operation failed with code: "
                        + response.code()
                        + " and message: "
                        + response.message());
            }
        }
    });

همان‌طور که مشاهده می‌کنید، تابع ()Calendar.getInstance().getTimeInMillis به ما زمان گذشته از تاریخ ۱ ژانویه‌ی ۱۹۷۰ را بر حسب میلی‌ثانیه می‌دهد و ما آن را به عنوان آرگومان تابع History می‌دهیم. پیام‌های بکتوری هم همگی یک مشخصه از جنس long به نام Date دارند که زمان ارسال پیام را بر حسب میلی‌ثانیه‌ی گذشته از تاریخ ۱ ژانویه‌ی ۱۹۷۰ نشان می‌دهد. با این حساب، با صدازدن متد بالا، همه‌ی پیام‌های این گروه را تا تاریخ و ساعت «آخرین پیام موجود در لیست» داریم و سری بعدی، کافیست که این متد را با تاریخ و ساعت همان آخرین پیام فراخوانی کنیم.

هم‌چنین، گفته شد که با هربار صدا زدن تابع بالا، یک بسته از پیام‌های گروه به دست ما می‌رسد. سایز این بسته حداکثر یک عدد ثابت است که این عدد ثابت سمت سرور تعیین می‌شود و هم‌اکنون برابر ۲۵ است. در صورتی که بیش از ۲۵ عدد پیام قبل از تاریخ و ساعت مشخص‌شده وجود داشته باشند، دقیقا ۲۵ پیام منتهی به تاریخ و ساعت مشخص‌شده بارگذاری می‌شوند و برای دسترسی به بقیه‌ی پیام‌ها، دوباره باید متد بالا را صدا کنیم (با تاریخ و ساعت جدید!). در غیر این‌صورت، چون پیام‌های منتهی به زمان مشخص‌شده کمتر یا مساوی ۲۵ تا هستند، همه‌ی آن‌ها با موفقیت دریافت می‌شوند.

تاریخچه چت‌های کاربر

مشابه قسمت قبل، یکی از کارهای رایج دیگر این است که تاریخچه‌ی چت‌های خود با یک کاربر خاص را ببینید. فرض بر اینست که UserId کاربر مورد نظر را دانسته و پیام‌های چت با او را از «تاریخ و ساعت» مشخصی به بعد دارید. به عنوان مثال، اگر هیچ پیامی از آن گروه را ندارید، منظور از این «تاریخ و ساعت» مشخص همان زمان حال می‌شود! در این صورت، کدی مانند زیر به شما بسته‌ای از پیام‌های چت با آن کاربر را که به ترتیب و بلافاصله قبل از آن تاریخ و ساعت قرار دارند، در اختیار شما قرار می‌دهد. ساختار این بسته‌ها به لحاظ تعداد از سناریوی مشابه در قسمت قبل پیروی می‌کند.

// Get Realtime api
BacktoryRealtimeAndroidApi backtoryApi = BacktoryRealtimeAndroidApi.getInstance();

// Request group history
backtoryApi.requestUserChatHistoryAsync("<RECEIVER-USER-ID-HERE>", Calendar.getInstance().getTimeInMillis(),
        new BacktoryCallBack<UserChatHistoryResponse>() {
            @Override
            public void onResponse(BacktoryResponse<UserChatHistoryResponse> response) {
                // Check if request was successful or not
                if (response.isSuccessful()) {
                    List<ChatMessage> chatMessages = response.body().getChatMessageList();
                    for(ChatMessage message : chatMessages) {
                        SimpleChatMessage msg = (SimpleChatMessage) message;
                        Log.d("TAG", "Group message from " + msg.getSenderId() + ": "
                                + msg.getMessage());
                    }
                } else {
                    Log.d("TAG", "Operation failed with code: "
                            + response.code()
                            + " and message: "
                            + response.message());
                }
            }
        });

دریافت پیام‌های Offline

وقتی یک کاربر به سرویس بلادرنگ اتصال پیدا می‌کند، می‌توانید پیام‌هایی را که در مدت وصل نبودنش به سرویس بلادرنگ بکتوری برای او ارسال شده است (اصطلاحا می‌گوییم پیام‌های Offline)، برای او نمایش دهید. برای این کار به طریق زیر اقدام کنید:

// Get Realtime api
BacktoryRealtimeAndroidApi backtoryApi = BacktoryRealtimeAndroidApi.getInstance();

// Request group history
backtoryApi.requestOfflineMessagesAsync(new BacktoryCallBack<OfflineMessageResponse>() {
    @Override
    public void onResponse(BacktoryResponse<OfflineMessageResponse> response) {
        // Check if request was successful or not
        if (response.isSuccessful()) {
            List<ChatMessage> chatMessages = response.body().getChatMessageList();
            for(ChatMessage message : chatMessages) {
                if (message instanceof SimpleChatMessage) {
                    SimpleChatMessage msg = (SimpleChatMessage) message;
                    Log.d("TAG", "Group message from " + msg.getSenderId() + ": "
                            + msg.getMessage());
                }
                else if (message instanceof UserAddedMessage) {
                    UserAddedMessage msg = (UserAddedMessage) message;
                    Log.d("TAG", "User " + msg.getAddedUserId()
                            + " is added to group by " + msg.getAdderUserId());
                }
                else if (message instanceof ChatInvitationMessage) {
                    ChatInvitationMessage msg = (ChatInvitationMessage) message;
                    Log.d("TAG", "Invitation to group " + msg.getGroupId()
                            + " by User " + msg.getCallerId());
                }
                else if (message instanceof UserJoinedMessage) {
                    UserJoinedMessage msg = (UserJoinedMessage) message;
                    Log.d("TAG", "User " + msg.getUserId() + " joined the group.");
                }
                else if (message instanceof UserLeftMessage) {
                    UserLeftMessage msg = (UserLeftMessage) message;
                    Log.d("TAG", "User " + msg.getUserId() + " left the group.");
                }
                else if (message instanceof UserRemovedMessage) {
                    UserRemovedMessage msg = (UserRemovedMessage) message;
                    Log.d("TAG", "User " + msg.getRemovedUserId() + " is removed by "
                            + msg.getRemoverUserId());
                }
            }
        } else {
            Log.d("TAG", "Operation failed with code: "
                    + response.code()
                    + " and message: "
                    + response.message());
        }
    }
});

در این‌جا هم پیام‌ها در بسته‌هایی به ما عرضه می‌شود که این بسته‌ها به لحاظ تعدادشان مشابه دو قسمت قبلی هستند.

نکته: پیام‌های درون بسته‌های دریافت شده در درخواست‌های history بر اساس زمان مرتب‌شده هستند و درایه‌ی صفرم آرایه از همه جدیدتر است. هم‌چنین، پیام‌های درون بسته‌های دریافت شده در درخواست offline نیز بر اساس زمان مرتب‌شده هستند؛ اما درایه‌ی صفرم آرایه از همه قدیمی‌تر است.

برای جا افتادن بهتر نحوه‌ی کار با درخواست آف‌لاین مثالی می‌زنیم. فرض کنید می‌خواهید برنامه‌ای مانند تلگرام پیاده‌سازی کنید که به هنگام بالا آمدن، همه‌ی پیام‌هایی را که به هنگام آف‌لاین بودن برای کاربر ارسال شده است، دریافت کند. برای این هدف باید آن‌قدر تابع requestOfflineMessagesAsync را صدا کند تا این‌که بسته‌ای با سایز کمتر از ۲۵ دریافت کند. در این حالت مطمئن می‌شوید که همه‌ی پیام‌های آف‌لاین را دریافت کرده‌اید. کد زیر این کار را انجام می‌دهد:

public int PAGE_SIZE = 25;
public List<ChatMessage> allMessages = new ArrayList<>();

public void fetchAllOfflineMessages() {
    BacktoryRealtimeAndroidApi.getInstance().requestOfflineMessagesAsync(
            new BacktoryCallBack<OfflineMessageResponse>() {
        @Override
        public void onResponse(BacktoryResponse<OfflineMessageResponse> response) {
            if (response.isSuccessful()) {
                OfflineMessageResponse newPage = response.body();
                allMessages.addAll(newPage.getChatMessageList());

                if (newPage.getChatMessageList().size() >= PAGE_SIZE) {
                    fetchAllOfflineMessages();
                }
            } else {
                Log.d("TAG", "failed; " + response.message());
            }
        }
    });
}

بعد از این‌که تابع بالا (احتمالا) چندین بار خودش را به صورت بازگشتی صدا می‌زند، در پایان آرایه‌ی allMessages به ترتیب شامل همه‌ی پیام‌های آف‌لاین خواهد بود. برای گرفتن همه‌ی پیام‌های history نیز تابعی بازگشتی مشابه بالا کافیست؛ فقط باید تاریخ آخرین پیام دریافتی را به عنوان آرگومان تابع بازگشتی بدهیم.

گام بعدی