【Android App】实战项目之仿拼多多的直播带货(附源码和演示 超详细必看)

news2024/12/23 14:47:02

需要源码请点赞关注收藏后评论区留言私信~~~

近年来电商业态发生了不小的改变,传统的电商平台把商品分门别类,配上精美的图文说明供消费者挑选,新潮的电商平台则请来明星网红,开启直播秀向广大粉丝推销商品,往往一场直播就能达到数千万销售额。 这种新型的买卖行为被称作“直播带货”,主播们现场试用试穿试吃,还跟众多粉丝网络互动,同时直播形式让消费者如临其境,使人无法抑制购买欲望,这些都造就了精准、高效的直播电商。

一、需求描述

主播在直播界面吆喝叫卖,观众浏览直播界面闲逛。除此以外,直播界面还提供下列功能:

(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<String, EntityInfo> mRoomMap = new HashMap<>(); // 直播房间的名称映射
    private List<EntityInfo> 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();
    }
}

创作不易 觉得有帮助请点赞关注收藏~~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/59430.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微服务应对雪崩的容错方案

引言 书接上篇 微服务绕不过的坎-服务雪崩 &#xff0c;玩微服务不可避免的问题&#xff1a;服务雪崩&#xff0c;那为了应付服务雪崩问题&#xff0c;需要做啥预防性操作呢&#xff1f;答案是&#xff1a;做好容错保护 容错方案 前面说了&#xff0c;要防止雪崩的扩散&…

[附源码]计算机毕业设计springboot疫情期间小学生作业线上管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Android自定义视图

View 自定义视图主要涉及四个方面&#xff1a;绘图、交互、性能和封装 绘图 主要涉及两个对象&#xff1a;画布&#xff08;Canvas&#xff09;和画笔&#xff08;Paint&#xff09;&#xff0c;画布主要解决画什么的问题&#xff0c;在画布上可以绘制各种各样的图形&#x…

《CTFshow - Web入门》04. Web 31~40

Web 31~40web31知识点题解web32知识点题解web33知识点题解web34知识点题解web35知识点题解web36知识点题解web37知识点题解web38知识点题解web39知识点题解web40知识点题解web31 知识点 这里依旧可以用到 web29 的方法&#xff1a; 嵌套eval逃逸参数 当然&#xff0c;能多学…

# 智慧社区管理系统-基础信息管理-06抄表管理

一后端 1:entity package com.woniu.community.entity;import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;Data AllArgsConstructor NoArgsConstructor public class Records {private int id;private int typeId;private Double num…

博安生物更新招股书:上半年亏1.5亿 绿叶制药与建银聚源是股东

雷递网 雷建平 12月3日山东博安生物技术股份有限公司&#xff08;简称&#xff1a;“博安生物”&#xff09;日前再次递交招股书&#xff0c;并更新招股书&#xff0c;准备在香港上市。上半年期内亏损1.53亿元博安生物是绿叶制药集团的附属公司&#xff0c;于2013年成立&#x…

远程桌面树莓派【内网穿透】

本篇文章主要分享如何在公网环境下&#xff0c;远程桌面连接家里的树莓派。 远程桌面环境&#xff0c;我们选择通过XRDP来实现&#xff0c;它内部使用的是windows远程桌面的协议。 而由于现在普遍处于大内网环境&#xff0c;绝大部分人都没有公网IP&#xff0c;所以我们这里用…

(9)点云数据处理学习——Global registration(全局注册)

1、主要参考 &#xff08;1&#xff09;官网的地址 Global registration — Open3D 0.16.0 documentation 2、作用和原理 2.1个人理解 PS理解&#xff1a;&#xff08;1&#xff09;ICP的作用是&#xff0c;2个点云数据在初步转换关系&#xff08;已知不精确&#xff09;的…

【关系抽取】TPLinker:单阶段联合抽取,并解决暴漏偏差

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

车载GNSS/INS/LiDAR坐标系定义与理解

目录一、基本坐标系1.1 地心惯性坐标系&#xff08;Inertial coordinate system&#xff0c;i系&#xff09;1.2 地心地固坐标系&#xff08;Earth-Centered, Earth-Fixed&#xff0c;e系&#xff09;1.3 导航坐标系&#xff08;Navigation&#xff0c;n系&#xff09;1.4 车体…

[附源码]计算机毕业设计springboot疫苗药品批量扫码识别追溯系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

一、领域驱动设计核心思想与设计过程

一、软件发展的必然规律 1、软件是对真是世界的模拟&#xff0c;但真实世界软件十分复杂。 2、人在认识真实世界的时候总是有一个从简单到复杂的过程 3、软件需求的变更成为一种必然的事情&#xff0c;并且总是由简单向复杂转变 4、初期软件的业务逻辑十分简单清晰命令&#x…

C语言画直方图

前言 最近在看K&R的《C语言程序设计语言》这本书&#xff0c;第一单元的练习13要求画一个统计单词长度的直方图&#xff0c;这里忽略了计算单词长度的代码&#xff0c;假设已知单词长度存入一个digit数组中&#xff0c;根据这个数组画水平直方图和垂直直方图。实话说&…

C++11新特性-原始字面量

当我们书写文件路径的时候&#xff0c;会发现&#xff0c;文件路径无法正确输出&#xff0c;如下&#xff1a; 这是因为反斜杠本身就是转义的意思&#xff0c;如果想要输出反斜杠则需要两个反斜杠&#xff0c;如下&#xff1a; 当然这只是其中一种解决方法&#xff0c;还有一种…

实战项目如何抵御即跨站脚本(XSS)攻击

一、XSS攻击的危害 XSS攻击通常指的是通过利用网页开发时留下的漏洞&#xff0c;通过巧妙的方法注入恶意指令代码到网页&#xff0c;使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上也可以包括Java、VBScript、ActiveX、Flash或者甚至是…

思派健康通过上市聆讯:F轮估值17亿美元 腾讯是大股东

雷递网 雷建平 12月3日思派健康科技日前通过聆讯&#xff0c;准备在香港上市。思派健康早在2021年8月就已经递交招股书&#xff0c;这是时隔一年多后&#xff0c;这之前第三次递交招股书。这也意味着&#xff0c;时隔一年多后&#xff0c;思派健康终于要上市了。上半年亏损3.5亿…

SpringSecurity(八)【会话管理】

八、会话管理 简介 当浏览器调用登录接口登录成功之后&#xff0c;服务端会和浏览器之间创建一个会话&#xff08;Session&#xff09;&#xff0c;浏览器在每次发送请求时都会携带一个 SessionId&#xff0c;服务端则根据这个 SessionId 来判断用户身份。当浏览器关闭之后&…

从硬件角度看服务器性能调优

bios整体配置bios系统设置Hyper Thread开启超线程&#xff0c;设置后lscpu命令Thread(s) per core 值显示为 2。超线程可以理解为CPU的虚拟化&#xff0c;一颗物理CPU并行执行两条流水线指令。确认处理器基本频率及睿频频率&#xff0c;部分处理器基础频率低&#xff0c;但是睿…

看完了你还能不懂JAVA内存模型(JMM),我输了

前言 开篇一个例子&#xff0c;我看看都有谁会&#xff1f;如果不会的&#xff0c;或者不知道原理的&#xff0c;还是老老实实看完这篇文章吧。 Slf4j(topic "c.VolatileTest") public class VolatileTest { static boolean run true; public static void main(S…

基于Java+Swing实现《扫雷》游戏

基于JavaSwing实现《扫雷》游戏一、系统介绍二、功能展示三、其他系统一、系统介绍 windows自带的游戏《扫雷》是陪伴了无数人的经典游戏&#xff0c;本程序参考《扫雷》的规则进行了简化&#xff0c;用java语言实现&#xff0c;采用了swing技术进行了界面化处理&#xff0c;设…