Recyclerview Adapter的notifyDataSetChanged没有更新RecyclerView

时间:2018-06-13 17:08:40

标签: java android sql arrays database

我有一个RecyclerView聊天应用程序与firebase实时数据库和本地SQLite数据库。我将消息保存到本地数据库(SQLite),然后调用adapter.notifyDataSetChanged()

如果消息已经在数据库中(消息唯一ID),则SQLite将在数据库insertOrThrow方法上返回0。我正在检查这样的可用性。

if (id == 0) {
    Log.d(TAG,"Database Already Has Value Of This Random Id ");
    adapter.notifyDataSetChanged();
} else {
    Chat_Wrapper chat_wrapper = new Chat_Wrapper(Chat_Msg, null, null, null, null, null, null, Chat_TimeStamp, UserPhone_Intent, UserImage_Intent, Chat_FROM, null,null,id);
    message.add(chat_wrapper);
    adapter.notifyDataSetChanged();
}

但是,即使正在调用else语句,我的RecyclerView屏幕也不会更新,但在后台,如果我输入或接收任何消息,它会保存到本地数据库但不会#39} ; t在屏幕上显示。

聊天RecyclerView适用于以下情况

  1. 当我从最近的应用中清除应用时
  2. 停止从本地数据库中获取数据
  3. 首次推出聊天屏幕
  4. 当我直接通知聊天屏幕时,我正面临这个问题。

    我是如何正常加载聊天片段的。

    getFragmentManager().beginTransaction().add(R.id.Navigation_Drawer, chatFragment).commit();

    使用Fragment

    Notification加载Asynctask
    ((Navigation_Drawer)context).getFragmentManager().beginTransaction().replace(R.id.Navigation_Drawer, chatFragment).commit();
    

    我是如何从通知中启动ChatFragment的。

    public class FireBase_Messaging_Service extends FirebaseMessagingService {
    
        public static final String TAG="###FireBase MSG###";
        public static final int NOTIFICATION=5;
        String UserName;
        String ID;
        String Msg;
    
        Map<String,String> data;
        @Override
        public void onMessageReceived(RemoteMessage remoteMessage) {
            super.onMessageReceived(remoteMessage);
            Log.d(TAG,"From "+remoteMessage.getFrom());
            if (remoteMessage.getData().size()>0){
                data = remoteMessage.getData();
                Log.d(TAG,"Message Data "+remoteMessage.getData());
                data = remoteMessage.getData();
    
                UserName = data.get("name");
                ID = data.get("ID");
                Msg = data.get("Message");
    
                showNotification(Msg,ID,UserName);
            }
    
            if (remoteMessage.getNotification()!=null){
                Log.d(TAG,"Message Notification Body "+remoteMessage.getNotification().getBody());
               // Toast.makeText(this, "Notification "+remoteMessage.getNotification().getBody(), Toast.LENGTH_LONG).show();
            }
        }
    
        private void showNotification(String Message,String ID,String UserName) {
            Log.d(TAG,"Show Notification "+Message+" "+ID);
            Intent intent=new Intent(this, Navigation_Drawer.class);
            intent.putExtra("Type","Text");
            //intent.putExtra("Type",MsgType);
            intent.putExtra("ID",ID);
            intent.putExtra("uname",UserName);
            intent.putExtra("Message",Msg);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
            PendingIntent pendingIntent=PendingIntent.getActivity(this,NOTIFICATION,intent,PendingIntent.FLAG_UPDATE_CURRENT);
            int color = getResources().getColor(R.color.black);
            String ChannelID = "Message";
            notificationChannel(ChannelID,"Chat");
            NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext(),ChannelID)
                    .setSmallIcon(R.drawable.default_x)
                    .setColor(color)
                    .setContentTitle(UserName)
                    .setContentText(Message)
                    .setChannelId(ChannelID)
                    .setTicker("My App")
                    .setDefaults(Notification.DEFAULT_VIBRATE | Notification.DEFAULT_SOUND | Notification.FLAG_SHOW_LIGHTS)
                    .setLights(0xff00ff00, 1000, 500) // To change Light Colors
                    .setStyle(new NotificationCompat.BigTextStyle().bigText(Message))//For Expandable View
                    .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                    .setContentIntent(pendingIntent)
                    .setAutoCancel(true);
    
            NotificationManagerCompat managerCompat = NotificationManagerCompat.from(this);
            managerCompat.notify(NOTIFICATION,builder.build());
        }
    
        @Override
        public void onDeletedMessages() {
            super.onDeletedMessages();
        }
    
        private void notificationChannel (String ChannelID, String channelName) {
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
                NotificationChannel  channel = new NotificationChannel(ChannelID,channelName, NotificationManager.IMPORTANCE_DEFAULT);
                channel.setLightColor(Color.GREEN);
                NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
                notificationManager.createNotificationChannel(channel);
            }
        }
    }
    

    我还注意到,通过记录将数据添加到列表message.add(chat_wrapper)之后,它首先显示了大小的增加,但是当while循环结束时,它显示ArrayList的最后一个大小。

    这是ChatFragment班。

     public class Chat_Screen_Fragment extends Fragment implements View.OnClickListener, ChildEventListener{
    
        public static final String TAG = "###CHAT SCREEN###";
        List<Chat_Wrapper> message = new ArrayList<>();
    
        Chat_Adapter adapter;
        RecyclerView recyclerView;
        LinearLayoutManager layoutManager;
    
        @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);
            // GET INTENT VALUES FROM USER PROFILE CLASS
    
            UserName_Intent = getArguments().getString("Get_Name");
            UserImage_Intent = getArguments().getString("Get_Image");
            UserPhone_Intent = getArguments().getString("Get_Phone");
            UserID_Intent = getArguments().getString("Get_ID");
            FirebaseToken_Intent = getArguments().getString("Get_Token"); //Firebase Token of other person
            Room_Name_Intent = getArguments().getString("Get_Other"); // Room Name of chat
            UserLastSeen_Intent=getArguments().getString("LastSeen");
            //Sender_FCMToken = Session.getFirebaseID();
            // RECYCLER VIEW
            recyclerView = v.findViewById(R.id.Chat_Screen_Message_List);
            layoutManager = new LinearLayoutManager(getActivity());
            layoutManager.setStackFromEnd(true);
            recyclerView.setHasFixedSize(true);
            recyclerView.setLayoutManager(layoutManager);
            databaseReference = FirebaseDatabase.getInstance().getReference().child(Room_Name_Intent);
            databaseReference.addChildEventListener(this);
    
            adapter = new Chat_Adapter(getActivity(), message);
            recyclerView.setAdapter(adapter);
            // FETCH OLD MESSAGE FROM DATABASE
            chatDatabase();
            return v;
        }
        // FIREBASE REAL TIME DATABASE WHICH FETCH ALL MESSAGES (SYNC) FROM ONLINE DATABASE
        @Override
        public void onChildAdded(DataSnapshot dataSnapshot, String s) {
            append_chat_conversation(dataSnapshot);
        }
    
        @Override
        public void onChildChanged(DataSnapshot dataSnapshot, String s) {
            append_chat_conversation(dataSnapshot);
        }
    
        @Override
        public void onChildRemoved(DataSnapshot dataSnapshot) {
    
        }
    
        @Override
        public void onChildMoved(DataSnapshot dataSnapshot, String s) {
    
        }
    
        @Override
        public void onCancelled(DatabaseError databaseError) {
    
        }
    
        private synchronized void append_chat_conversation(DataSnapshot dataSnapshot) {
            iterator = dataSnapshot.getChildren().iterator();
    
            while (iterator.hasNext()) {
    
                // GETTING DATA FROM FIREBASE DATABASE 
    
                Chat_Msg = (String) ((DataSnapshot) iterator.next()).getValue();
                Chat_FROM = (String) ((DataSnapshot) iterator.next()).getValue();
                Chat_FROM_ID = (String) ((DataSnapshot) iterator.next()).getValue();
                Chat_TO = (String) ((DataSnapshot) iterator.next()).getValue();
                Chat_TimeStamp = (String) ((DataSnapshot) iterator.next()).getValue();
                Chat_Type= (String) ((DataSnapshot) iterator.next()).getValue();
                Random_ID=(String) ((DataSnapshot) iterator.next()).getValue();
                Chat_FCM_FROM= (String) ((DataSnapshot) iterator.next()).getValue();
                Chat_FCM_TO= (String) ((DataSnapshot) iterator.next()).getValue();
    
                Log.d(TAG, "Chat Items " + Chat_Msg + " " + Random_ID);
    
                Chat_Database tempChatDatabase = new Chat_Database(getActivity());
                boolean hasValue = tempChatDatabase.CheckValueExist(Random_ID);
                Log.d(TAG,"DATABASE ALREADY HAS VALUE OF TIMESTAMP= "+hasValue);
    
                if (!hasValue) {
                    Log.d(TAG,"DATABASE DON'T HAVE SAME ENTRY FOR TIME STAMP. ENTERED INTO HAS VALUE");
                    Log.d(TAG,"Chat Message "+Chat_Msg);
    
               if (Chat_Type.equals("Typed_Message")) {
                    Log.d(TAG, "VIEW TYPE IS Message " + Chat_Msg);
                    long id = chat_database.Insert_Chat(Session.getUserID(),Room_Name_Intent, UserID_Intent, "Text", Chat_Msg, Chat_FROM, Chat_TO, Chat_TimeStamp, Chat_FCM_FROM, Chat_FCM_TO, Session.getPhoneNO(), UserPhone_Intent,Random_ID,UserImage_Intent,UserLastSeen_Intent,Chat_FROM_ID);
    
                    //Adding Chat Data Into Database
                    Log.d(TAG,"Database Entry ID "+id);
    
                    if (id == 0) {
                        Log.d(TAG,"Database Already Has Value Of This Random Id ");
                        adapter.notifyDataSetChanged();
                        continue;
    
                    } else {
                        Log.d(TAG,"Database Don't Has Value Of This Random Id ");
                        Log.d(TAG,"Message Size "+message.size());
                        Chat_Wrapper chat_wrapper = new Chat_Wrapper(Chat_Msg, null, null, null, null, null, null, Chat_TimeStamp, UserPhone_Intent, UserImage_Intent, Chat_FROM, null,null,id);
                        message.add(chat_wrapper);
                        Log.d(TAG,"Message Size "+message.size());
                        adapter.notifyDataSetChanged();
                        Log.d(TAG,"Adapter Notified Data Set "+adapter.getItemCount());
                        recyclerView.post(new Runnable() {
                            @Override
                            public void run() {
                                Log.d(TAG, "Moving to Bottom");
                                recyclerView.smoothScrollToPosition(adapter.getItemCount());
                            }
                        });
                    }
            }
    
            Log.d(TAG, "MESSAGE ARRAY SIZE " + message.size());
            chat_database.isDatabaseClose();
    }
    
        private void chatDatabase(){
            //Database Init and Filling Adapter
            Log.d(TAG,"Chat Database Function");
            chat_database=new Chat_Database(getActivity());
            chatCursor=chat_database.getUserChat(UserID_Intent);
            boolean checkDB_Exist=functions.DatabaseExist(getActivity(),"CHAT_DATABASE.DB");
            boolean chatItemsCounts=chatCursor.getCount()>0;
            chatCursor.moveToFirst();
            Log.d(TAG,"Value At Chat Database "+ checkDB_Exist+" "+chatItemsCounts);
            if (checkDB_Exist && chatCursor.getCount()>0 && chatCursor.getString(chatCursor.getColumnIndex("RECEIVER_USER_ID")).equals(UserID_Intent)){
    
                Log.d(TAG,"Database Exist Chat Database");
                message.clear();
                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
    
    
                        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());
    
                Room_Name_Intent = database_RoomName;
                layoutManager = new LinearLayoutManager(getActivity());
                recyclerView.setLayoutManager(layoutManager);
                adapter.notifyDataSetChanged();
                chatCursor.close();
                boolean value = chat_database.isDatabaseClose();
                recyclerView.post(new Runnable() {
                    @Override
                    public void run() {
                        Log.d(TAG, "Moving to Bottom");
                        recyclerView.smoothScrollToPosition(message.size()-1);
    
                    }
                });
                Log.d(TAG,"Value Of Database Close or Not "+value);
    
            }
        }
    }
    

2 个答案:

答案 0 :(得分:0)

我认为你需要在这里实现LoaderCallbacks并听取数据库中所做的更改以相应地更新RecyclerView。我在这里创建了一个repository in Github,它显示了数据库的读取,写入和更新,并使数据库中的更改在相应的RecyclerView中具有正确的效果,并向数据库注册了内容观察者。

整个想法是让一个观察者附加到您的数据库表中,该表将通知您表中的任何更改。检测到更改时,将自动生成数据库读取查询,并在从表中重新加载数据时将触发RecyclerView函数内的onLoadFinished更新。

我在Github项目中有一个演示实现,该项目显示了RecyclerView中显示的用户列表,并在不调用RecyclerView的情况下自动更新notifyDataSetChanged。请检查控制数据的适配器,以便再次显示RecyclerView中的数据。这是您在案例中可能避免任何复杂性的最简单的实现。

希望有所帮助。

<强>更新

在完成代码之后,我想出了一些你应该做的修复。很难理解为什么它没有像你预期的那样工作,因为给出的代码格式和完整性都不是很好。但是,我可以在这里建议一些可能有用的关键修复。

append_chat_conversation功能中,每次找到新的聊天消息时都不必致电notifyDataSetChanged,并将其添加到message。我想建议,不要在message列表中添加聊天消息。您可能会删除以下if-else块。只需更新聊天数据库并在其中插入新的聊天消息即可。所以我建议您删除以下部分。

if (id == 0) {
    Log.d(TAG,"Database Already Has Value Of This Random Id ");
    adapter.notifyDataSetChanged();
    continue;

} else {
    Log.d(TAG,"Database Don't Has Value Of This Random Id ");
    Log.d(TAG,"Message Size "+message.size());
    Chat_Wrapper chat_wrapper = new Chat_Wrapper(Chat_Msg, null, null, null, null, null, null, Chat_TimeStamp, UserPhone_Intent, UserImage_Intent, Chat_FROM, null,null,id);
    message.add(chat_wrapper);
    Log.d(TAG,"Message Size "+message.size());
    adapter.notifyDataSetChanged();
    Log.d(TAG,"Adapter Notified Data Set "+adapter.getItemCount());
    recyclerView.post(new Runnable() {
        @Override
        public void run() {
            Log.d(TAG, "Moving to Bottom");
            recyclerView.smoothScrollToPosition(adapter.getItemCount());
        }
    });
} 

在此行之前调用chatDatabase函数以从数据库加载消息。

// FETCH MESSAGE FROM DATABASE
chatDatabase();

Log.d(TAG, "MESSAGE ARRAY SIZE " + message.size());
chat_database.isDatabaseClose();

现在修复您的chatDatabase功能。您每次调用LinearLayoutManager函数时,都会创建一个新的RecyclerView并将其分配给chatDatabase。我建议也删除它。

修改您的chatDatabase功能,如下所示。

private void chatDatabase() {
    //Database Init and Filling Adapter
    Log.d(TAG, "Chat Database Function");
    chat_database = new Chat_Database(getActivity());
    chatCursor = chat_database.getUserChat(UserID_Intent);
    boolean checkDB_Exist = functions.DatabaseExist(getActivity(), "CHAT_DATABASE.DB");
    boolean chatItemsCounts = chatCursor.getCount() > 0;
    chatCursor.moveToFirst();
    Log.d(TAG, "Value At Chat Database " + checkDB_Exist + " " + chatItemsCounts);
    if (checkDB_Exist && chatCursor.getCount() > 0 && chatCursor.getString(chatCursor.getColumnIndex("RECEIVER_USER_ID")).equals(UserID_Intent)) {

        Log.d(TAG, "Database Exist Chat Database");
        message.clear();
        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


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

        Room_Name_Intent = database_RoomName;

        adapter.setChatMessages(message); // Add a public function in your adapter to set the chat messages 
        adapter.notifyDataSetChanged();

        chatCursor.close();
        boolean value = chat_database.isDatabaseClose();
        recyclerView.post(new Runnable() {
            @Override
            public void run() {
                Log.d(TAG, "Moving to Bottom");
                recyclerView.smoothScrollToPosition(message.size() - 1);

            }
        });

        Log.d(TAG, "Value Of Database Close or Not " + value);
    }
}

适配器中的setChatMessages函数看起来像这样。

public void setChatMessages(ArrayList<Message> messageList) {
    this.message = messageList;
}

答案 1 :(得分:0)

我通过挖掘android生命周期来解决这个问题。正如我上面提到的,只有当我从通知中输入 ChatFragment 时才会遇到此问题。我只是活动状态问题。代码正在运作。我在做什么我总是在通知点击(在Firebase代码中)重新创建活动。

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);

Intent中挖掘大量代码并更改多个标志之后。只有android:launchMode="singleTask"解决了我的问题。只有在不存在时才会创建活动。现在,在点击通知时,它不会调用活动onDestroy方法。它是onStart的启动活动,可以避免重新创建活动。

我在 AndroidManifest的 NavigationDrawer活动代码中添加此标记。

 <activity
            android:name=".Navigation_Drawer"
            android:launchMode="singleTask"
            android:theme="@style/AppTheme"/>

这类问题对开发人员来说真的很头疼,但我不知道用这一行代码可以解决这个问题。谢谢大家的帮助。