在上一篇《Android多人視頻聊天應(yīng)用的開發(fā)(二)一對(duì)一聊天》中我們學(xué)習(xí)了如何使用聲網(wǎng)Agora SDK進(jìn)行一對(duì)一的聊天,本篇主要討論如何使用Agora SDK進(jìn)行多人聊天。主要需要實(shí)現(xiàn)以下功能:

成都創(chuàng)新互聯(lián)公司專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于
網(wǎng)站設(shè)計(jì)制作、網(wǎng)站設(shè)計(jì)、新華網(wǎng)絡(luò)推廣、
微信小程序開發(fā)、新華網(wǎng)絡(luò)營(yíng)銷、新華企業(yè)策劃、新華品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運(yùn)營(yíng)等,從售前售中售后,我們都將竭誠(chéng)為您服務(wù),您的肯定,是我們大的嘉獎(jiǎng);
成都創(chuàng)新互聯(lián)公司為所有大學(xué)生創(chuàng)業(yè)者提供
新華建站搭建服務(wù),24小時(shí)服務(wù)熱線:028-86922220,官方網(wǎng)址:chinadenli.net
1、上一篇已經(jīng)實(shí)現(xiàn)過的聊天功能
2、隨著加入人數(shù)和他們的手機(jī)攝像頭分辨率的變化,顯示不同的UI,即所謂的“分屏”
3、點(diǎn)擊分屏中的小窗,可以放大顯示該聊天窗
分屏
根據(jù)前期技術(shù)調(diào)研,分屏顯示最好的方式是采用瀑布流結(jié)合動(dòng)態(tài)聊天窗實(shí)現(xiàn),這樣比較方便的能夠適應(yīng)UI的變化。所謂瀑布流,就是目前比較流行的一種列表布局,會(huì)在界面上呈現(xiàn)參差不齊的多欄布局。我們先實(shí)現(xiàn)一個(gè)瀑布流:
瀑布流的實(shí)現(xiàn)方式很多,本文采用結(jié)合GridLayoutManager的RecyclerView來實(shí)現(xiàn)。我們首先自定義一個(gè)RecyclerView,命名為GridVideoViewContainer。核心代碼如下:
intcount = uids.size(); if(count <= 2) { //只有本地視頻或聊天室內(nèi)只有另外一個(gè)人 this.setLayoutManager(newLinearLayoutManager(activity.getApplicationContext(), orientation, false)); } else if(count > 2) { //多人聊天室 intitemSpanCount = getNearestSqrt(count); this.setLayoutManager(newGridLayoutManager(activity.getApplicationContext(), itemSpanCount, orientation, false)); } |
根據(jù)上面的代碼可以看出,在聊天室里只有自己的本地視頻或者只有另外一個(gè)人的時(shí)候,采用LinearLayoutManager,這樣的布局其實(shí)與前文的一對(duì)一聊天類似;而在真正意義的多人聊天室里,則采用GridLayoutManager實(shí)現(xiàn)瀑布流,其中itemSpanCount就是瀑布流的列數(shù)。
有了一個(gè)可用的瀑布流之后,下面我們就可以實(shí)現(xiàn)動(dòng)態(tài)聊天窗了:
動(dòng)態(tài)聊天窗的要點(diǎn)在于item的大小由視頻的寬高比決定,因此Adapter及其對(duì)應(yīng)的layout就該注意不要寫死尺寸。在Adapter里控制item具體尺寸的代碼如下:
if(force || mItemWidth== 0 || mItemHeight== 0) { WindowManager windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics outMetrics = newDisplayMetrics(); windowManager.getDefaultDisplay().getMetrics(outMetrics);
intcount = uids.size(); intDividerX = 1; intDividerY = 1;
if(count == 2) { DividerY = 2; } else if(count >= 3) { DividerX = getNearestSqrt(count); DividerY = (int) Math.ceil(count * 1.f / DividerX); }
intwidth = outMetrics.widthPixels; intheight = outMetrics.heightPixels;
if(width > height) { mItemWidth= width / DividerY; mItemHeight= height / DividerX; } else{ mItemWidth= width / DividerX; mItemHeight= height / DividerY; } } |
以上代碼根據(jù)視頻的數(shù)量確定了列數(shù)和行數(shù),然后根據(jù)列數(shù)和屏幕寬度確定了視頻的寬度,接著根據(jù)視頻的寬高比和視頻寬度確定了視頻高度。同時(shí)也考慮了手機(jī)的橫豎屏情況(就是if (width > height)這行代碼)。
該Adapter對(duì)應(yīng)的layout的代碼如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/user_control_mask" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">
<ImageView android:id="@+id/default_avatar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:visibility="gone" android:src="@drawable/icon_default_avatar" android:contentDescription="DEFAULT_AVATAR"/>
<ImageView android:id="@+id/indicator" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_alignParentBottom="true" android:layout_marginBottom="@dimen/video_indicator_bottom_margin" android:contentDescription="VIDEO_INDICATOR"/>
<LinearLayout android:id="@+id/video_info_container" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_marginTop="24dp" android:layout_marginStart="15dp" android:layout_marginLeft="15dp" android:visibility="gone" android:orientation="vertical">
<TextView android:id="@+id/video_info_metadata" android:layout_width="wrap_content" android:layout_height="wrap_content" android:singleLine="true" style="@style/NotificationUIText"/> </LinearLayout>
</RelativeLayout> |
我們可以看到,layout中有關(guān)尺寸的屬性都是wrap_content,這就使得item大小隨視頻寬高比變化成為可能。
把分屏的布局寫好之后,我們就可以在每一個(gè)item上播放聊天視頻了。
播放聊天視頻
在Agora SDK中一個(gè)遠(yuǎn)程視頻的顯示只和該用戶的UID有關(guān),所以使用的數(shù)據(jù)源只需要簡(jiǎn)單定義為包含UID和對(duì)應(yīng)的SurfaceView即可,就像這樣:
private finalHashMap<Integer, SurfaceView> mUidsList= newHashMap<>(); |
每當(dāng)有人加入了我們的聊天頻道,都會(huì)觸發(fā)onFirstRemoteVideoDecoded(int uid, int width, int height, int elapsed)方法,第一個(gè)uid就是他們的UID;接下來我們要為每個(gè)item新建一個(gè)SurfaceView并為其創(chuàng)建渲染視圖,最后將它們加入剛才創(chuàng)建好的mUidsList里并調(diào)用setupRemoteVideo( VideoCanvas remote )方法播放這個(gè)聊天視頻。這個(gè)過程的完整代碼如下:
@Override public voidonFirstRemoteVideoDecoded(intuid, intwidth, intheight, intelapsed) { doRenderRemoteUi(uid); }
private voiddoRenderRemoteUi(final intuid) { runOnUiThread(newRunnable() { @Override public voidrun() { if(isFinishing()) { return; }
if(mUidsList.containsKey(uid)) { return; }
SurfaceView surfaceV = RtcEngine.CreateRendererView(getApplicationContext()); mUidsList.put(uid, surfaceV);
booleanuseDefaultLayout = mLayoutType== LAYOUT_TYPE_DEFAULT;
surfaceV.setZOrderOnTop(true); surfaceV.setZOrderMediaOverlay(true);
rtcEngine().setupRemoteVideo(newVideoCanvas(surfaceV, VideoCanvas.RENDER_MODE_HIDDEN, uid));
if(useDefaultLayout) { log.debug("doRenderRemoteUi LAYOUT_TYPE_DEFAULT "+ (uid & 0xFFFFFFFFL)); switchToDefaultVideoView(); } else{ intbigBgUid = mSmallVideoViewAdapter== null? uid : mSmallVideoViewAdapter.getExceptedUid(); log.debug("doRenderRemoteUi LAYOUT_TYPE_SMALL "+ (uid & 0xFFFFFFFFL) + " "+ (bigBgUid & 0xFFFFFFFFL)); switchToSmallVideoView(bigBgUid); } } }); } |
以上代碼與前文中播放一對(duì)一視頻的代碼如出一撤,但是細(xì)心的讀者可能已經(jīng)發(fā)現(xiàn)我們并沒有將生成的SurfaceView放在界面里,這正是與一對(duì)一視頻的不同之處:我們要在一個(gè)抽象的VideoViewAdapter類里將SurfaceView放出來,關(guān)鍵代碼如下:
SurfaceView target = user.mView; VideoViewAdapterUtil.stripView(target); holderView.addView(target, 0, newFrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); |
一般Android工程師看見holderView就明白這是ViewHolder的layout的根layout了,而user是哪兒來的,詳見文末的代碼,文中不做贅述。
這樣在多人聊天的時(shí)候我們就能使用分屏的方式播放用戶聊天視頻了,如果想放大某一個(gè)用戶的視頻該怎么辦呢?
全屏和小窗
當(dāng)用戶雙擊某一個(gè)item的時(shí)候,他希望對(duì)應(yīng)的視頻能夠全屏顯示,而其他的視頻則變成小窗口,那么我們先定義一個(gè)雙擊事件接口:
public interfaceVideoViewEventListener { voidonItemDoubleClick(View v, Object item); } |
具體實(shí)現(xiàn)方式如下:
mGridVideoViewContainer.setItemEventHandler(newVideoViewEventListener() { @Override public voidonItemDoubleClick(View v, Object item) { log.debug("onItemDoubleClick "+ v + " "+ item + " "+ mLayoutType);
if(mUidsList.size() < 2) { return; }
UserStatusData user = (UserStatusData) item; intuid = (user.mUid== 0) ? config().mUid: user.mUid;
if(mLayoutType== LAYOUT_TYPE_DEFAULT&& mUidsList.size() != 1) { switchToSmallVideoView(uid); } else{ switchToDefaultVideoView(); } } }); |
將被選中的視頻全屏播放的方法很容易理解,我們只看生成小窗列表的方法:
private voidswitchToSmallVideoView(intbigBgUid) { HashMap<Integer, SurfaceView> slice = newHashMap<>(1); slice.put(bigBgUid, mUidsList.get(bigBgUid)); Iterator<SurfaceView> iterator = mUidsList.values().iterator(); while(iterator.hasNext()) { SurfaceView s = iterator.next(); s.setZOrderOnTop(true); s.setZOrderMediaOverlay(true); }
mUidsList.get(bigBgUid).setZOrderOnTop(false); mUidsList.get(bigBgUid).setZOrderMediaOverlay(false);
mGridVideoViewContainer.initViewContainer(this, bigBgUid, slice, mIsLandscape);
bindToSmallVideoView(bigBgUid);
mLayoutType= LAYOUT_TYPE_SMALL;
requestRemoteStreamType(mUidsList.size()); } |
小窗列表要注意移除全屏的那個(gè)UID,此外一切都和正常瀑布流視圖相同,包括雙擊小窗的item將其全屏播放。
到了這里我們就已經(jīng)使用Agora SDK完成了一個(gè)有基本功能的簡(jiǎn)單多人聊天demo,要產(chǎn)品化還有很多的東西要做,在這里先做一個(gè)簡(jiǎn)單的總結(jié)吧!
Agora SDK使用總結(jié)
聲網(wǎng)Agora提供了高質(zhì)量的視頻通信SDK,不僅覆蓋了主流的操作系統(tǒng),集成效率也比較高,而且還支持包括聊天,會(huì)議,直播等功能在內(nèi)的多個(gè)模式的視頻通話。SDK中API設(shè)計(jì)基本能夠滿足大部分的開發(fā)需要,而且隱藏了底層開發(fā),只需要提供SurfaceView和UID即可播放視頻,這樣對(duì)于App層的開發(fā)者來說十分友好。非常適合有視頻聊天開發(fā)需求的開發(fā)者。在視頻領(lǐng)域創(chuàng)業(yè)大爆發(fā)的今天,建議更多的想要從事該領(lǐng)域的開發(fā)者可以嘗試下。
當(dāng)然聲網(wǎng)Agora也并非盡善盡美,有些地方還有改進(jìn)的空間,我有兩個(gè)建議,以往廠商可以考慮下:
1、Agora支持Kotlin,目前Kotlin現(xiàn)在已經(jīng)成為Google官方建議的Android開發(fā)語(yǔ)言,支持Kotlin有助于跟上時(shí)代的步伐。但Agora并沒有把Kotlin的demo放在官網(wǎng)上。
2、希望可以提供帶基礎(chǔ)UI的SDK,就像UMeng的分享SDK一樣或者AMap的導(dǎo)航SDK,一套帶簡(jiǎn)單UI的SDK不僅能直接應(yīng)用到項(xiàng)目中,還允許開發(fā)者進(jìn)一步定制,這樣更容易收到App層的開發(fā)者技術(shù)選型時(shí)的青睞,他們的集成效率也會(huì)更高。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。
當(dāng)前題目:Android多人視頻聊天應(yīng)用的開發(fā)(三)多人聊天-創(chuàng)新互聯(lián)
網(wǎng)頁(yè)URL:http://chinadenli.net/article16/dejidg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供外貿(mào)建站、標(biāo)簽優(yōu)化、面包屑導(dǎo)航、營(yíng)銷型網(wǎng)站建設(shè)、網(wǎng)站內(nèi)鏈、外貿(mào)網(wǎng)站建設(shè)
廣告
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源:
創(chuàng)新互聯(lián)