Android 集成FireBase Realtime DataBase实现聊天

2022-04-08 00:00:00 会话 聊天 添加 用户信息 改变

在看google 2016年io大会时上面提到FireBase,抱着好奇心态研究了下,当时就觉得觉得这个太酷了.当时我就决定写个聊天的东西出来,因为很多网友都写过了,应该不会太难,于是乎我也玩玩吧,这个项目一共耗费了2周的时间,其中来回改了几次数据结构所以耽误了一些时间下面就是写成的效果(里面还有很多bug).


这里完全本着学习的目的来做的,做到现在,已经没有刚开始的兴奋和耐心,只是想快点结束.这个项目一共集成了FireBase的Authentication , RealTime DataBase,CloudMessage,Storage 一共四个小功能,在FireBase全家桶当中远远不知这些.感谢伟大的Google公司FireBase官网地址: https://firebase.google.com/

今天这篇文章要来介绍下聊天功能的实现,之前的一篇文章:Android FirBase RealTimeDb JsonTree设计,基于RealTime聊天的json格式 里面提到了具体的json格式设计,FireBase Console也支持导入导出json文件,也可以代码创建,我是都尝试了.

聊天核心的工具类


public class RealTimeDb {
Context ctx;
private static RealTimeDb realTimeDb;
public final DatabaseReference dbRef;
private final FirebaseDatabase database;
private final MyValueEventListener valueEventListener;


private RealTimeDb(Context ctx) {
this.ctx = ctx;
database = FirebaseDatabase.getInstance();
dbRef = database.getReference(Constants.realTimeDb_refence).child(Constants.Users);
String chatList = Constants.ChatList;
valueEventListener = new MyValueEventListener(ctx);
}

public static RealTimeDb getInstance(Context ctx) {
if (realTimeDb == null) {
synchronized ("a") {
if (realTimeDb == null) {
realTimeDb=new RealTimeDb(ctx);
}
}
}
return realTimeDb;
}


//测试存储数据使用
public void sendStingTodb(String content) {
DatabaseReference message = database.getReference("message");
message.setValue("hellow Firebase db");
message.addValueEventListener(valueEventListener);
}


/**
* 设置用户信息
* @param userid
* @param user 改变的值
* @return RealTimeDb
*/
public RealTimeDb savaUserInfo(String userid, User user) {
getUserRef(userid).setValue(user);
return realTimeDb;
}

/**
* 设置用户信息改变的监听
* @param dataChange
*/
public void setOnUserDataChagne(UserDataChange dataChange) {
valueEventListener.dataChangelistener = dataChange;
}

/**
* 设置会话信息改变的监听
* @param messageDataChange
*/
public void setOnMessageDataChange( MessageDataChange messageDataChange) {
valueEventListener.messageDataChange = messageDataChange;
}

/**
* 设置会话列表改变的监听
* @param chatListDataChange
*/
public void setOnChatListDataChange(ChatListDataChange chatListDataChange) {
valueEventListener.chatListDataChange = chatListDataChange;
}

/**
* 获取用户信息 次获取信息和信息改变都是一个回调
* @param dataChange 用户信息回调接口
*/
public RealTimeDb getUserData(UserDataChange dataChange) {
setOnUserDataChagne(dataChange);
return realTimeDb;
}

/**
* 获取会话列表信息的引用
* @param userid
* @return
*/
public DatabaseReference getChatListRef(String userid) {
DatabaseReference dbRef = database.getReference(Constants.ChatList).child(userid);
dbRef.addValueEventListener(valueEventListener);
return dbRef;
}

/**
* 获取用户信息的引用
* dbRef.addValueEventListener 次加载和数据改变都会执行
* @param userid
* @return
*/
public DatabaseReference getUserRef(String userid) {
DatabaseReference dbRef = database.getReference(Constants.Users).child(userid);
dbRef.addValueEventListener(valueEventListener);
return dbRef;
}

/**
* 会话信息的引用
* @param messageid
* @return
*/
public DatabaseReference getMessageRef(String messageid) {
String messages = Constants.Messages;
DatabaseReference dbRef = database.getReference(Constants.Messages).child(messageid);
dbRef.addValueEventListener(valueEventListener);
return dbRef;
}

/**
* 更新会话信息
* @param messageid
*/
public void updataSession(String messageid, SessionBean sessionBean,int position) {
DatabaseReference reference= getMessageRef(messageid);
// ArrayList<SessionBean> list= new ArrayList<>();
// SessionBean sessionBean = new SessionBean("hellow "+messageid+"!", "", "", "ake", System.currentTimeMillis() + "");
// SessionBean sessionBean1 = new SessionBean("hellow ake!", "", "", messageid, System.currentTimeMillis() + "");
// list.add(sessionBean);
// list.add(sessionBean1);
// reference.setValue(sessionBean);
Map<String, Object> map = new HashMap<>();
map.put(position+"", sessionBean);
reference.updateChildren(map);
// reference.addChildEventListener(new ChildEventListener() {
// @Override
// public void onChildAdded(DataSnapshot dataSnapshot, String s) {
// Toast.makeText(ctx, "添加成功", Toast.LENGTH_SHORT).show();
// }
//
// @Override
// public void onChildChanged(DataSnapshot dataSnapshot, String s) {
//
// }
//
// @Override
// public void onChildRemoved(DataSnapshot dataSnapshot) {
//
// }
//
// @Override
// public void onChildMoved(DataSnapshot dataSnapshot, String s) {
//
// }
//
// @Override
// public void onCancelled(DatabaseError databaseError) {
//
// }
// });
}

public void updataChatList(String username){
DatabaseReference reference = database.getReference(Constants.ChatList).child(username);
ArrayList<ChatListBean> list= new ArrayList<>();
// ChatListBean itemBean = new ChatListBean(list);
// list.add(itemBean);.
// reference.setValue(list);
// reference.addChildEventListener();
}



}


聊天界面Activity


public class SessionActivity extends MVPBaseActivity<SessionContract.View, SessionPresenter> implements SessionContract.View, View.OnClickListener {


public EditText etContent;
public Button btnSend;
public RecyclerView recyclerView;
private ArrayList<SessionBean> list;
private SessionAdapter adapter;
private RealTimeDb instance;
int position;
public static String friendsLogo = "",friendsId;
private String ortherId;

@Override
public int getLayoutResId() {
return R.layout.activity_session;
}

@Override
public void initView() {
etContent = (EditText) findViewById(R.id.etContent);
btnSend = (Button) findViewById(R.id.btnSend);
recyclerView = (RecyclerView) findViewById(R.id.cvMessage);
}

@Override
public void initListener() {
list = new ArrayList<>();
btnSend.setOnClickListener(this);
LinearLayoutManager manager = new LinearLayoutManager(SessionActivity.this, LinearLayoutManager.VERTICAL,false);
recyclerView.setLayoutManager(manager);
adapter = new SessionAdapter(SessionActivity.this, list);
recyclerView.setAdapter(adapter);
instance = RealTimeDb.getInstance(SessionActivity.this);
instance.setOnMessageDataChange(new MessageDataChange() {
@Override
public void onMessageDataChange(List<SessionBean> value) {
if (list != null && value!=null) {

if (value.size() > 0) {
ortherId = value.get(0).userId;
friendsId = value.get(0).friendsId;
getLogoUrl(friendsId);
}

position = value.size();
list.clear();
list.addAll(value);
adapter.notifyDataSetChanged();
}
}
});
instance.getMessageRef(Constants.messageid);
}

@Override
public void initData() {}

@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btnSend:
submit();
break;
}
}

public void submit() {
String s = etContent.getText().toString().toString();
String userId = SPUtil.getString(Constants.UserID, "");
if (list.size() > 0) {
ortherId = list.get(0).userId;
friendsId = list.get(0).friendsId;
}
SessionBean sessionBean = new SessionBean(s,"","","ake", System.currentTimeMillis()+"",userId.equals(ortherId), userId,friendsId);
instance.updataSession(Constants.messageid, sessionBean,position);
}

public void getLogoUrl(String userId) {
StorageUtil.getInstance().getUrlFromUserId(userId + ".jpeg", new UploadListenerImpl() {
@Override
public void onSuccess(Uri uri) {
friendsLogo = uri.toString();
adapter.notifyDataSetChanged();
}
});
}



}

聊天中使用的数据结构如下:


其中遇到的一个坑,就是这个messages这个json是个数组[ ] 官方提供的方法是:


通过为列表中的各新元素使用自动生成的键,多个客户端可以同时向同一位置添加子节点,而不存在写入冲突。

push() 生成的 ID 基于时间戳,因此列表项目会自动按时间顺序排列。

原来使用的是这样的代码:

DatabaseReference reference= getMessageRef(messageid).push();
reference.setValue(sessionBean);

保存后结构是
{ {
"content" : "今天吃啥饭?",
"friendsId" : "J72v7pA3VaSrqVGvzOJaO2uO3lI3",
"img_receive" : "",
"img_send" : "",
"isReceive" : false,
"name" : "天涯恋",
"timestamp" : "",
"userId" : "QizjLuiA1fgKuzIse3L8pMNRzBG3"
},"LuiA1O2uO3_5dthyh":{
"content" : "不知道?",
"friendsId" : "QizjLuiA1fgKuzIse3L8pMNRzBG3",
"img_receive" : "",
"img_send" : "11111111111111",
"isReceive" : true,
"name" : "andy",
"timestamp" : "14258646654",
"userId" : "J72v7pA3VaSrqVGvzOJaO2uO3lI3"
}}

然而我需要的是

[ {
"content" : "今天吃啥饭?",
"friendsId" : "J72v7pA3VaSrqVGvzOJaO2uO3lI3",
"img_receive" : "",
"img_send" : "",
"isReceive" : false,
"name" : "天涯恋",
"timestamp" : "",
"userId" : "QizjLuiA1fgKuzIse3L8pMNRzBG3"
},{
"content" : "不知道?",
"friendsId" : "QizjLuiA1fgKuzIse3L8pMNRzBG3",
"img_receive" : "",
"img_send" : "11111111111111",
"isReceive" : true,
"name" : "andy",
"timestamp" : "14258646654",
"userId" : "J72v7pA3VaSrqVGvzOJaO2uO3lI3"
}]

它给我添加了一个键,这个键是的就像官方说的基于时间,于是我大胆的尝试了新的添加数据的方法:

DatabaseReference reference= getMessageRef(messageid);
Map<String, Object> map = new HashMap<>();
map.put(position+"", sessionBean);//position当前集合的长度
reference.updateChildren(map);
这样就会自动在原来的数据中添加为集合的一个对象

相关文章