欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android Flutter基于WebSocket實現(xiàn)即時通訊功能

 更新時間:2022年03月25日 11:55:20   作者:島上碼農(nóng)  
WebSocket是一種在單個TCP連接上進行全雙工通信的協(xié)議。本文將利用Flutter WebSocket實現(xiàn)即時通訊功能,文中示例代碼講解詳細,感興趣的可以了解一下

前言

我們在前面花了很大篇幅介紹 Provider 狀態(tài)管理,這是因為在 Flutter 中,Provider 是眾多狀態(tài)管理插件的首選。本篇以即時聊天為例,來講述 Provider 的綜合應(yīng)用,也算是 Provider 狀態(tài)管理系列的終結(jié)篇。本篇涉及的內(nèi)容如下:

  • 聯(lián)系人界面的構(gòu)建;
  • 聊天界面的簡單實現(xiàn);
  • StreamProvider 接收 Socket流數(shù)據(jù)并自動通知界面刷新;
  • MultiProvider為聊天主界面提供多個Provider狀態(tài);
  • 多個 Provider存在交叉數(shù)據(jù)時處理方式。

聯(lián)系人界面構(gòu)建

我們在聊天前,需要選擇對應(yīng)的聯(lián)系人進行單聊,因此需要構(gòu)建一個聯(lián)系人列表。這里我們使用簡單的 ListView.builder+Mock 數(shù)據(jù)構(gòu)建聯(lián)系人列表。界面如下所示,其中關(guān)鍵的就是點擊聯(lián)系人時將聯(lián)系人的 id通過路由傳遞過去,以便發(fā)送消息時通過用戶 id指定接收用戶。

return?ListTile(
??leading:?_getRoundImage(contactors[index].avatar,?50),
??title:?Text(contactors[index].nickname),
??subtitle:?Text(
????contactors[index].description,
????style:?TextStyle(fontSize:?14.0,?color:?Colors.grey),
??),
??onTap:?()?{
????debugPrint(contactors[index].id);
????RouterManager.router.navigateTo(context,
????????'${RouterManager.chatPath}?toUserId=${contactors[index].id}');
??},
);

聊天界面的實現(xiàn)

我們將發(fā)送的消息放在右邊,將接收到的消息放在左邊,居左還是居右通過 Container 的 margin 來實現(xiàn)。至于區(qū)分,通過消息對象的fromUserId 來區(qū)分,如果 fromUserId 和當前用戶id 一致,則是發(fā)送出去的消息,否則就是接收到的消息。在這里我們因為還沒有用戶體系,先將當前的用戶 id 寫死。為了實現(xiàn)模擬器之間的聊天,我們一個模擬器設(shè)置為 user1,一個設(shè)置為 user2。界面也是使用ListView.builder(萬能不?)構(gòu)建。

return?ListView.builder(
??itemBuilder:?(context,?index)?{
????MessageEntity?message?=?messages[index];
????double?margin?=?20;
????double?marginLeft?=?message.fromUserId?==?'user1'???60?:?margin;
????double?marginRight?=?message.fromUserId?==?'user1'???margin?:?60;
????return?Container(
??????margin:?EdgeInsets.fromLTRB(marginLeft,?margin,?marginRight,?margin),
??????padding:?EdgeInsets.all(15),
??????alignment:?message.fromUserId?==?'user1'
????????????Alignment.centerRight
??????????:?Alignment.centerLeft,
??????decoration:?BoxDecoration(
??????????color:?message.fromUserId?==?'user1'
????????????????Colors.green[300]
??????????????:?Colors.blue[400],
??????????borderRadius:?BorderRadius.circular(10)),
??????child:?Text(
????????message.content,
????????style:?TextStyle(color:?Colors.white),
??????),
????);
??},
??itemCount:?messages.length,
);

聊天界面的一個特點是會接收StreamProvider 推送的最新的消息,為了統(tǒng)一,我們將接收消息和發(fā)送消息都通過StreamProvider推送更新界面。

//?發(fā)送消息時將消息加入到流控制器中
void?sendMessage(String?event,?T?message)?{
??_socket.emit(event,?message);
??_socketResponse.sink.add(message);
}

//?接收消息時也加入到流控制器中
_socket.on(recvEvent,?(data)?{
??_socketResponse.sink.add(data);
});

這樣不管是接收消息還是發(fā)送消息都會通過 StreamProvider 重新構(gòu)建聊天界面。那問題來了,聊天列表數(shù)據(jù)如何刷新呢?

消息界面的 MultiProvider

消息界面需要接收 StreamProvider 的消息流,還需要使用消息列表數(shù)據(jù),這里我們使用了 MultiProvider。其中消息發(fā)送框和聊天界面共用 ChatMessageModel(僅為演示,實際可以拆分開)。

final?chatMessageModel?=?ChatMessageModel();
//...
body:?Stack(
??alignment:?Alignment.bottomCenter,
??children:?[
????MultiProvider(
??????providers:?[
????????StreamProvider<Map<String,?dynamic>?>(
????????????create:?(context)?=>?streamSocket.getResponse,
????????????initialData:?null),
????????ChangeNotifierProvider.value(value:?chatMessageModel)
??????],
??????child:?StreamDemo(),
????),
????ChangeNotifierProvider.value(
??????child:?MessageReplyBar(messageSendHandler:?(message)?{
????????Map<String,?String>?json?=?{
??????????'fromUserId':?'user1',
??????????'toUserId':?widget.toUserId,
??????????'contentType':?'text',
??????????'content':?message
????????};
????????streamSocket.sendMessage('chat',?json);
??????}),
??????value:?chatMessageModel,
????),
]

//...

其中ChatMessageModel即消息列表狀態(tài)數(shù)據(jù),里面只有一個消息對象數(shù)組和一個添加消息方法,以及一個 content 屬性是給消息回復框使用的。

這里就有一個問題,StreamProvider 推送 StreamSocket過來的消息的時候, ChatMessageModel 其實是不知道的。如果要知道,一個辦法就是在 StreamSocket 引用 ChatMessageModel對象,然后調(diào)用其 addMessage 方法添加消息。但是這樣會增加兩個類的耦合。還有一種方式是取巧的方式了,那就是 StreamdDemo的 build 方法能夠獲取到 StreamSocket 推送的最新消息,在這里讀取到最新的消息后就可以添加到消息列表了。由于前面我們發(fā)送消息和接收消息都將消息加入到了消息流中,這樣處理方式就統(tǒng)一了。

這種方式需要注意,Provider 不允許在組件的build 方法中再次調(diào)用類似 notifyListeners 的方法通知該組件刷新,因此在 ChatMessageModel的 addMessage 方法里不可以使用notifyListeners來通知組件刷新,否則會出現(xiàn)同一組件刷新沖突。實際上,因為另一個Provider 已經(jīng)通知該組件刷新了,因此也沒必要再通知了。當然,這僅僅是一種取巧方法,假設(shè)這個addMessage 方法還需要通知其他組件刷新,那這種形式就就不可取了。

class?ChatMessageModel?with?ChangeNotifier?{
??List<MessageEntity>?_messages?=?[];
??List<MessageEntity>?get?messages?=>?_messages;

??String?content?=?'';

??void?addMessage(Map<String,?dynamic>?json)?{
????_messages.add(MessageEntity.fromJson(json));
??}
}

這里我們先不考慮這種情況,StreamDemo 的 build關(guān)于這部分的處理方法如下,這里對于吧 ChatMessageModel 也就不需要使用 watch 方法了,完全依賴于 StreamProvider 的流推送來更新組件。每次發(fā)送消息或接收消息后,構(gòu)建時在返回組件樹前就更新了消息列表數(shù)據(jù)了,因此也能保證數(shù)據(jù)是最新的。其實,相當于我們投機取巧實現(xiàn)了兩個 Provider之間的數(shù)據(jù)交互。

@override
Widget?build(BuildContext?context)?{
??Map<String,?dynamic>??messageJson?=?context.watch<Map<String,?dynamic>?>();
??if?(messageJson?!=?null)?{
????context.read<ChatMessageModel>().addMessage(messageJson);
??}
??List<MessageEntity>?messages?=?context.read<ChatMessageModel>().messages;
??//?ListView?部分
}

運行效果

來看一下運行效果,模擬器的好處就是可以開多個調(diào)試。效果是實現(xiàn)了,不過實際即時聊天比這個復雜很多,而且一般也不會用 Socket,但是如果 App 內(nèi)部要實現(xiàn)應(yīng)用打開后的即時消息推送,WebSocket 是一個不錯的選擇。源碼已經(jīng)提交,后端和Flutter 代碼分布如下:

Flutter Provider 部分代碼(null safety 版本)

后端代碼(Express 版本)

以上就是Android Flutter基于WebSocket實現(xiàn)即時通訊功能的詳細內(nèi)容,更多關(guān)于Flutter WebSocket通訊的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 解決Android 10/Android Q手機在后臺無法正常定位問題

    解決Android 10/Android Q手機在后臺無法正常定位問題

    這篇文章主要介紹了解決Android 10/Android Q手機在后臺無法正常定位問題,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-11-11
  • Android實現(xiàn)長按圓環(huán)動畫View效果的思路代碼

    Android實現(xiàn)長按圓環(huán)動畫View效果的思路代碼

    這篇文章主要介紹了Android實現(xiàn)長按圓環(huán)動畫View效果,本文給大家分享實現(xiàn)思路,通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-09-09
  • FFmpeg?Principle學習new_video_stream添加視頻輸出流

    FFmpeg?Principle學習new_video_stream添加視頻輸出流

    這篇文章主要為大家介紹了FFmpeg?Principle學習new_video_stream添加視頻輸出流示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-10-10
  • Android 調(diào)用系統(tǒng)相冊選擇照片

    Android 調(diào)用系統(tǒng)相冊選擇照片

    這篇文章主要介紹了Android 調(diào)用系統(tǒng)相冊選擇照片的方法,幫助大家更好的進行Android開發(fā),感興趣的朋友可以了解下
    2020-12-12
  • Android 獲取內(nèi)外SD卡路徑幾種方法總結(jié)

    Android 獲取內(nèi)外SD卡路徑幾種方法總結(jié)

    這篇文章主要介紹了Android 獲得內(nèi)外SD卡路徑幾種方法總結(jié)的相關(guān)資料,需要的朋友可以參考下
    2016-12-12
  • Android如何通過URI獲取文件路徑示例代碼

    Android如何通過URI獲取文件路徑示例代碼

    這篇文章主要給大家介紹了關(guān)于Android如何通過URI獲取文件路徑的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對各位Android開發(fā)者們具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。
    2018-01-01
  • Android實現(xiàn)GridView中的item自由拖動效果

    Android實現(xiàn)GridView中的item自由拖動效果

    在前一個項目中,實現(xiàn)了一個功能是gridview中的item自由拖到效果,實現(xiàn)思路很簡單,主要工作就是交換節(jié)點,以及拖動時的移動效果,下面小編給大家分享具體實現(xiàn)過程,對gridview實現(xiàn)拖拽效果感興趣的朋友一起看看吧
    2016-11-11
  • 在Android里完美實現(xiàn)基站和WIFI定位

    在Android里完美實現(xiàn)基站和WIFI定位

    眾所周知的,在OPhone和大部分國產(chǎn)的Android定制機里不支持最簡單實用的基站和WIFI定位,只能使用速度慢而耗電的GPS定位,但OPhone和華為/中興生產(chǎn)的一些Android定制機卻占據(jù)了一定的市場,因此導致了很多使用了定位技術(shù)的Andorid應(yīng)用挺尷尬的。
    2014-07-07
  • Android通過startService實現(xiàn)文件批量下載

    Android通過startService實現(xiàn)文件批量下載

    這篇文章主要為大家詳細介紹了Android通過startService實現(xiàn)文件批量下載的示例,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2015-12-12
  • Android實現(xiàn)登錄注冊功能

    Android實現(xiàn)登錄注冊功能

    這篇文章主要為大家詳細介紹了Android實現(xiàn)登錄注冊功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-04-04

最新評論