Recycler chat Pagination add new message at top

Ritu :

I am working on a chat app where I need to show reverse pagination and show the user's previous chat when the user scrolls up.

I am first loading data from SQLite database to show the last 10 messages of the user.

public Cursor getLimitUserChat(String UserID,int nextChat){
    Log.d(TAG,"Get Single Row Running= ID "+UserID);
    database=this.getReadableDatabase();
    cursor = database.rawQuery("SELECT * FROM " + TABLE_NAME + " Where "+ RECEIVER_USERID +"="+ UserID+" ORDER BY ID DESC LIMIT 10 OFFSET "+nextChat,null);
    return cursor;
}

Then I add a cursor to the custom ArrayList

private  class databaseAsync extends AsyncTask<Void,Void,Void> {
    boolean checkDB_Exist,chatItemsCounts;
    private Parcelable recyclerViewState;
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        Log.d(TAG,"Chat Database Function "+databaseChatValue);
        if (databaseChatValue == 0){
            message.clear();
        }
        recyclerViewState = recyclerView.getLayoutManager().onSaveInstanceState();


        //chatCursor=chat_database.getUserChat(UserID_Intent);
        chatCount = chat_database.getUserChatCount(UserID_Intent);
        chatCursor=chat_database.getLimitUserChat(UserID_Intent,databaseChatValue);
        checkDB_Exist=functions.DatabaseExist(getActivity(),"CHAT_DATABASE.DB");
        chatItemsCounts=chatCursor.getCount()>0;
        chatCursor.moveToFirst();
        Log.d(TAG,"Chat Cursor "+ chatCursor.getCount());
        Log.d(TAG,"Total Chat Counts "+chatCount);
    }

    @Override
    protected Void doInBackground(Void... voids) {
        if (checkDB_Exist && chatCursor.getCount()>0 && chatCursor.getString(chatCursor.getColumnIndex("RECEIVER_USER_ID")).equals(UserID_Intent)) {
            chatCursor.moveToFirst();
            do {
                database_rowID = chatCursor.getInt(chatCursor.getColumnIndex("ID"));
                database_userID = chatCursor.getString(chatCursor.getColumnIndex("USER_ID"));
                database_RoomName = chatCursor.getString(chatCursor.getColumnIndex("ROOM_NAME"));
                database_ReceiverID = chatCursor.getString(chatCursor.getColumnIndex("RECEIVER_USER_ID"));
                database_MessageType = chatCursor.getString(chatCursor.getColumnIndex("MESSAGE_TYPE"));
                database_Message = chatCursor.getString(chatCursor.getColumnIndex("USER_MESSAGE"));
                database_MsgFrom = chatCursor.getString(chatCursor.getColumnIndex("SENDER_NAME"));
                database_MsgTo = chatCursor.getString(chatCursor.getColumnIndex("RECEIVER_NAME"));
                database_TimeStamp = chatCursor.getString(chatCursor.getColumnIndex("TIME_STAMP"));
                database_FCMfrom = chatCursor.getString(chatCursor.getColumnIndex("SENDER_TOKEN"));
                database_FCMto = chatCursor.getString(chatCursor.getColumnIndex("RECEIVER_TOKEN"));
                database_LocalPath = chatCursor.getString(chatCursor.getColumnIndex("DOWNLOADED_AT"));
                database_PhoneFrom = chatCursor.getString(chatCursor.getColumnIndex("MY_PHONE"));
                database_PhoneTo = chatCursor.getString(chatCursor.getColumnIndex("OTHER_PHONE"));

                Log.d(TAG, "Value Of Database Message String = " + database_Message);
                Log.d(TAG, "Row ID of Database " + database_rowID);
                // Check Message Type
                if (true) {

                    if (database_MessageType.equals("Image")) {
                        Log.d(TAG, "Message Type Is Image");
                        Log.d(TAG, "Row ID of Database " + database_rowID);
                        Chat_Wrapper image = new Chat_Wrapper(null, database_Message, null, null, null, null, null, database_TimeStamp, database_PhoneTo, UserImage_Intent, database_MsgFrom, null, null, database_rowID);
                        message.add(image);
                    } else if (database_MessageType.equals("GIF")) {
                        Chat_Wrapper image = new Chat_Wrapper(null, database_Message, null, null, null, null, null, database_TimeStamp, database_PhoneTo, UserImage_Intent, database_MsgFrom, null, null, database_rowID);
                        message.add(image);
                    } else if (database_MessageType.equals("Video") || (database_MessageType.equals("Youtube_Video"))) {
                        Log.d(TAG, "Message Type Is Video");
                        Chat_Wrapper Video = new Chat_Wrapper(null, null, database_Message, null, null, null, null, database_TimeStamp, database_PhoneTo, UserImage_Intent, database_MsgFrom, null, null, database_rowID);
                        message.add(Video);
                    } else if (database_MessageType.equals("Audio")) {
                        Log.d(TAG, "Message Type Is Audio");
                        Chat_Wrapper Audio = new Chat_Wrapper(null, null, null, database_Message, null, null, null, database_TimeStamp, database_PhoneTo, UserImage_Intent, database_MsgFrom, null, null, database_rowID);
                        message.add(Audio);
                    } else if (database_MessageType.equals("Documents")) {
                        Log.d(TAG, "Message Type Is Documents");
                        Chat_Wrapper Docs = new Chat_Wrapper(null, null, null, null, database_Message, null, null, database_TimeStamp, database_PhoneTo, UserImage_Intent, database_MsgFrom, null, null, database_rowID);
                        message.add(Docs);
                    } else if (database_MessageType.equals("Location")) {
                        Log.d(TAG, "Message Type Is Location");
                        Chat_Wrapper Location = new Chat_Wrapper(null, null, null, null, null, database_Message, null, database_TimeStamp, database_PhoneTo, UserImage_Intent, database_MsgFrom, null, null, database_rowID);
                        message.add(Location);
                    } else if (database_MessageType.equals("Geofence")) {
                        Log.d(TAG, "Message Type Is Geofence");
                        Chat_Wrapper GeoFence = new Chat_Wrapper(null, null, null, null, null, null, null, Chat_TimeStamp, UserPhone_Intent, UserImage_Intent, database_MsgFrom, database_Message, null, database_rowID);
                        message.add(GeoFence);
                    } else if (database_MessageType.equals("Contacts")) {
                        Log.d(TAG, "Message Type Is Contacts");
                        Chat_Wrapper Contacts = new Chat_Wrapper(null, null, null, null, null, null, database_Message, database_TimeStamp, database_PhoneTo, UserImage_Intent, database_MsgFrom, null, null, database_rowID);
                        message.add(Contacts);
                    } else if (database_MessageType.equals("Online Media")) {
                        Log.d(TAG, "Message Type Is Online Media");
                        Chat_Wrapper Online_Media = new Chat_Wrapper(null, null, database_Message, null, null, null, null, database_TimeStamp, database_PhoneTo, UserImage_Intent, database_MsgFrom, null, null, database_rowID);
                        message.add(Online_Media);
                    } else if (database_MessageType.equals("Text")) {
                        Log.d(TAG, "Message Type Is Text");
                        Chat_Wrapper text = new Chat_Wrapper(database_Message, null, null, null, null, null, null, database_TimeStamp, database_PhoneTo, UserImage_Intent, database_MsgFrom, null, null, database_rowID);
                        message.add(text);
                    } else if (database_MessageType.equals("Google_Search")) {
                        Log.d(TAG, "Message Type Is Google Search");
                        List<String> gSearch = new ArrayList<>();
                        gSearch.add(database_Message);
                        Chat_Wrapper GoogleSearch = new Chat_Wrapper(null, null, null, null, null, null, null, database_TimeStamp, database_PhoneTo, UserImage_Intent, database_MsgFrom, null, gSearch, database_rowID);
                        message.add(GoogleSearch);
                    }
                }
                }
                while (chatCursor.moveToNext()) ;
                Room_Name_Intent = database_RoomName;
                chatCursor.close();
                boolean value = chat_database.isDatabaseClose();
                Log.d(TAG, "Value Of Database Close or Not " + value);
            }

        return null;
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        super.onPostExecute(aVoid);
        recyclerView.getLayoutManager().onRestoreInstanceState(recyclerViewState);
        adapter.notifyDataSetChanged();
        if (message.size()>2){
            recyclerView.smoothScrollToPosition(message.size()-1);
        }else {
            recyclerView.smoothScrollToPosition(layoutManager.getItemCount());
        }
        Log.d(TAG,"Chat Database  "+database_OFFSET);
        database_OFFSET +=10;
        Log.d(TAG,"Chat Database  "+database_OFFSET);
    }
}

I also have made RecyclerView and LayoutManager settings like this

layoutManager.setStackFromEnd(true);
layoutManager.setReverseLayout(true);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);

At first load, it fetches total 10 result from the local database but as soon as it loads into screen first, it loads in the correct order (Latest message at the end and older at the top). But RecyclerView doesn't scroll at bottom automatically. At the start, it loads from the top and when I scroll it calls the following method.

recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        super.onScrollStateChanged(recyclerView, newState);
        if (newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL){
            Log.d(TAG,"Hello I am scrolling screen ");
            isScrolling = true;
        }
    }

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        currentVisible = layoutManager.getChildCount();
        TotalItems = layoutManager.getItemCount();
        scrolledOutItems = layoutManager.findFirstVisibleItemPosition();
        int check = TotalItems - currentVisible+scrolledOutItems;
        Log.d(TAG,"Current Visible = "+currentVisible+" Total = "+TotalItems+" Scrolled Out Items = "+scrolledOutItems+" Check = "+check);

        if (isScrolling && TotalItems == currentVisible + scrolledOutItems ){
            Log.d(TAG,"Fetch Data Now "+databaseChatValue);
            if (chatCount > databaseChatValue){
                Log.d(TAG,"Total item count is more than database = "+chatCount +" "+databaseChatValue);
                new databaseAsync().execute();
                isScrolling = false;
            }
        }
    }
});

And loads another into screen.

Issues In Code

  • When Set layoutManager.setStackFromEnd(true); without layoutManager.setReverseLayout(true); pagination works at bottom of last message and also new message adds at bottom
    • When Set layoutManager.setReverseLayout(true); pagination works as required but new message stacked at top of the oldest message.

enter image description here

Update :I notice my newest message has index number in array [0] and my last message after scrolls to oldest message [21]. So when i typed new message into my chat box it assign to [22] in array and shows above oldest message at top not at the bottom of the screen.

enter image description here

androidXP :

Whenever you add new item into you chat screen dont go with message.add(Video); instead add item message.add(0,Video); which will add items at bottom of screen then adding top of the screen. It will be add into start position of array i.e. [0].

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=151457&siteId=1