当前位置:   article > 正文

快速接入腾讯TUIKaraoke在线 K 歌场景_腾讯k歌api

腾讯k歌api

组件介绍

TUIKaraoke 是一个开源的音视频 UI 组件,集成了 腾讯云实时音视频、即时通信、正版曲库直通车等产品,通过在项目中集成 TUIKaraoke 组件,只需要编写几行代码就可以为您的应用添加在线 K 歌场景,体验 K 歌、麦位管理、收发礼物、文字聊天等 TRTC 在 KTV 场景下的相关能力。

基本功能如下图所示:

在这里插入图片描述

  • 房主创建新的 Karaoke 房间开播,听众进入 Karaoke 房间收听/互动。
  • 房主可以管理点歌、将座位上的麦上主播踢下麦。
  • 房主还能对座位进行封禁,其他听众就不能再进行申请上麦了。
  • 听众可以申请上麦,变成麦上主播,上麦后可以点歌和唱歌,也可以随时下麦成为普通的听众。
  • 支持发送礼物和各种文本、自定义消息,自定义消息可用于实现弹幕、点赞等。

房间内的角色及描述

角色描述
房主歌房创建者
连麦主播进入歌房后,通过上麦成为连麦主播
主唱连麦主播点歌后进行排麦演唱,正在演唱者成为主唱
听众进入歌房的倾听者

核心功能

  • 实时音频互动:超低延时观看,听众实时接收房主和连麦主播的音频流,保证互动的流畅性。
  • 互动连麦:听众可上麦成为连麦主播,房间内所有用户都可以实时收听麦上主播互动。
  • 正版曲库:正版曲库直通车提供超20w热门曲目,全套高精度伴奏歌词,多码率音质灵活应用,搜索/榜单/歌手分类多维选曲。
  • 排麦模块:连麦主播点歌后,歌曲进入已点列表;当同时上麦人数大于 1 时,根据每首点播歌曲的排麦顺序上麦演唱。
  • 歌词模块:歌曲播放时,根据播放进度显示对应的歌词;听众收听的歌曲进度与歌词进度实时同步。

今天我们来体验一下,如何使用TUIKaraoke组件来快速搭建在线K歌。
当然在实验之前需要做一些准备,诸如环境配置,获取AppID和密钥等。

获取应用的SDKAppID和密钥

如果您未开通腾讯云 TRTC 服务,可进入 腾讯云实时音视频控制台,创建一个新的 TRTC 应用后,在应用管理列表里面找到当前的应用:

在这里插入图片描述

点击配置管理,进入到应用信息页面,在应用信息里面就可以找到SDKAppID:

在这里插入图片描述

点击快速上手,第二步 获取签发UserSig的密钥Secretkey:

在这里插入图片描述

环境准备

  • 最低兼容 Android 4.2(SDK API Level 17),建议使用 Android 5.0 (SDK API Level 21)及以上版本
  • Android Studio 3.5及以上版本

我们用最新版的Android Studio创建新项目,或者在你的项目里面Android Studio 需要3.5及以上版本,API Level 至少是17,官方建议 21以上。另外如果是体验官方的demo,gradle版本还是使用demo的gradle-wrapper.properties里面的设置,jdk使用1.8。在我们的新项目里面或者现有项目里面就可以不用按照demo的来了。这里我创建的新项目语言是kotlin,gradle版本是7.4.2,当然jdk也相应的使用了jdk16。放一张我的配置

在这里插入图片描述

可以通过Use Gradle from选择使用自己本地下载好的gradle,或者还是按照gradle-wrapper.properties里面配置的去下载就行了。

组件集成

下载并导入 TUIKaraoke 组件

1.单击进入 GitHub - tencentyun/TUIKaraoke,选择克隆/下载代码,然后拷贝 Android目录下的 tuikaraokedebug 目录到您的工程中(debug :调试相关, tuikaraoke : KTV业务逻辑)。
在这里插入图片描述

  1. 接着在 setting.gradle 中导入如下配置:
include ':tuikaraoke'
include ':debug'
  • 1
  • 2

3.在 app 的 build.gradle 文件中添加对 TUIKaraoke 的依赖:

api project(':tuikaraoke')
  • 1

4.在根目录的 build.gradle 文件中添加 TRTC SDKIM SDK 的依赖:

ext {
liteavSdk = "com.tencent.liteav:LiteAVSDK_TRTC:latest.release" 
imSdk = "com.tencent.imsdk:imsdk-plus:latest.release" 
}
  • 1
  • 2
  • 3
  • 4

配置权限及混淆规则

AndroidManifest.xml 中配置 App 的权限,SDK 需要以下权限(6.0以上的 Android 系统需要动态申请麦克风、读取存储权限等):

// 使用场景:悬浮窗功能需要此权限;
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />        
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
// 使用场景:使用蓝牙耳机时需要此权限;
<uses-permission android:name="android.permission.BLUETOOTH" />                  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在 proguard-rules.pro 文件,将 SDK 相关类加入不混淆名单:

-keep class com.tencent.** { *; }
  • 1

配置工程

编译下载完成后项目里面已经有了tuikaraokedebug两个模块了
在这里插入图片描述

  1. 在项目里找到并打开 debug/src/main/java/com/tencent/liteav/debug/GenerateTestUserSig.java 文件。
    配置 GenerateTestUserSig.java 文件中的SDKAppIDSecretkey 为上面从腾讯云实时音视频控制台里面获取到的SDKAppID和秘钥。
    在这里插入图片描述

至此,项目的前期准备已经完成,试着编译下,不出意外的话应该可以编译成功。

接下来我们就一起一步一步来实现在线KTV场景啦。

实现在线KTV场景

初始化并登录

1.设置登录用户信息
用户进入应用时,需要收集登录用户信息,包括userId,userName还有头像等信息。
我们可以构造一个简单的登录界面,输入框只允许输入字符串类型,长度不超过32字节,不支持使用特殊字符,使用英文或数字来设置userId。大致如下:

在这里插入图片描述

当然,我们可以根据自己具体的项目结合业务实际账号体系自行设置。
TUIKaraoke提供了两个类,UserModel模型类和UserModelManager管理类来管理用户信息。
构造好用户模型信息后就可以使用UserModelManager实例来存储为后续使用:

    private fun login() {
        val userId = mEditUserId.text.toString().trim()
        val userModel = UserModel()
        userModel.apply {
            this.userId = userId
            userName = userId
            userSig = GenerateTestUserSig.genTestUserSig(userId)
            val index = Random().nextInt(AvatarConstant.USER_AVATAR_ARRAY.count())
            val coverUrl = AvatarConstant.USER_AVATAR_ARRAY[index]
            userAvatar = coverUrl
        }
        val manager = UserModelManager.getInstance()
        manager.userModel = userModel

        val intent = Intent(this, MainActivity::class.java)
        startActivity(intent)
        finish()
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

其中 userSig:根据 SDKAppId、userId,Secretkey 等信息计算得到的安全保护签名,可以使用TUIKaraoke 提供的GenerateTestUserSig.genTestUserSig 计算,或者参考 如何计算及使用 UserSig实现。

2.配置TRTCKaraokeRoom 组件,TRTCKaraokeRoom 是基于腾讯云实时音视频(TRTC)和即时通信 IM 服务组合而成的组件,支持提供一系列房间列表、房间热度、主播列表等功能,比如创建房间,管理点歌上麦,发送礼物和各种文本、自定义消息,自定义消息可用于实现弹幕、点赞等。

首先通过sharedInstance来获取TRTCKaraokeRoom 单例对象。

 public static synchronized TRTCKaraokeRoom sharedInstance(Context context);
  • 1

接着通过TRTCKaraokeRoom的login方法登录到服务:

public abstract void login(int sdkAppId,
 String userId, String userSig,
TRTCKaraokeRoomCallback.ActionCallback callback);
  • 1
  • 2
  • 3

userIduserSig可以从我们前面登录的信息里面拿到,接下来就简单了,代码如下:

 /**
     * 初始化实例并登录
     */
    private fun initData() {
        // 1.初始化 获取 TRTCKaraokeRoom 单例对象
        mTRTCKaraokeRoom = TRTCKaraokeRoom.sharedInstance(this)
        // 2.登录
        mTRTCKaraokeRoom.login(
            GenerateTestUserSig.SDKAPPID,
            userModel.userId,  //当前用户的 ID,字符串类型,只允许包含英文字母(a-z 和 A-Z)、数字(0-9)、连词符(-)和下划线(_)
            userModel.userSig   //签名
        ) { code, _ ->
            if (code == 0) {//登录成功回调,成功时 code 为0。

                //修改个人信息
                mTRTCKaraokeRoom.setSelfProfile(
                    userModel.userName,
                    userModel.userAvatar
                ) { code, _ ->
                    if (code == 0) {
                        Log.d(TAG, "修改个人信息成功")
                    }
                }
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

TRTCKaraokeRoom服务配置好了后,我们就可以管理房间了,创建房间或者进入房间,也可以获取房间列表。
其中创建房间和进入房间需要按两步走,只有房主才能创建房间,销毁房间,听众只能进入房间,退出房间。

创建房间

创建房间我们使用TUIKaraoke提供的KaraokeRoomCreateDialog弹窗就可以了,我们只需要提供登录的房主信息,具体的创建房间就由TUIKaraoke来完成就好了。
在这里插入图片描述
调用弹窗的代码如下:

/**
     * 创建房间(房主调用),若房间不存在,系统将自动创建一个新房间。
     */
    private fun createRoom() {
        val dialog = KaraokeRoomCreateDialog(this)
        dialog.showRoomCreateDialog(
            userModel.userId,
            userModel.userId,
            userModel.userAvatar,
            TRTCCloudDef.TRTC_AUDIO_QUALITY_DEFAULT,
            true
        )
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

不幸的是,在这里,大家打开弹窗的时候可能会报错。

  • com.tencent.liteav.tuikaraoke.ui.room.KaraokeRoomBaseActivity requestFeature使用报错。报错信息是
java.lang.RuntimeException: 
Unable to start activity ComponentInfo{com.mariko.karaoke/com.tencent.liteav.tuikaraoke.ui.room.KaraokeRoomAnchorActivity}: 
android.util.AndroidRuntimeException: requestFeature()must be called before adding content
  • 1
  • 2
  • 3

需要修改KaraokeRoomBaseActivity 由继承 AppCompatActivity 改为 Activity

创建歌曲管理实现类

1.拷贝歌曲管理类实现。
在打开弹窗的时候还有个错误:

 java.lang.RuntimeException: Unable to start activity ComponentInfo {com.mariko.karaoke/com.tencent.liteav.tuikaraoke.ui.room.KaraokeRoomAnchorActivity}: java.lang.NullPointerException:
  Attempt to invoke virtual method  'void com.tencent.liteav.tuikaraoke.ui.music.KaraokeMusicService.setRoomInfo(com.tencent.liteav.tuikaraoke.model.TRTCKaraokeRoomDef$RoomInfo)'
  on a null object reference
  • 1
  • 2
  • 3

原因是在KaraokeRoomAnchorActivity里面KaraokeMusicService.setRoomInfo调用崩溃了,为什么会崩溃呢?原来通过KaraokeMusicService是通过 mPakcageName 反射创建管理实现的:

// 通过反射创建歌曲管理实现类的实例
  public void createKTVMusicImpl() {
      try {
          Class clz = Class.forName(mPakcageName);
          Constructor constructor = clz.getConstructor(Context.class);
          mKaraokeMusicService = (KaraokeMusicService) constructor.newInstance(this);
      } catch (Exception e) {
          e.printStackTrace();
      }
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

找到mPakcageName

private String   mPakcageName = "com.tencent.liteav.demo.karaokeimpl.KaraokeMusicServiceImpl";
  • 1

在我们的项目的里面是没有的,提示我们要实现这个歌曲管理类,然后替换。

为了快速实现,我们从 GitHub - tencentyun/TUIKaraoke, 选择已经下载的demo代码里面,找到TUIKaraoke/Android/app/src/main/java/com/tencent/liteav/demo/karaokeimpl的karaokeimpl文件夹,拷贝到我们的项目里面,记得更改下包名,最后如下图所示:
在这里插入图片描述

2.拷贝本地音频文件。
从demo项目里面拷贝assets目录里面的音频文件和字幕。
在这里插入图片描述
3.加载音频文件。
在进入房间之前,也就是打开弹窗之前需要将本地的音频文件预先加载到内存里面。
使用一个公共方法加载音频或者字幕:

public static void copyAssetsToFile(Context context, String name) {
        String savePath = ContextCompat.getExternalFilesDirs(context, null)[0].getAbsolutePath();
        String filename = savePath + "/" + name;
        File dir = new File(savePath);
        // 如果目录不存在,创建这个目录
        if (!dir.exists()) {
            dir.mkdir();
        }
        try {
            if (!(new File(filename)).exists()) {
                InputStream is = context.getResources().getAssets().open(name);
                FileOutputStream fos = new FileOutputStream(filename);
                byte[] buffer = new byte[7168];
                int count = 0;
                while ((count = is.read(buffer)) > 0) {
                    fos.write(buffer, 0, count);
                }
                fos.close();
                is.close();
            }
        } catch (Exception e) {
            e.printStackTrace();

        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

然后再分别加载所有文件:

public static void initLocalData(Context context) {
        copyAssetsToFile(context, "houlai_bz.mp3");
        copyAssetsToFile(context, "houlai_yc.mp3");

        copyAssetsToFile(context, "qfdy_yc.mp3");
        copyAssetsToFile(context, "qfdy_bz.mp3");

        copyAssetsToFile(context, "xq_bz.mp3");
        copyAssetsToFile(context, "xq_yc.mp3");

        copyAssetsToFile(context, "nuannuan_bz.mp3");
        copyAssetsToFile(context, "nuannuan_yc.mp3");

        copyAssetsToFile(context, "jda.mp3");
        copyAssetsToFile(context, "jda_bz.mp3");

        copyAssetsToFile(context, "houlai_lrc.vtt");
        copyAssetsToFile(context, "qfdy_lrc.vtt");
        copyAssetsToFile(context, "xq_lrc.vtt");
        copyAssetsToFile(context, "nuannuan_lrc.vtt");
        copyAssetsToFile(context, "jda_lrc.vtt");
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

我们使用的歌曲来自本地的,当然可以增加自己的实现,调用api从腾讯云正版曲库获取歌曲。
在这里插入图片描述
在这里插入图片描述

至此创建房间的弹窗应该可以打开了,K歌房间也可以进去啦。

房间主界面

打开弹窗后TUIKaraoke是通过KaraokeRoomAnchorActivity来创建房间和K歌主界面的,KaraokeRoomAnchorActivity继承自KaraokeRoomBaseActivity,KaraokeRoomBaseActivity主要是加载界面和处理一些事件等,位于tuikaraoke.ui.room 目录下。页面布局是R.layout.trtckaraoke_activity_main
在这里插入图片描述
我们要做一些定制可以从布局上面顺藤摸瓜了。

消息回显

在K歌界面我们看到了一段 欢迎消息,同时还有有跳转的链接:
在这里插入图片描述

很想把它换掉或者去掉对不对?
其实他就是一个欢迎消息的回显。
在房间里面我们有很多消息类型,有的是文本消息,还有的是带同意按钮的邀请等待的消息,消息的实体tuikaraoke.ui.widget.msg.MsgEntityMsgEntity实体类:

package com.tencent.liteav.tuikaraoke.ui.widget.msg;

public class MsgEntity {
    public static final int TYPE_NORMAL       = 0;
    public static final int TYPE_WAIT_AGREE   = 1;
    public static final int TYPE_AGREED       = 2;
    public static final int TYPE_WELCOME      = 3;
    public static final int TYPE_ORDERED_SONG = 4;
    public static final int TYPE_ERROR        = -1;

    public String  userId;
    public String  userName;
    public String  content;
    public String  invitedId;
    public String  linkUrl;
    public int     type;
    public int     color;
    public boolean isChat;
    public String  songName;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

有6种类型:

 * 普通消息:      TYPE_NORMAL        消息的内容会在界面显示出来
 * 邀请等待的消息: TYPE_WAIT_AGREE    消息中会有同意的按钮,可以进行事件处理
 * 邀请已同意消息: TYPE_AGREED        邀请消息已被处理,事件按钮被隐藏
 * 欢迎消息:      TYPE_WELCOME       会出现在界面中,同时有跳转的链接url
 * 点歌消息:      TYPE_ORDERED_SONG  消息中会有管理点歌的按钮,房主可以进行事件处理
  • 1
  • 2
  • 3
  • 4
  • 5

TUIKaraoke提供了一个消息互动显示的适配器MsgListAdapter,根据消息的类型显示不同的样式,消息的发送者的username可以对颜色进行设置,而且实现了监听按钮等的点击事件,当有消息添加到mList,就通知适配器刷新。
同时使用一个mRvImMsgRecyclerView来展示消息的。涉及到消息的几个属性如下:
KaraokeRoomBaseActivity文件:

protected RecyclerView               mRvImMsg;
protected MsgListAdapter             mMsgListAdapter;
protected List<MsgEntity>            mMsgEntityList;
  • 1
  • 2
  • 3

统一添加消息的入口是在KaraokeRoomBaseActivityshowImMsg方法里面:

 protected void showImMsg(final MsgEntity entity)
  • 1

到这里我们就可以找到在KaraokeRoomBaseActivityonCreate里面,开始加载页面的时候就新增了一条欢迎消息了:
在这里插入图片描述
消息的类型是TYPE_WELCOME,找到欢迎的文本和文本点击的链接是R.string.trtckaraoke_welcome_visitR.string.trtckaraoke_welcome_visit_link,在string.xml资源文件里面我们就可以重新设置为我们自己的,或者也可以不显示欢迎信息,把上面那段欢迎消息注释掉即可。

<string name="trtckaraoke_welcome_visit">"欢迎体验TRTC Karaoke!进一步了解如何快速搭建Karaoke,请点击: "</string>
<string name="trtckaraoke_welcome_visit_link">"https://cloud.tencent.com/document/product/647/59403"</string>
  • 1
  • 2
礼物面板
  • 更换查询礼物信息的实现

首先在KTV界面的xml 布局 trtckaraoke_activity_main.xml中找到礼物按钮

 <androidx.appcompat.widget.AppCompatImageButton
            android:id="@+id/btn_more_gift"
            style="@style/TRTCKtvRoomButtonStyle"
            android:layout_marginEnd="20dp"
            android:background="@drawable/trtckaraoke_ic_gift" />
  • 1
  • 2
  • 3
  • 4
  • 5

接着查看礼物按钮的点击事件:

 mBtnGift.setOnClickListener(new View.OnClickListener() {
    @Override
	public void onClick(View v) {
		 showGiftPanel();
	 }
 });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

事件中打开的就是展示礼物面板

//展示礼物面板
    private void showGiftPanel() {
        IGiftPanelView giftPanelView = new GiftPanelViewImp(this);
        giftPanelView.init(mGiftInfoDataHandler);
        giftPanelView.setGiftPanelDelegate(new GiftPanelDelegate() {
            @Override
            public void onGiftItemClick(GiftInfo giftInfo) {
                sendGift(giftInfo);
            }

            @Override
            public void onChargeClick() {

            }
        });
        giftPanelView.show();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

可以看到我们的礼物面板是一个弹窗GiftPanelViewImp,继承自BottomSheetDialog。它完整实现了礼物的接口IGiftPanelView,我们完全要定制礼物面板的话也需要实现这套接口:

public interface IGiftPanelView {
    /**
     * 面板通用接口
     */
    void init(GiftInfoDataHandler giftInfoDataHandler);

    /**
     * 打开礼物面板
     */
    void show();

    /**
     * 关闭礼物面板
     */
    void hide();

    //订阅礼物面板事件
    void setGiftPanelDelegate(GiftPanelDelegate delegate);

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

创建一个实例就是通过void init(GiftInfoDataHandler giftInfoDataHandler)来初始化的,入参是一个GiftInfoDataHandler,它包含了如何获取礼物信息和获取成功失败后的回调。
看下GiftInfoDataHandler类:

public class GiftInfoDataHandler {
    private static final String TAG = "GiftInfoManager";

    private GiftAdapter           mGiftAdapter;
    private Map<String, GiftInfo> mGiftInfoMap = new HashMap<>();

    public void setGiftAdapter(GiftAdapter adapter) {
        mGiftAdapter = adapter;
        queryGiftInfoList(null);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

构造一个GiftInfoDataHandler需要一个实现了GiftAdapter的获取礼物信息的适配器mGiftAdapter

public abstract class GiftAdapter {
    /**
     * 查询礼物信息
     *
     * @param callback
     */
    public abstract void queryGiftInfoList(OnGiftListQueryCallback callback);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

KaraokeRoomBaseActivity类里可以找到initData房里初始化了mGiftInfoDataHandler,通过传入一个默认实现的DefaultGiftAdapterImp来构造mGiftInfoDataHandler:

 // 礼物
	 GiftAdapter giftAdapter = new DefaultGiftAdapterImp();
	 mGiftInfoDataHandler = new GiftInfoDataHandler();
	 mGiftInfoDataHandler.setGiftAdapter(giftAdapter);
  • 1
  • 2
  • 3
  • 4

到这里已经是拨开云雾见青天啦,其实我们要找的就是这个DefaultGiftAdapterImp,是它实现如何获取礼物的,那么先看下DefaultGiftAdapterImp 类:

public class DefaultGiftAdapterImp extends GiftAdapter implements HttpGetRequest.HttpListener {
    private static final String TAG = "DefaultGiftAdapterImp";

    private static final int    CORE_POOL_SIZE = 5;
    private static final String GIFT_DATA_URL  = "https://liteav.sdk.qcloud.com/app/res/picture/live/gift/gift_data.json";

    private GiftBeanThreadPool      mGiftBeanThreadPool;
    private OnGiftListQueryCallback mOnGiftListQueryCallback;

    @Override
    public void queryGiftInfoList(final OnGiftListQueryCallback callback) {
        mOnGiftListQueryCallback = callback;
        ThreadPoolExecutor threadPoolExecutor = getThreadExecutor();
        HttpGetRequest     request            = new HttpGetRequest(GIFT_DATA_URL, this);
        threadPoolExecutor.execute(request);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

我们看到它实现GiftAdapter接口的查询礼物信息的方法queryGiftInfoList,在queryGiftInfoList方法里面我们看到它是通过http请求从网络服务器上获取到了礼物数据的,接口地址就是

 private static final String GIFT_DATA_URL  = "https://liteav.sdk.qcloud.com/app/res/picture/live/gift/gift_data.json";
  • 1

试着从浏览器里面打开接口看下返回数据
在这里插入图片描述
接口返回的数据类型是GiftBean,DefaultGiftAdapterImp又做了一层转换,转换成后面要方便处理的GiftData类型:

public class GiftData {
    // 礼物id
    public String giftId;
    //礼物图片对应的url
    public String giftPicUrl;
    //礼物全屏动画url
    public String lottieUrl;
    //礼物的名称
    public String title;
    //礼物价格
    public int    price;
    //礼物类型 0为普通礼物, 1为播放全屏动画
    public int    type;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

到这里我们其实就可以模仿DefaultGiftAdapterImp做一套自己的实现,或者根据自己的业务需要实现自己的网络接口,按照GiftData模型返回数据类型就行。

  • 调整礼物面板显示
    通过查看礼物面板GiftPanelViewImp的代码,它是通过一个ViewPager来切换不同页的,每页显示的礼物是一个List<View>
  1. 设置礼物多行显示。
    默认的list是单行显示的,我们可以设置为多行。
    GiftPanelViewImp类里面找到mDefalutPanelType属性,它是个String类型,默认值是一个常量GIFT_PANEL_TYPE_SINGLEROW,指向的字符串是single_row,也就是单行,我们可以修改为多行显示。
    在定义GIFT_PANEL_TYPE_SINGLEROW常量的文件里,我们找到多行显示的常量GIFT_PANEL_TYPE_MULTIROW,替换下mDefalutPanelType的值:
private String mDefalutPanelType = GIFT_PANEL_TYPE_MULTIROW;
  • 1

运行项目显示的效果如下:
在这里插入图片描述
显示了两行礼物,随着礼物数量增多就可以实时适配多行显示了。

  1. 实现礼物点击和充值事件。
    在礼物面板上我们已经看到了各种礼物还有右下角的充值按钮了。我们只需要订阅礼物面板的事件就可以实现我们自己的需求了。
    礼物面板事件:
public interface GiftPanelDelegate {
    /**
     * 礼物点击事件
     */
    void onGiftItemClick(GiftInfo giftInfo);

    /**
     * 充值点击事件
     */
    void onChargeClick();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在实例化礼物面板的时候,KaraokeRoomBaseActivity已经帮我们实现了礼物的点击事件了:

giftPanelView.setGiftPanelDelegate(new GiftPanelDelegate() {
            @Override
            public void onGiftItemClick(GiftInfo giftInfo) {
                sendGift(giftInfo);
            }

            @Override
            public void onChargeClick() {

            }
        });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

sendGift方法就是发送礼物消息出去同时展示礼物动画和弹幕,还有处理弹幕消息的handleGiftMsg方法等。
充值点击事件就需要我们根据业务的需要自己实现啦。

播放礼物动画

查看TUIKaraoke并没有提供播放礼物动画,我们可以尝试着自己在TUIKaraoke的基础上简单实现一个使用Lottie播放动画的需求。
Lottie是支持Android, iOS, 和React Native,并且只需简单的代码就可以实现复杂动画效果的库,具体使用我们可以参考lottie-android

在TUIKaraoke的build.gradle文件里面引入Lottie库:

implementation 'com.airbnb.android:lottie:5.2.0'
  • 1

在KTV主页面布局trtckaraoke_activity_main里面最外层新增LottieAnimationView控件:

<androidx.constraintlayout.widget.ConstraintLayout
...
....
 <com.airbnb.lottie.LottieAnimationView
        android:id="@+id/lt_gift"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:lottie_autoPlay="false"
        app:lottie_loop="false"
        app:lottie_repeatMode="restart" />
</androidx.constraintlayout.widget.ConstraintLayout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

定义LottieAnimationView属性,并新增监听动画完成事件,播放完动画后隐藏控件。

	private LottieAnimationView mLottieAnimationView;
	
	mLottieAnimationView = findViewById(R.id.lt_gift);
	mLottieAnimationView.addAnimatorListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
                mLottieAnimationView.setVisibility(View.VISIBLE);
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                mLottieAnimationView.setVisibility(View.GONE);
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
	});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

新增一个方法来开始播放动画:

 //展示礼物动画
    private void showGiftLottieAnimation(String lottieUrl) {
        mLottieAnimationView.setVisibility(View.VISIBLE);
        mLottieAnimationView.setAnimationFromUrl(lottieUrl);
        mLottieAnimationView.playAnimation();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

接下来需要在两个地方添加播放动画,一个就是点击礼物的时候播放,另一个是在收到别人发送礼物的时候播放动画了。

在打开礼物面板初始化的时候,礼物面板的点击礼物的delega里面:

//展示礼物面板
    private void showGiftPanel() {
        IGiftPanelView giftPanelView = new GiftPanelViewImp(this);
        giftPanelView.init(mGiftInfoDataHandler);
        giftPanelView.setGiftPanelDelegate(new GiftPanelDelegate() {
            @Override
            public void onGiftItemClick(GiftInfo giftInfo) {
                sendGift(giftInfo);
                //播放动画
                if (!giftInfo.lottieUrl.isEmpty()) {
                    showGiftLottieAnimation(giftInfo.lottieUrl);
                }
            }

            @Override
            public void onChargeClick() {

            }
        });
        giftPanelView.show();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

在收到消息里面,TUIKaraoke通过handleGiftMsg方法处理弹幕消息,在这个方法里面可以播放我们的礼物动画:

  /**
     * 处理礼物弹幕消息
     */
    private void handleGiftMsg(TRTCKaraokeRoomDef.UserInfo userInfo, String data) {
        if (mGiftInfoDataHandler != null) {
            Gson gson = new Gson();
            GiftSendJson jsonData = gson.fromJson(data, GiftSendJson.class);
            String giftId = jsonData.getGiftId();
            GiftInfo giftInfo = mGiftInfoDataHandler.getGiftInfo(giftId);
            if (giftInfo != null) {
                if (userInfo != null) {
                    giftInfo.sendUserHeadIcon = userInfo.userAvatar;
                    if (!TextUtils.isEmpty(userInfo.userName)) {
                        giftInfo.sendUser = userInfo.userName;
                    } else {
                        giftInfo.sendUser = userInfo.userId;
                    }
                }
                mGiftAnimatorLayout.show(giftInfo);
                //播放动画
                if (!giftInfo.lottieUrl.isEmpty()) {
                    showGiftLottieAnimation(giftInfo.lottieUrl);
                }
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

至此,当我们点击了含有lottieUrl的礼物的时候就可以看到礼物动画了。
在这里插入图片描述

回顾总结

总结一下,很多UI组件和功能TUIKaraoke都帮我们实现了,我们只需要在项目里面接入就行了,然后在TUIKaraoke里面修改下配置,通过接口增加我们的实现,也可以在TUIKaraoke的基础上稍加修改就可以基本上完成我们的需求了。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小舞很执着/article/detail/735793
推荐阅读
相关标签
  

闽ICP备14008679号