需要源码请点赞关注收藏后评论区留言私信~~~
近年来电商业态发生了不小的改变,传统的电商平台把商品分门别类,配上精美的图文说明供消费者挑选,新潮的电商平台则请来明星网红,开启直播秀向广大粉丝推销商品,往往一场直播就能达到数千万销售额。 这种新型的买卖行为被称作“直播带货”,主播们现场试用试穿试吃,还跟众多粉丝网络互动,同时直播形式让消费者如临其境,使人无法抑制购买欲望,这些都造就了精准、高效的直播电商。
主播在直播界面吆喝叫卖,观众浏览直播界面闲逛。除此以外,直播界面还提供下列功能:
(1)关注店铺、加入会员、领券、下单等等
(2)发表留言与主播聊天互动
(3)给主播打赏
下面是拼多多的助农计划界面 我们来实现一个类似于他的
(1)圆形图形:直播间左上角的房间标志经过了圆形裁剪。
(2)打赏视图:观众通过打赏礼物激励主播。
(3)Socket通信:与房间、观众有关的信令管理,需要采取Socket通信与后端服务器交互。 (4)移动数据格式JSON:客户端与服务器之间传输信令,需要把信令内容封装为JSON格式。 (5)实时音视频:开源库WebRTC适用于小型在线直播。
下面介绍代码模块之间的关系与作用
(1)LiveListActivity.java:这是直播房间的列表界面。
(2)LiveServerActivity.java:这是主播的预览界面。
(3)LiveClientActivity.java:这是观众的预览界面。
(4)服务端HttpServer模块中的VideoChatServer.java:处理Socket通信后端的信令消息传输。
此外,直播带货还需要与之配合的信令服务器,它涵盖了Socket通信后端的信令消息传输
直播间的事件消息
观众进入直播间后,一边是用户观看主播的表演,一边是App接收直播间的事件消息,这些事件消息又包括下列几类:
(1)自己加入直播间,引起直播间总人数变化;
(2)监听其他人加入房间与退出房间的事件,并实时刷新直播间总人数;
(3)自己可以发表聊天消息,也能收到别人发表的聊天消息;
(4)监听房间的关闭事件,一旦房间被主播关闭,就要自动退出该房间;
一旦观众上线下线,进入房间或者离开房间都要改变观众在房间映射表里的状态。
效果展示如下 可以作为观众 也可以作为主播
观众可以给主播的打赏或者关注 发评论等等
部分代码如下 需要全部代码请点赞关注收藏后评论区留言~~~
package com.example.live;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;
import com.example.live.adapter.EntityListAdapter;
import com.example.live.bean.EntityInfo;
import com.example.live.bean.RoomInfo;
import com.example.live.bean.RoomSet;
import com.example.live.util.SocketUtil;
import com.example.live.widget.InputDialog;
import com.google.gson.Gson;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.socket.client.Socket;
public class LiveListActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
private final static String TAG = "LiveListActivity";
private String mSelfName; // 我的昵称
private EntityListAdapter mAdapter; // 直播房间的列表适配器
private Map mRoomMap = new HashMap<>(); // 直播房间的名称映射
private List mRoomList = new ArrayList<>(); // 直播房间列表
private Socket mSocket; // 声明一个套接字对象
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_live_list);
mSelfName = getIntent().getStringExtra("self_name");
initView(); // 初始化视图
initSocket(); // 初始化套接字
}
// 初始化视图
private void initView() {
TextView tv_title = findViewById(R.id.tv_title);
tv_title.setText("直播房间列表");
findViewById(R.id.iv_back).setOnClickListener(v -> finish());
mAdapter = new EntityListAdapter(this, mRoomList);
ListView lv_room = findViewById(R.id.lv_room);
lv_room.setAdapter(mAdapter);
lv_room.setOnItemClickListener(this);
findViewById(R.id.btn_open_room).setOnClickListener(v -> openCreateDialog());
}
// 初始化套接字
private void initSocket() {
mSocket = MainApplication.getInstance().getSocket();
mSocket.connect(); // 建立Socket连接
// 等待服务器返回直播房间列表
mSocket.on("return_room_list", (args) -> {
JSONObject json = (JSONObject) args[0];
Log.d(TAG, "return_room_list: "+json.toString());
RoomSet roomSet = new Gson().fromJson(json.toString(), RoomSet.class);
if (roomSet!=null && roomSet.getRoom_list()!=null) {
Log.d(TAG, "getRoom_list().size: "+roomSet.getRoom_list().size());
mRoomMap.clear();
for (RoomInfo room : roomSet.getRoom_list()) {
mRoomMap.put(room.getRoom_name(), new EntityInfo(room.getRoom_name(), "主播:"+room.getAnchor_name(), room));
}
mRoomList.clear();
mRoomList.addAll(mRoomMap.values());
runOnUiThread(() -> mAdapter.notifyDataSetChanged());
}
});
// 等待新房间的开通事件
mSocket.on("room_have_opened", (args) -> {
JSONObject json = (JSONObject) args[0];
Log.d(TAG, "room_have_opened: "+json.toString());
RoomInfo room = new Gson().fromJson(json.toString(), RoomInfo.class);
mRoomMap.put(room.getRoom_name(), new EntityInfo(room.getRoom_name(), "主播:"+room.getAnchor_name(), room));
mRoomList.clear();
mRoomList.addAll(mRoomMap.values());
runOnUiThread(() -> mAdapter.notifyDataSetChanged());
});
// 等待原房间的关闭事件
mSocket.on("room_have_closed", (args) -> {
String roomName = (String) args[0];
mRoomMap.remove(roomName);
mRoomList.clear();
mRoomList.addAll(mRoomMap.values());
runOnUiThread(() -> mAdapter.notifyDataSetChanged());
});
}
@Override
protected void onResume() {
super.onResume();
// 向服务器请求获取直播房间列表
new Handler(Looper.myLooper()).postDelayed(() -> mSocket.emit("get_room_list", mSelfName), 500);
}
@Override
protected void onDestroy() {
super.onDestroy();
mSocket.off("return_room_list"); // 取消监听房间列表事件
mSocket.off("room_have_opened"); // 取消监听房间开通事件
mSocket.off("room_have_closed"); // 取消监听房间关闭事件
if (mSocket.connected()) { // 已经连上Socket服务器
mSocket.disconnect(); // 断开Socket连接
}
}
// 打开房间创建对话框
private void openCreateDialog() {
InputDialog didialog = new InputDialog(this, "", 0,
"请输入直播间名称", (idt, content, seq) -> {
String roomName = content;
RoomInfo room = new RoomInfo(mSelfName, roomName, new HashMap<>());
SocketUtil.emit(mSocket, "open_room", room); // 发送房间开通事件
// 主动开通房间,就跳到主播自己的直播页面
Intent intent = new Intent(this, LiveServerActivity.class);
intent.putExtra("self_name", mSelfName);
intent.putExtra("room_name", roomName);
startActivity(intent);
});
didialog.show(); // 弹出创建房间对话框
}
@Override
public void onItemClick(AdapterView> parent, View view, int position, long id) {
EntityInfo room = mRoomList.get(position);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(String.format("你是否要进入%s?", room.name));
builder.setPositiveButton("是", (dialog, which) -> {
// 想要进入某个房间,就跳到用户自己的直播页面
Intent intent = new Intent(this, LiveClientActivity.class);
intent.putExtra("self_name", mSelfName);
intent.putExtra("room_name", room.name);
intent.putExtra("anchor_name", ((RoomInfo) room.info).getAnchor_name());
startActivity(intent);
});
builder.setNegativeButton("否", null);
builder.create().show();
}
}
创作不易 觉得有帮助请点赞关注收藏~~~