欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

Android多人視頻聊天應(yīng)用的開發(fā)(三)多人聊天-創(chuàng)新互聯(lián)

在上一篇《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)

小程序開發(fā)