У меня есть RecyclerView
, который я использую для чата, и все работает, но обратная нумерация страниц, такая как загрузка истории чата из локальной SQLite
базы данных, не работает, как приложение Whatsapp или Telegram.
При первой загрузке язагружаю историю чата пользователя по умолчанию только с 10 сообщениями из локальной SQLite
базы данных.Если я потяну сверху, он загружает следующие (более старые) 10 сообщений и т. Д.
Я использую Firebase Realtime Database
в качестве нашего сервера чата, который синхронизируется в реальном времени, а когда пользователь отправляет новое сообщение, он получает сообщение и добавляет в SQLite Database
затем загружается в самое старое сообщение, как показано на рисунке ниже
![enter image description here](https://i.stack.imgur.com/4QF6E.jpg)
Основной класс
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.chat_screen_main_fragment, container, false);
setRetainInstance(true);
// RECYCLER VIEW
recyclerView = v.findViewById(R.id.Chat_Screen_Message_List);
layoutManager = new LinearLayoutManager(getActivity());
layoutManager.scrollToPosition(message.size() - 1);
if (adapter == null) {
adapter = new Chat_Adapter(getActivity(), message);
}
layoutManager.setStackFromEnd(true);
layoutManager.setReverseLayout(true);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);
chat_database=new Chat_Database(getActivity());
// Testing For Pagination
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 "+OFFSET);
if (chatCount > OFFSET){
Log.d(TAG,"Total item count is more than database = "+chatCount +" "+OFFSET);
new databaseAsync().execute();
isScrolling = false;
}
}
}
});
}
//THIS METHOD WILL FETCH ALL MESSAGES FROM FIREBASE DATABASE
private synchronized void append_chat_conversation(DataSnapshot dataSnapshot) {
Iterator iterator = dataSnapshot.getChildren().iterator();
while (iterator.hasNext()) {
// NOW GET ALL DATA FROM FIREBASE DATABASE AND SAVE IT INTO STRINGS THEN CHECK EACH BY ITS MESSAGE TYPE
Chat_Msg = (String) ((DataSnapshot) iterator.next()).getValue();
Chat_FROM = (String) ((DataSnapshot) iterator.next()).getValue();
Chat_TO = (String) ((DataSnapshot) iterator.next()).getValue();
Chat_Type= (String) ((DataSnapshot) iterator.next()).getValue();
if (Chat_Type.equals("Local_Image")) {
long id = chat_database.Insert_Chat(Session.getUserID(), "Image", Chat_Msg);
if (id==0){
return;
}
Chat_Wrapper image = new Chat_Wrapper(null, Chat_Msg, null, null, null, null, null, Chat_TimeStamp,id );
message.add(image);
adapter.notifyDataSetChanged();
recyclerView.post(new Runnable() {
@Override
public void run() {
recyclerView.smoothScrollToPosition(adapter.getItemCount());
}
});
} else if (Chat_Type.equals("Typed_Message")){
long id=chat_database.Insert_Chat(Session.getUserID(),"Text", Chat_Msg);
//Adding Chat Data Into Database
if (id==0){
return;
}
Chat_Wrapper chat_wrapper = new Chat_Wrapper(Chat_Msg, null, null, null, null, null, null, Chat_TimeStamp,id);
message.add(chat_wrapper);
adapter.notifyDataSetChanged();
recyclerView.post(new Runnable() {
@Override
public void run() {
recyclerView.smoothScrollToPosition(adapter.getItemCount());
}
});
}
}
//FETCHING DATA FROM LOCAL DATABASE
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 "+OFFSET);
if (OFFSET == 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,OFFSET);
chatCursor.moveToFirst();
}
@Override
protected Void doInBackground(Void... voids) {
if (checkDB_Exist && chatCursor.getCount()>0) {
chatCursor.moveToFirst();
do {
database_rowID = chatCursor.getInt(chatCursor.getColumnIndex("ID"));
database_userID = chatCursor.getString(chatCursor.getColumnIndex("USER_ID"));
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"));
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("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);
}
}
}
while (chatCursor.moveToNext()) ;
chatCursor.close();
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
recyclerView.getLayoutManager().onRestoreInstanceState(recyclerViewState);
adapter.notifyDataSetChanged();
OFFSET +=10;
}
}
Адаптер чата
public class Chat_Adapter extends RecyclerView.Adapter<Chat_Adapter.ViewHolder> {
Chat_Wrapper chat_wrapper;
//ARRAYLIST OF MESSAGES OBJECT CONTAINING ALL THE MESSAGES IN THE THREAD
List<Chat_Wrapper> arrayList_message;
public Chat_Adapter(Context context, List<Chat_Wrapper> message) {
this.context = context;
this.arrayList_message = message;
}
@Override
public Chat_Adapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View Layout;
Log.d(TAG,"On Create View Holder Calling ");
if (viewType==1){
Log.d(TAG,"View Tyoe Is "+viewType);
Layout=LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_screen_message_item,parent,false);
// ImagePath=Session.getUserImage();
}
else {
Log.d(TAG,"View Type Is "+viewType);
Layout=LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_screen_message_item_other,parent,false);
// ImagePath=chat_wrapper.getImageView();
}
return new ViewHolder(Layout);
}
@Override
public void onBindViewHolder(final Chat_Adapter.ViewHolder holder, final int position) {
chat_wrapper=arrayList_message.get(position);
context=holder.itemView.getContext();
if (valueofImage){
// Showing Sent User Image in thumbnail
Glide.with(context).load(chat_wrapper.getImageSent()).apply(new RequestOptions()
.fitCenter()
.skipMemoryCache(true))
.thumbnail(0.1f)
.into(holder.Sent_Image);
}
}
else if (valueofMessage){
Log.d(TAG,"Value Of Message Running ImagePath "+ImagePath);
holder.Sent_Video.setVisibility(View.GONE);
holder.Sent_Image.setVisibility(View.GONE);
holder.TimeStampImage.setVisibility(View.GONE);
holder.TimeStampDoc.setVisibility(View.GONE);
holder.TimeStampVideo.setVisibility(View.GONE);
holder.Search_title.setVisibility(View.GONE);
holder.Search_link.setVisibility(View.GONE);
holder.Search_snippet.setVisibility(View.GONE);
holder.Google_Image.setVisibility(View.GONE);
holder.videoView.setVisibility(View.GONE);
holder.Doc_FileName.setVisibility(View.GONE);
holder.Doc_ImageView.setVisibility(View.GONE);
holder.Doc_FileSize.setVisibility(View.GONE);
holder.GeoFencing_Layout.setVisibility(View.GONE);
holder.GeoFencing_Image.setVisibility(View.GONE);
holder.GeoFencing_LatLng.setVisibility(View.GONE);
holder.Message.setVisibility(View.VISIBLE);
holder.TimeStamp.setVisibility(View.VISIBLE);
holder.User_Image.setVisibility(View.VISIBLE);
//CHECK SENDER IS SAME AS LOGGED IN USER
if ((Session.getUserFname()+" "+Session.getUserLname()).equals(chat_wrapper.getSender_UserName())){
ImagePath=Session.getUserImage();
Log.d(TAG,"Session.getUserImage() "+Session.getUserImage());
Log.d(TAG,"Value Of Message Running ImagePath "+ImagePath);
}
else {
holder.Message.setText(chat_wrapper.getMessage());
holder.TimeStamp.setText(chat_wrapper.getTimestamp());
}
@Override
public int getItemCount() {
Log.d(TAG,"GET ITEM COUNT--Array Message List Size "+arrayList_message.size());
return arrayList_message.size();
}
}
SQLite Query
//This method will get row by limit
public Cursor getLimitUserChat(String UserID,int nextChat){
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;
}