一卷旌收千骑虏,万全身出百重围。这篇文章主要讲述Android多人视频聊天应用的开发多人聊天相关的知识,希望能为你提供帮助。
在上一篇《android多人视频聊天应用的开发(二)一对一聊天》中我们学习了如何使用声网Agora SDK进行一对一的聊天,本篇主要讨论如何使用Agora SDK进行多人聊天。主要需要实现以下功能:
1、上一篇已经实现过的聊天功能
【Android多人视频聊天应用的开发多人聊天】2、随着加入人数和他们的手机摄像头分辨率的变化,显示不同的UI,即所谓的“分屏”
3、点击分屏中的小窗,可以放大显示该聊天窗
分屏
根据前期技术调研,分屏显示最好的方式是采用瀑布流结合动态聊天窗实现,这样比较方便的能够适应UI的变化。所谓瀑布流,就是目前比较流行的一种列表布局,会在界面上呈现参差不齐的多栏布局。我们先实现一个瀑布流:
瀑布流的实现方式很多,本文采用结合GridLayoutManager的RecyclerView来实现。我们首先自定义一个RecyclerView,命名为GridVideoViewContainer。核心代码如下:
int count = uids.size();
if (count < = 2) { // 只有本地视频或聊天室内只有另外一个人 this.setLayoutManager(new LinearLayoutManager(activity.getApplicationContext(), orientation, false)); } else if (count > 2) { // 多人聊天室 int itemSpanCount = getNearestSqrt(count); this.setLayoutManager(new GridLayoutManager(activity.getApplicationContext(), itemSpanCount, orientation, false)); } |
有了一个可用的瀑布流之后,下面我们就可以实现动态聊天窗了:
动态聊天窗的要点在于item的大小由视频的宽高比决定,因此Adapter及其对应的layout就该注意不要写死尺寸。在Adapter里控制item具体尺寸的代码如下:
if (force || mItemWidth == 0 || mItemHeight == 0) { WindowManager windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics outMetrics = new DisplayMetrics(); windowManager.getDefaultDisplay().getMetrics(outMetrics); int count = uids.size(); int DividerX = 1; int DividerY = 1; if (count == 2) { DividerY = 2; } else if (count > = 3) { DividerX = getNearestSqrt(count); DividerY = (int) Math.ceil(count * 1.f / DividerX); } int width = outMetrics.widthPixels; int height = outMetrics.heightPixels; if (width > height) { mItemWidth = width / DividerY; mItemHeight = height / DividerX; } else { mItemWidth = width / DividerX; mItemHeight = height / DividerY; } } |
该Adapter对应的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=https://www.songbingjia.com/android/" @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> |
把分屏的布局写好之后,我们就可以在每一个item上播放聊天视频了。
播放聊天视频
在Agora SDK中一个远程视频的显示只和该用户的UID有关,所以使用的数据源只需要简单定义为包含UID和对应的SurfaceView即可,就像这样:
private final HashMap<
Integer, SurfaceView>
mUidsList = new HashMap<
>
();
|
@Override public void onFirstRemoteVideoDecoded(int uid, int width, int height, int elapsed) { doRenderRemoteUi(uid); } private void doRenderRemoteUi(final int uid) { runOnUiThread(new Runnable() { @Override public void run() { if (isFinishing()) { return; } if (mUidsList.containsKey(uid)) { return; } SurfaceView surfaceV = RtcEngine.CreateRendererView(getApplicationContext()); mUidsList.put(uid, surfaceV); boolean useDefaultLayout = mLayoutType == LAYOUT_TYPE_DEFAULT; surfaceV.setZOrderOnTop(true); surfaceV.setZOrderMediaOverlay(true); rtcEngine().setupRemoteVideo(new VideoCanvas(surfaceV, VideoCanvas.RENDER_MODE_HIDDEN, uid)); if (useDefaultLayout) { log.debug(" doRenderRemoteUi LAYOUT_TYPE_DEFAULT " + (uid & 0xFFFFFFFFL)); switchToDefaultVideoView(); } else { int bigBgUid = mSmallVideoViewAdapter == null ? uid : mSmallVideoViewAdapter.getExceptedUid(); log.debug(" doRenderRemoteUi LAYOUT_TYPE_SMALL " + (uid & 0xFFFFFFFFL) + " " + (bigBgUid & 0xFFFFFFFFL)); switchToSmallVideoView(bigBgUid); } } }); } |
SurfaceView target = user.mView;
VideoViewAdapterUtil.stripView(target); holderView.addView(target, 0, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); |
这样在多人聊天的时候我们就能使用分屏的方式播放用户聊天视频了,如果想放大某一个用户的视频该怎么办呢?
全屏和小窗
当用户双击某一个item的时候,他希望对应的视频能够全屏显示,而其他的视频则变成小窗口,那么我们先定义一个双击事件接口:
public interface VideoViewEventListener { void onItemDoubleClick(View v, Object item); } |
mGridVideoViewContainer.setItemEventHandler(new VideoViewEventListener() { @Override public void onItemDoubleClick(View v, Object item) { log.debug(" onItemDoubleClick " + v + " " + item + " " + mLayoutType); if (mUidsList.size() < 2) { return; } UserStatusData user = (UserStatusData) item; int uid = (user.mUid == 0) ? config().mUid : user.mUid; if (mLayoutType == LAYOUT_TYPE_DEFAULT & & mUidsList.size() != 1) { switchToSmallVideoView(uid); } else { switchToDefaultVideoView(); } } }); |
private void switchToSmallVideoView(int bigBgUid) { HashMap< Integer, SurfaceView> slice = new HashMap< > (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()); } |
到了这里我们就已经使用Agora SDK完成了一个有基本功能的简单多人聊天demo,要产品化还有很多的东西要做,在这里先做一个简单的总结吧!
Agora SDK使用总结
声网Agora提供了高质量的视频通信SDK,不仅覆盖了主流的操作系统,集成效率也比较高,而且还支持包括聊天,会议,直播等功能在内的多个模式的视频通话。SDK中API设计基本能够满足大部分的开发需要,而且隐藏了底层开发,只需要提供SurfaceView和UID即可播放视频,这样对于App层的开发者来说十分友好。非常适合有视频聊天开发需求的开发者。在视频领域创业大爆发的今天,建议更多的想要从事该领域的开发者可以尝试下。
当然声网Agora也并非尽善尽美,有些地方还有改进的空间,我有两个建议,以往厂商可以考虑下:
1、Agora支持Kotlin,目前Kotlin现在已经成为Google官方建议的Android开发语言,支持Kotlin有助于跟上时代的步伐。但Agora并没有把Kotlin的demo放在官网上。
2、希望可以提供带基础UI的SDK,就像UMeng的分享SDK一样或者AMap的导航SDK,一套带简单UI的SDK不仅能直接应用到项目中,还允许开发者进一步定制,这样更容易收到App层的开发者技术选型时的青睐,他们的集成效率也会更高。
推荐阅读
- 安卓Day16-bug
- muiAPP与服务器之间的交互原理
- android 7.0 pm install 失败问题
- 抖音直播APP软件系统为什么能这么火(反映出的问题又会是什么?)
- AndroidMac下Android Studio设置App启动页
- Appium移动自动化测试之元素定位
- AndroidAndroid Studio3.1 Mac版本设置项目桌面icon
- AppScan简单应用
- respberry2b + android5.1