Recycler chat Pagination добавить новое сообщение в начало - PullRequest
2 голосов
/ 12 марта 2019

Я работаю над приложением чата, в котором мне нужно показать обратную нумерацию страниц и показать предыдущий чат пользователя, когда пользователь прокручивает вверх.

Я сначала загружаю данные из базы SQLite, чтобы показать последние 10 сообщений пользователя.

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;
}

Затем я добавляю курсор к пользовательскому 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);
    }
}

Я также сделал RecyclerView и LayoutManager настройки, подобные этой

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

При первой загрузке он получает всего 10 результатов из локальной базы данных, но как только он загружается на экран первым, он загружается в правильном порядке (последнее сообщение в конце и старшее вверху). Но RecyclerView не прокручивается внизу автоматически. В начале он загружается сверху, а при прокрутке вызывает следующий метод.

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;
            }
        }
    }
});

И загружает еще один на экран.

Проблемы в коде

  • Когда установлено layoutManager.setStackFromEnd(true); без layoutManager.setReverseLayout(true);, нумерация страниц работает внизу последнего сообщения, а также добавляется новое сообщение внизу
    • Когда установлено layoutManager.setReverseLayout(true);, нумерация страниц работает должным образом, но новое сообщение накладывается поверх самого старого сообщения.

enter image description here

Обновление : я заметил, что мое самое новое сообщение имеет индексный номер в массиве [0] и мое последнее сообщение после прокрутки к самому старому сообщению [21]. Поэтому, когда я набираю новое сообщение в своем окне чата, оно присваивается значению [22] в массиве и отображается над самым старым сообщением вверху, а не внизу экрана.

enter image description here

Ответы [ 2 ]

2 голосов
/ 15 марта 2019

Всякий раз, когда вы добавляете новый элемент на экран чата, не нажимайте message.add(Video);, вместо этого добавьте элемент message.add(0,Video);, который добавит элементы в нижней части экрана, а затем в верхнюю часть экрана. Он будет добавлен в начальную позицию массива, т.е. [0].

0 голосов
/ 12 марта 2019

Обновление

Теперь я думаю, проблема в вашем запросе к базе данных. Я предполагаю, что всякий раз, когда вводится новое сообщение, оно сохраняется в базе данных с самым высоким значением ID, что делает его самым последним в вашей организации таблицы базы данных. Следовательно, getLimitUserChat никогда не должен возвращать последнее сообщение, если вы правильно устанавливаете смещение.


Я не знаю, что делает функция dataBaseAsync.execute. Я предполагаю, что он добавляет больше элементов в ArrayList и вызывает notifyDateSetChanged.

Следовательно, данные должны быть заполнены в вашем RecyclerView в правильном порядке, если добавление недавно извлеченных данных в ArrayList является правильным. Однако вы также можете заметить, что каждый раз, когда добавляются новые разбитые на страницы данные, ваш RecyclerView может прокручиваться вниз, так как включен обратный макет, что может быть нежелательно для приложения чата.

Следовательно, чтобы сохранить RecyclerView в том же месте перед загрузкой новых данных, вам нужно сохранить состояние RecyclerView и восстановить состояние при получении новых данных. Вот код для сохранения состояния RecyclerView и возврата в то же состояние.

// Save state
private Parcelable recyclerViewState;
recyclerViewState = recyclerView.getLayoutManager().onSaveInstanceState();

// Restore state
recyclerView.getLayoutManager().onRestoreInstanceState(recyclerViewState);

И я хотел бы предложить вам установить LayoutManager следующим образом.

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

Пожалуйста, проверьте, правильно ли заполнен ArrayList (т.е. новые данные вверху списка и старые данные внизу).

Надеюсь, это поможет!

Пожалуйста, удалите из вашего onPostExecute следующее.

if (message.size() > 2){
    recyclerView.smoothScrollToPosition(message.size()-1);
} else {
    recyclerView.smoothScrollToPosition(layoutManager.getItemCount());
}

А также добавить необходимые null проверки в preExecute.

...