Eu tenho RecyclerView
que estou usando para bate-papo e tudo está funcionando, mas a paginação reversa como história de carga bate-papo entre o local SQLite
banco de dados não está funcionando como Whatsapp ou telegrama App.
Na primeira carga i estou carregando histórico de chat do usuário por padrão com apenas 10 mensagens do local SQLite
banco de dados. Se eu puxar de cima ele carrega próximos (mais velhos) 10 mensagens e assim por diante.
Eu estou usando Firebase Realtime Database
como nosso servidor de chat que sincronização em tempo real e quando o usuário enviar nova mensagem que buscar mensagem e adicionar em SQLite Database
cargas, em seguida, acima de mensagem mais antiga como na imagem abaixo
Classe principal
@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;
}
}
bate-papo Adapter
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 consulta
//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;
}
Usando message.add(chat_wrapper);
vai colocar o elemento adicionado ao final da lista por isso vai ser mostrado no final da lista, enquanto você está revertendo o Recycler
, uso message.add(0,chat_wrapper);
por isso vai ser no início da lista de matriz.