環信EaseUI 集成,集成不做描述,看文檔即可,下面主要談一些對easeui的個性化需求修改。
該篇文章將解決的問題:
1、如何將App用戶體系的用戶名和用戶頭像 顯示於環信的easeui
2、如何從library中調用app中的方法?
3、easeui頭像都是方形的,如果修改為圓型顯示?
4、環信用戶注冊問題:環信用戶注冊需要交給服務器注冊用戶的同時去注冊
5、環信登錄和注銷sdk的使用在App 客戶端實現,同步於App用戶的登錄和退出
6、第一次會話發起的時候,此時發消息的和收消息的用戶的數據可能不在數據庫中存在,需要在這個情景之下單獨先進行雙方的數據存儲
7、創建群聊方法失敗
8、群聊功能,能接受到消息,但是發送消息發不出去
9、會話界面只有點擊事件,沒有長按點擊事件(沒有刪除操作,需要自行添加長按彈對話框刪除操作)
10、easeui 7.0+ 8.0+ 調用會話拍照功能,崩潰
11、easeui 點擊對方的視頻消息,崩潰問題
--------------------------------------------------------------------------------------------------------------------
一、如何將App用戶體系的用戶名和用戶頭像 顯示於環信的easeui
這個問題是所有人都想解決的,集成easeui之后 ,雖然大部分功能給我們做好了,但是他是顯示的環信用戶體系的用戶名和默認的頭像。
這個用戶名是唯一的,官方提供了兩種方式來解決。這里我們使用用戶發送消息攜帶擴展信息的方式來實現。
首先看一下環信的用戶體系,用戶名(唯一值,easeui中顯示的用戶名就是他,實際上,我們自己數據庫的用戶體系中,就把用戶的唯一id作為環信的用戶名)
環信的用戶名 == 后台數據庫的id , 目的保證唯一值,區分用戶信息
App端 需要一個數據庫,每一個記錄有三個字段: id ,userName, userAvatar
實現思路:
1、發送消息的時候(一般是當前登錄用戶,取名用戶A) ,將項目后台用戶A的id、頭像url和用戶名字符串作為消息的擴展屬性一並發送出去
找到EaseChatFragment文件
大致看一下,該行數范圍內的代碼,很明顯是一個個發送各種類型消息的方法,方法內最后都調用了sendMessage()方法,
顯然我們需要在sendMessage()方法內 給 消息(message) 添加擴展屬性即可 ,如下圖
添加了932-935行代碼,實現了當app當前登錄用戶每次發消息(不管什么類型的消息)都會添加3個擴展屬性,分別為發出人的用戶名,用戶頭像,用戶id
(注意,這個id要在自己的服務器數據里是唯一的,一個用戶一個id,用時要求后端開發人員在環信用該id在環信用戶體系里作為唯一的用戶名,保證自己服務器里一個用戶對於環信用戶體系里的一個用戶)
總結:
第一步,給每個發出去的消息添加3個擴展屬性
2、發送方處理好了,只需要給每個發出去的消息添加3個擴展屬性即可,接下來就是收消息方的處理
這里每個用戶大致有3個主要界面,會話歷史界面,聯系人界面,單聊窗口界面。
其中會話歷史列表界面和聯系人界面類似,下面只以會話歷史列表界面為例,實現用戶頭像和用戶名的顯示
會話歷史界面對應的是EaseConversationListFragment界面。
閱讀下代碼,里面有一個refresh()方法,很現實就是更新列表的方法。
注意的是,該fragment里面是沒有監聽消息更新的listener,則第一步先根據文檔在該fragment里面添加一個消息監聽
同時,注冊和注銷監聽
仔細看一個EMMessageListener 里面有一個onMessageReceived(List<Message> message){}回調
很顯然,當有消息收到的時候,會執行該方法回調,同時把消息數據返回,注意這里的消息是一個集合的消息數據
結合第一步發出去的每一個消息都帶有發送人的用戶名,用戶頭像,用戶唯一id 三個信息,則這里只需要把三個信息從每一個消息message里面提取出來即可
代碼很簡單,注意這里需要用到數據庫的知識,我這里使用的是 greendao , 關於數據庫的學習這里就不說了,不會的童鞋可以自行去學習
總結:
第二步 就是一個獲取每一個消息中的擴展屬性,知道這個每一條消息是哪個用戶發來的,他的用戶名用戶頭像用戶唯一id都可以獲取到,然后存儲到數據庫中
3、上面兩步很明顯了, 一個是告訴對方 我叫什么、我的頭像信息、我的唯一id,一個是接收方,得到每一個消息的擴展屬性進行數據庫存儲。
該流程下第三步就很明顯了,就是把存儲的數據庫信息中獲取消息所屬用戶id的頭像和名字 顯示在界面上即可(id作為唯一標准)。
①、以會話歷史列表界面(EaseConversationListFragment)為例,聯系人界面類似
找到那行關鍵代碼:refresh()
handler發送了一個消息,繼續找對該消息的處理
很顯然,當有消息來的時候,先清空消息列表,然后加載當前消息,刷新listview
看一下conversationListView.refresh()做了什么? ctrl+鼠標左鍵點擊該方法代碼進入了 EaseConversationList.java
依舊是handler發送一個消息,繼續查詢對該消息的處理
最后定位到了adapter.notifyDataSetChanged(),刷新列表 ,定位到EaseConversationAdapter
總結一下,當有新消息來的時候,刷新適配器。
到這里很顯然知道該怎么做了,刷新適配器的時候,更改ui即可了
兩個if一個else,只需要改else里面部分即可,為啥? 看注釋
①、從數據庫中根據id獲取用戶的頭像和昵稱
如果數據庫中沒有 ,則用默認的昵稱和頭像
如果數據庫中油 ,則顯示,注意,
可以看出原來easeui顯示的用戶名是環信系統里面的用戶名,實際上我們把它作為數據庫的id,用該id對應的用戶名來顯示
顯示用戶名改為:
②、用戶名很簡單,把原本顯示id的改為顯示id對應的用戶名字符串的即可
頭像呢,定位到EaseUserUtils.setUserAvatar()方法,如下,是easeui原來的使用方式,可以看到都用了一個默認的圖片來顯示頭像
則我們只需要對應在EaseUserUtils里面寫一個定制的顯示頭像的方法 , 將第二個參數 把從數據庫對應id取出的記錄中的頭像url替換,顯示
注意,這里Glide的使用,添加了一個.dontAnimate()的使用,用於解決特定情況下第一個不會正常顯示圖片的情況,算是一個小bug,可根據自身情況添加。
總結:想要在會話歷史列表顯示實際的頭像和用戶名 只需要在list對應的adapter修改顯示ui的部分代碼即可。
4、還剩一個關鍵的界面,將頭像和用戶名顯示出來,就是會話界面 EaseChatFragment
這個界面需要修改的部分:
①標題,修改為聊天對象的用戶名,默認是環信用戶體系中聊天用戶的用戶名,即數據庫存的三個擴展屬性的id
②發送的消息,即app當前用戶發出去的item的頭像和用戶名,右側部分
③接受的消息,即app其他用戶發過來的item的頭像和用戶名,左側部分
下面按順序解決,
先定位到聊天界面的layout : ease_fragment_chat.xml
如上圖,就幾個view
很顯然,EaseTitleBar 就是聊天界面上的標題
其他,EaseChatMessageList是聊天item的列表
主要修改這兩處view的使用
ctrl+鼠標左鍵定位到EaseTitleBar這個自定義控件位置
在ctrl+鼠標左鍵點擊EaseTitleBar看一下這個控件哪里有用到
跟聊天有關,那很顯然就是EaseBaseFragment了,查看一下該文件代碼,這個fragment是一個抽象類,有兩個方法initview setUpView ,而EaseChatFragment繼承了該類
則再回到easeChatFragment里面 查詢一下setUpView 和 initView的使用
到這里就很顯然了, 這便是單聊情況下的if
easeui原代碼是灰色注釋掉的部分,可以看到titleBar顯示的是用戶的用戶名,即環信用戶體系中的用戶名,而我們把他作為id,唯一值
所以在這里還是根據這個id來去數據庫中找尋id對應的用戶名 setTitle()進去即可,修改聊天界面標題為對方用戶名就是這么簡單。
接下來是修改聊天界面的發送方和接收方的頭像問題。
這個具體找到代碼的思路就不介紹了,比較麻煩,直接定位到想要代碼吧
這里就是各種類型的消息的item的自定義控件,都繼承自EaseChatRow類
然后研究一下EaseChatRow類 ,發現了關鍵代碼
比較容易看懂,當消息是發出去的時候,調用了一個現實頭像的方法,當消息是接收的時候,定義了一個現實頭像和用戶名的方法
那解決方法,就是從該處在數據庫中根據id獲取到頭像和用戶名的數據顯示即可。
思路如此,不在細講
二、如何從library中調用app中的方法?
當依賴easeui的時候,是用import module的形式導入的,所以主程序是可以調用easeui類庫中的類和方法,但是反之不行
當數據庫操作的時候,發現該問題,解決辦法就是反射調用,具體查詢相關文章
三、easeui頭像都是方形的,如果修改為圓型顯示?
找一個用到顯示頭像的xml代碼
可以看到easeui使用了一個自定義控件來顯示EaseImageView
查看該控件源碼:
發現
說明該控件的shapeType屬性是來控制圖片是方形顯示還是圓形顯示的。
查詢源碼發現init()方法對該屬性進行了初始話,默認值為0 ,如果想圓形顯示,則改為1即可
如此一來,不該顯示圖片的控件,不該每一個調用控件的自定義屬性 即可實現統一圓形顯示。
其他注意點:
1、環信用戶注冊需要交給服務器注冊用戶的同時去注冊
2、環信登錄和注銷sdk的使用在App 客戶端實現,同步於App用戶的登錄和退出
3、第一次會話發起的時候,此時發消息的和收消息的用戶的數據可能不在數據庫中存在,需要在這個情景之下單獨先進行雙方的數據存儲
4、上面講到一個接收到新消息的回調方法 onMessageReceived
會有一種情況。B用戶尚未登錄APP, A用戶給B用戶發了消息(兩個用戶之間是第一次會話,並且是A給B發起的會話,也就是說B用戶那邊是沒有數據庫存儲A用戶的三個信息的),B用戶登錄消息之后 會有消息列表,但是因為沒有執行
onMessageReceived 方法,導致沒有對A用戶的消息中的擴展數據進行數據庫存儲,所以會導致B用戶這邊會話列表中A用戶的頭像和用戶名顯示不出,解決辦法 定位到EaseConversationListFragment類中的 loadConversationList 方法
查看源碼得知會話列表刷新的時候都會執行,那就在這個方法中對所有的消息的擴展字段進行數據庫存儲,且只有第一次創建該fragment的時候才執行存儲
onCreate()中
boolean isLoadData = false; // 是否已經緩存了數據 用於界面剛登陸的時候 對之前接受到的數據的處理
--------------------------------------------------------------------------------------------------------------------------------------------------------
5.、創建群聊方法失敗
報303 錯誤,
解決辦法,這個方法的使用需要在子線程中進行,不可以在主線程進行
所以放到Thread里面即可
6、群聊功能,能接受到消息,但是發送消息發不出去
經檢查:
當點擊會話列表 群組item進入會話界面的時候,EaseChatFragment.java 中 的setUpView方法執行了 if(chatType == EaseConstant.CHATTYPE_SINGLE)
為什么點擊群組item進入的類型是單聊的type, 往上查詢chatType怎么來的
顯然是從Activity中獲取到的,同時還從Activity中獲取到了 toChatUsername 的值
繼續往上查詢 EaseChatActivity
發現這里進行了setArguments方法,顯然這里不是數據最開始獲取的地方,繼續查,就是進入到EaseChatActivity的intent跳轉調用了
發現了intent傳遞了 但是沒有傳遞
而顯然一直類型為默認類型EaseConstant.CHATTYPE_SINGLE
導致群聊進入會話界面的類型是單聊
所以intent進入EaseChatActivity的時候,將 一並傳遞
如下:
Log日志:
發現type是GroupChat也就是字符串類型,但是接受的時候是int類型
找到EMConversation.class類
還有EaseConstant.class類
解決辦法,intent打開EaseChatActivity.class 的時候 傳遞相應的int值即可
7、會話列表item長按事件
easeui默認是沒有會話列表item長按事件的,體驗上就是會話列表沒有刪除操作
所以需要我們自行給會話列表添加一個item長按事件監聽
解決辦法:
找到EaseConversationListFragment.java
這個fragment是會話界面
找到setUpView()方法,第三行
很明顯這里是單點事件的接口回調
當然,如果長按事件需要在該fragment處理的,則直接添加長按點擊事件
如果想和單點事件一樣,則需要仿照單點做一個接口回調,這里不再敘述。
8、easeui 7.0+ 8.0+ 調用會話拍照功能,崩潰
easeui調用相機代碼本身沒有適配7.0+ 8.0+ 機型 , 需要自己適配一下
解決方案:Android項目實戰(四十九):Andoird 7.0+相機適配
具體調整代碼:
找到EaseChatFragment文件,這個是會話界面相關
找到 selectPicFromCamera方法,調用相機方法
更改代碼如下:
/** * capture new image */ protected void selectPicFromCamera() { if (!EaseCommonUtils.isSdcardExist()) { Toast.makeText(getActivity(), R.string.sd_card_does_not_exist, Toast.LENGTH_SHORT).show(); return; } cameraFile = new File(PathUtil.getInstance().getImagePath(), EMClient.getInstance().getCurrentUser() + System.currentTimeMillis() + ".jpg"); //noinspection ResultOfMethodCallIgnored cameraFile.getParentFile().mkdirs(); // 7.0+ 8.0+ 調用相機適配 Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){ intent.putExtra(MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(getActivity(),"你的包名.fileprovider", cameraFile)); }else { intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(cameraFile)); } startActivityForResult(intent, REQUEST_CODE_CAMERA); }
9、easeui 點擊對方的視頻消息,崩潰問題
這個問題看日志就知道怎么解決,因為沒有在清單文件中注冊
解決方法:
AndroidManifest.xml 文件注冊 EaseShowVideoActivity
<activity android:name="com.hyphenate.easeui.ui.EaseShowVideoActivity" android:configChanges="orientation|keyboardHidden|screenSize" android:screenOrientation="portrait"></activity>
andoird7.0+ 機型的適配
查找EaseCompat.java 文件
會有如下代碼適配7.0+ 視頻播放的
這里要注意 easeui自帶寫的是fileProvider 和 自己寫的AndroidManifest.xml 中的7.0+適配代碼的 authorities 值是否一致,
按文章上面描述的方法寫的是fileprovider , P小寫,注意 要改成一致,即
否則報錯:
-------------------------------------------------------------------------------------------------------------------------------------------------
有問題歡迎加Android群探討。。