结对冲刺11
实现MainActivity
1 package com.example.chatapptest.activities; 2 3 import androidx.appcompat.app.AppCompatActivity; 4 5 import android.content.Intent; 6 import android.graphics.Bitmap; 7 import android.graphics.BitmapFactory; 8 import android.os.Bundle; 9 import android.util.Base64; 10 import android.view.View; 11 import android.widget.Toast; 12 13 import com.example.chatapptest.adapters.RecentConversationsAdapter; 14 import com.example.chatapptest.databinding.ActivityMainBinding; 15 import com.example.chatapptest.listeners.ConversionListener; 16 import com.example.chatapptest.models.ChatMessage; 17 import com.example.chatapptest.models.User; 18 import com.example.chatapptest.utilities.Constants; 19 import com.example.chatapptest.utilities.PreferenceManager; 20 import com.google.firebase.firestore.DocumentChange; 21 import com.google.firebase.firestore.DocumentReference; 22 import com.google.firebase.firestore.EventListener; 23 import com.google.firebase.firestore.FieldValue; 24 import com.google.firebase.firestore.FirebaseFirestore; 25 import com.google.firebase.firestore.QuerySnapshot; 26 import com.google.firebase.messaging.FirebaseMessaging; 27 28 import java.util.ArrayList; 29 import java.util.Collections; 30 import java.util.HashMap; 31 import java.util.List; 32 33 public class MainActivity extends BaseActivity implements ConversionListener { 34 35 private ActivityMainBinding binding; 36 private PreferenceManager preferenceManager; 37 private List<ChatMessage> conversations; 38 private RecentConversationsAdapter conversationsAdapter; 39 private FirebaseFirestore database; 40 41 @Override 42 protected void onCreate(Bundle savedInstanceState) { 43 super.onCreate(savedInstanceState); 44 binding = ActivityMainBinding.inflate(getLayoutInflater()); 45 setContentView(binding.getRoot()); 46 preferenceManager = new PreferenceManager(getApplicationContext()); 47 init(); 48 loadUserDetails(); 49 getToken(); 50 setListeners(); 51 listenConversations(); 52 } 53 54 //这些初始化操作为后续的对话记录展示和管理奠定了基础 55 private void init(){ 56 // 1. 创建一个存储最近对话数据的 ArrayList 57 conversations = new ArrayList<>(); 58 // 2. 创建 RecentConversationsAdapter 对象,并传入 conversations 列表和当前对象(可能是 Activity 或 Fragment)作为参数 59 conversationsAdapter = new RecentConversationsAdapter(conversations,this); 60 // 3. 将 conversationsAdapter 设置为 conversationsRecyclerView 的适配器,用于在界面上显示最近的对话列表 61 binding.conversationsRecyclerView.setAdapter(conversationsAdapter); 62 // 4. 获取 Firebase Firestore 数据库的实例,以便在后续操作中使用该数据库 63 database = FirebaseFirestore.getInstance(); 64 } 65 66 //这些监听器的设置为用户的登录退出和聊天创建提供了交互入口 67 private void setListeners(){ 68 // 1. 为 imageSignOut 图标设置点击监听器 69 binding.imageSignOut.setOnClickListener(v -> signOut()); 70 // 2. 为 fabNewChat 浮动按钮设置点击监听器 71 binding.fabNewChat.setOnClickListener(v -> { 72 // 2.1 当点击浮动按钮时,启动 UsersActivity 73 startActivity(new Intent(getApplicationContext(), UsersActivity.class)); 74 }); 75 } 76 77 //这段代码的主要作用是从 SharedPreferences 中读取用户的名称和头像信息,并将其显示在界面上 78 private void loadUserDetails(){ 79 // 1. 从 SharedPreferences 中获取用户名,并设置到 textName TextView 中 80 binding.textName.setText(preferenceManager.getString(Constants.KEY_NAME)); 81 // 2. 从 SharedPreferences 中获取用户头像的 Base64 编码字符串 82 byte[] bytes = Base64.decode(preferenceManager.getString(Constants.KEY_IMAGE),Base64.DEFAULT); 83 // 3. 将 Base64 编码的字符串解码为字节数组 84 Bitmap bitmap = BitmapFactory.decodeByteArray(bytes,0,bytes.length); 85 // 5. 将解码后的 Bitmap 图像设置到 imageProfile ImageView 中 86 binding.imageProfile.setImageBitmap(bitmap); 87 } 88 89 //使用 showToast() 方法可以方便地在应用程序的各个地方显示 Toast 消息 90 private void showToast(String message){ 91 // 使用 Toast.makeText() 方法创建一个新的 Toast 消息 92 Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show(); 93 } 94 95 //确保用户在使用聊天应用时,能够及时看到最新的对话信息 96 private void listenConversations(){ 97 // 1. 监听发送方为当前用户的对话记录变化 98 database.collection(Constants.KEY_COLLECTION_CONVERSATIONS) 99 .whereEqualTo(Constants.KEY_SENDER_ID,preferenceManager.getString(Constants.KEY_USER_ID)) 100 .addSnapshotListener(eventListener); 101 // 2. 监听接收方为当前用户的对话记录变化 102 database.collection(Constants.KEY_COLLECTION_CONVERSATIONS) 103 .whereEqualTo(Constants.KEY_RECEIVER_ID,preferenceManager.getString(Constants.KEY_USER_ID)) 104 .addSnapshotListener(eventListener); 105 } 106 107 //确保用户在使用聊天应用时,能够及时看到最新的对话信息。 108 private final EventListener<QuerySnapshot> eventListener = (value, error) -> { 109 // 1. 如果出现错误,直接返回 110 if(error != null){ 111 return; 112 } 113 // 2. 如果有数据变化 114 if(value != null){ 115 // 遍历数据变化的文档 116 for(DocumentChange documentChange : value.getDocumentChanges()){ 117 // 2.1 如果是新增文档 118 if(documentChange.getType() == DocumentChange.Type.ADDED){ 119 // 获取发送方和接收方的 ID 120 String senderId = documentChange.getDocument().getString(Constants.KEY_SENDER_ID); 121 String receiverId = documentChange.getDocument().getString(Constants.KEY_RECEIVER_ID); 122 // 创建一个新的 ChatMessage 对象 123 ChatMessage chatMessage = new ChatMessage(); 124 chatMessage.senderId = senderId; 125 chatMessage.receiverId = receiverId; 126 // 根据当前用户是发送方还是接收方,设置对话的头像、名称和 ID 127 if(preferenceManager.getString(Constants.KEY_USER_ID).equals(senderId)){ 128 chatMessage.conversionImage = documentChange.getDocument().getString(Constants.KEY_RECEIVER_IMAGE); 129 chatMessage.conversionName = documentChange.getDocument().getString(Constants.KEY_RECEIVER_NAME); 130 chatMessage.conversionId = documentChange.getDocument().getString(Constants.KEY_RECEIVER_ID); 131 }else { 132 chatMessage.conversionImage = documentChange.getDocument().getString(Constants.KEY_SENDER_IMAGE); 133 chatMessage.conversionName = documentChange.getDocument().getString(Constants.KEY_SENDER_NAME); 134 chatMessage.conversionId = documentChange.getDocument().getString(Constants.KEY_SENDER_ID); 135 } 136 // 设置最后一条消息和时间戳 137 chatMessage.message = documentChange.getDocument().getString(Constants.KEY_LAST_MESSAGE); 138 chatMessage.dateObject = documentChange.getDocument().getDate(Constants.KEY_TIMESTAMP); 139 // 将新的 ChatMessage 对象添加到 conversations 列表中 140 conversations.add(chatMessage); 141 // 2.2 如果是修改文档 142 } else if (documentChange.getType() == DocumentChange.Type.MODIFIED) { 143 // 遍历 conversations 列表,更新对应的消息和时间戳 144 for(int i = 0;i<conversations.size();i++){ 145 String senderId = documentChange.getDocument().getString(Constants.KEY_SENDER_ID); 146 String receiverId = documentChange.getDocument().getString(Constants.KEY_RECEIVER_ID); 147 if(conversations.get(i).senderId.equals(senderId) && conversations.get(i).receiverId.equals(receiverId)){ 148 conversations.get(i).message = documentChange.getDocument().getString(Constants.KEY_LAST_MESSAGE); 149 conversations.get(i).dateObject = documentChange.getDocument().getDate(Constants.KEY_TIMESTAMP); 150 break; 151 } 152 } 153 } 154 } 155 // 3. 将 conversations 列表按时间戳降序排序 156 Collections.sort(conversations,(obj1,obj2) -> obj2.dateObject.compareTo(obj1.dateObject)); 157 // 4. 通知适配器数据发生变化,并滚动到列表顶部 158 conversationsAdapter.notifyDataSetChanged(); 159 binding.conversationsRecyclerView.smoothScrollToPosition(0); 160 binding.conversationsRecyclerView.setVisibility(View.VISIBLE); 161 binding.progressBar.setVisibility(View.GONE); 162 } 163 }; 164 165 //这段代码是实现移动应用程序消息推送功能的一部分 166 private void getToken(){ 167 // 1. 获取 Firebase 云消息推送服务的实例 168 FirebaseMessaging.getInstance().getToken().addOnSuccessListener(this::updateToken); 169 } 170 171 //可以确保应用程序的消息推送功能能够正常工作,提高用户体验。 172 private void updateToken(String token){ 173 // 1. 获取 Firestore 数据库的实例 174 FirebaseFirestore database = FirebaseFirestore.getInstance(); 175 // 2. 获取当前用户在 Firestore 中的文档引用 176 DocumentReference documentReference = 177 database.collection(Constants.KEY_COLLECTION_USERS).document( 178 preferenceManager.getString(Constants.KEY_USER_ID) 179 ); 180 // 3. 更新当前用户文档中的 FCM 推送令牌字段 181 documentReference.update(Constants.KEY_FCM_TOKEN,token) 182 // 4. 如果更新失败,显示 Toast 提示 183 .addOnFailureListener(e -> showToast("Unable to update token")); 184 } 185 186 private void signOut(){ 187 // 1. 显示"正在登出..."的 Toast 提示 188 showToast("Signing out ..."); 189 // 2. 获取 Firestore 数据库的实例 190 FirebaseFirestore database = FirebaseFirestore.getInstance(); 191 // 3. 获取当前用户在 Firestore 中的文档引用 192 DocumentReference documentReference = 193 database.collection(Constants.KEY_COLLECTION_USERS).document( 194 preferenceManager.getString(Constants.KEY_USER_ID) 195 ); 196 // 4. 创建一个 HashMap 用于更新文档字段 197 HashMap<String,Object> updates = new HashMap<>(); 198 // 5. 将 FCM 推送令牌字段设置为删除操作 199 updates.put(Constants.KEY_FCM_TOKEN, FieldValue.delete()); 200 documentReference.update(updates) 201 // 7. 如果更新成功 202 .addOnSuccessListener(unused -> { 203 // 7.1 清除 SharedPreferences 中保存的用户信息 204 preferenceManager.clear(); 205 // 7.2 启动登录页面 Activity,并结束当前 Activity 206 startActivity(new Intent(getApplicationContext(),SignInActivity.class)); 207 finish(); 208 }) 209 // 8. 如果更新失败 210 .addOnFailureListener(e -> showToast("Unable to sign out")); 211 } 212 213 //实现用户点击对话列表中的对话,快速进入聊天页面的功能 214 @Override 215 public void onConversionClicked(User user) { 216 // 1. 创建一个 Intent 对象,指向 ChatActivity 类 217 Intent intent = new Intent(getApplicationContext(), ChatActivity.class); 218 // 2. 将当前点击的 User 对象通过 Intent 的 extras 传递到 ChatActivity 219 intent.putExtra(Constants.KEY_USER,user); 220 // 3. 启动 ChatActivity 221 startActivity(intent); 222 } 223 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?