java - 回收商聊天分页在顶部添加新消息

标签 java android sql android-recyclerview pagination

我正在开发一个聊天应用程序,我需要在其中显示反向分页并在用户向上滚动时显示用户之前的聊天记录。

我首先从 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);
    }
}

我也做了这样的RecyclerViewLayoutManager设置

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

最佳答案

每当您向聊天屏幕(数组列表)添加新项目时,不要使用 message.add(Video); 而是像这样在 0 位置添加项目 message.add(0,Video ); 这将在屏幕底部(数组列表顶部)添加项目,而不是在屏幕顶部(数组列表最后)添加项目。它将被添加到数组的起始位置,即 [0] 在您的情况下。

关于java - 回收商聊天分页在顶部添加新消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55115902/

相关文章:

java - 无法处理 EJB 类的业务接口(interface)

java - 使用stringbuilder和bufferedreader读取多个链接

java - 在显示警报对话框时是否可以阻止 UI 线程

mysql - 使用用户输入进行数据库规范化

java - FrameLayout 无法转换为 AbsListView Layout Params

java - 在将 CRUD 插入 TopComponent 后,CRUD 按钮不起作用

android - 如何使 SeparatedListAdapter 的节标题在滚动时推送上一节?

android - 图形布局调色板中缺少小部件(eclipse 上的 android)

mysql - 如何在 super 查询中使用子查询的结果?

sql - 多对多关系的替代方案