添加直播按钮

This commit is contained in:
xiao12feng@outlook.com 2025-12-17 17:23:54 +08:00
parent ed9d9ceb9c
commit 0289dafd1c
19 changed files with 165 additions and 41 deletions

View File

@ -17,8 +17,15 @@ android {
}
buildTypes {
release {
debug {
// 调试版本优化
isMinifyEnabled = false
isDebuggable = true
}
release {
// 发布版本优化
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
@ -26,6 +33,12 @@ android {
}
}
// 编译优化
dexOptions {
javaMaxHeapSize = "2g"
preDexLibraries = true
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17

View File

@ -9,7 +9,9 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.LiveStreaming"
android:usesCleartextTraffic="true">
android:usesCleartextTraffic="true"
android:hardwareAccelerated="true"
android:largeHeap="true">
<activity
android:name="com.example.livestreaming.FishPondActivity"
@ -37,7 +39,9 @@
<activity
android:name="com.example.livestreaming.MainActivity"
android:exported="true">
android:exported="true"
android:launchMode="singleTop"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />

View File

@ -53,6 +53,15 @@ public class MainActivity extends AppCompatActivity {
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
// 立即显示缓存数据提升启动速度
setupRecyclerView();
setupUI();
// 异步加载资源文件避免阻塞主线程
loadCoverAssetsAsync();
}
private void setupRecyclerView() {
adapter = new RoomsAdapter(room -> {
if (room == null) return;
Intent intent = new Intent(MainActivity.this, RoomDetailActivity.class);
@ -65,8 +74,11 @@ public class MainActivity extends AppCompatActivity {
binding.roomsRecyclerView.setLayoutManager(glm);
binding.roomsRecyclerView.setAdapter(adapter);
loadCoverAssets();
// 立即显示演示数据提升用户体验
adapter.submitList(buildDemoRooms(6));
}
private void setupUI() {
binding.swipeRefresh.setOnRefreshListener(this::fetchRooms);
binding.roomsRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@ -95,6 +107,9 @@ public class MainActivity extends AppCompatActivity {
}
});
// 设置添加直播按钮点击事件
binding.fabAddLive.setOnClickListener(v -> showCreateRoomDialog());
BottomNavigationView bottomNavigation = binding.bottomNavInclude.bottomNavigation;
bottomNavigation.setSelectedItemId(R.id.nav_home);
bottomNavigation.setOnItemSelectedListener(item -> {
@ -151,9 +166,11 @@ public class MainActivity extends AppCompatActivity {
stopPolling();
pollRunnable = () -> {
fetchRooms();
handler.postDelayed(pollRunnable, 5000);
// 增加轮询间隔减少网络请求频率
handler.postDelayed(pollRunnable, 10000);
};
handler.post(pollRunnable);
// 延迟首次请求让界面先显示
handler.postDelayed(pollRunnable, 1000);
}
private void stopPolling() {
@ -210,9 +227,13 @@ public class MainActivity extends AppCompatActivity {
dialog.dismiss();
fetchRooms();
Intent intent = new Intent(MainActivity.this, RoomDetailActivity.class);
intent.putExtra(RoomDetailActivity.EXTRA_ROOM_ID, room.getId());
startActivity(intent);
// 显示推流信息
showStreamInfo(room);
// 可选跳转到房间详情
// Intent intent = new Intent(MainActivity.this, RoomDetailActivity.class);
// intent.putExtra(RoomDetailActivity.EXTRA_ROOM_ID, room.getId());
// startActivity(intent);
}
@Override
@ -321,7 +342,9 @@ public class MainActivity extends AppCompatActivity {
return list;
}
private void loadCoverAssets() {
private void loadCoverAssetsAsync() {
// 在后台线程加载资源文件避免阻塞UI
new Thread(() -> {
AssetManager am = getAssets();
List<String> files = new ArrayList<>();
try {
@ -337,6 +360,13 @@ public class MainActivity extends AppCompatActivity {
}
} catch (IOException ignored) {
}
// 回到主线程更新UI
runOnUiThread(() -> {
if (adapter != null) {
adapter.setCoverAssetFiles(files);
}
});
}).start();
}
}

View File

@ -38,9 +38,26 @@ public class PlayerActivity extends AppCompatActivity {
triedAltUrl = false;
ExoPlayer exo = new ExoPlayer.Builder(this).build();
// 创建低延迟播放器配置
ExoPlayer exo = new ExoPlayer.Builder(this)
.setLoadControl(new androidx.media3.exoplayer.DefaultLoadControl.Builder()
// 减少缓冲区大小降低延迟
.setBufferDurationsMs(
1000, // 最小缓冲时长 1秒
3000, // 最大缓冲时长 3秒
500, // 播放缓冲时长 0.5秒
1000 // 播放后缓冲时长 1秒
)
.build())
.build();
// 设置播放器视图
binding.playerView.setPlayer(exo);
// 启用低延迟模式
binding.playerView.setUseController(true);
binding.playerView.setControllerAutoShow(false);
String altUrl = getAltHlsUrl(url);
exo.addListener(new Player.Listener() {
@Override

View File

@ -25,6 +25,9 @@ public final class ApiClient {
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(logging)
.connectTimeout(5, java.util.concurrent.TimeUnit.SECONDS)
.readTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
.writeTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
.build();
retrofit = new Retrofit.Builder()

View File

@ -21,6 +21,9 @@ public class Room {
@SerializedName("isLive")
private boolean isLive;
@SerializedName("viewerCount")
private int viewerCount;
@SerializedName("streamUrls")
private StreamUrls streamUrls;
@ -58,6 +61,10 @@ public class Room {
this.streamUrls = streamUrls;
}
public void setViewerCount(int viewerCount) {
this.viewerCount = viewerCount;
}
public String getId() {
return id;
}
@ -82,12 +89,17 @@ public class Room {
return streamUrls;
}
public int getViewerCount() {
return viewerCount;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Room)) return false;
Room room = (Room) o;
return isLive == room.isLive
&& viewerCount == room.viewerCount
&& Objects.equals(id, room.id)
&& Objects.equals(title, room.title)
&& Objects.equals(streamerName, room.streamerName)
@ -97,6 +109,6 @@ public class Room {
@Override
public int hashCode() {
return Objects.hash(id, title, streamerName, streamKey, isLive, streamUrls);
return Objects.hash(id, title, streamerName, streamKey, isLive, viewerCount, streamUrls);
}
}

View File

@ -212,6 +212,17 @@
android:visibility="gone"
/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fabAddLive"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginBottom="88dp"
android:contentDescription="添加直播"
android:src="@drawable/ic_add_24"
app:backgroundTint="@color/purple_500"
app:tint="@android:color/white" />
<include
android:id="@+id/bottomNavInclude"
layout="@layout/include_bottom_nav"

View File

@ -1,48 +1,82 @@
# SRS 配置文件 - 直播系统
listen 1935;
max_connections 1000;
daemon off;
srs_log_tank console;
# 全局优化配置
# 减少缓冲区大小,降低延迟
mr_enabled off;
# 启用快速启动
fast_cache 10;
# 优化TCP配置
tcp_nodelay on;
http_server {
enabled on;
listen 8080;
dir ./objs/nginx/html;
# 启用跨域支持
crossdomain on;
}
http_api {
enabled on;
listen 1985;
# 启用跨域支持
crossdomain on;
}
stats {
network 0;
}
vhost __defaultVhost__ {
# HLS 配置
# RTMP 配置 - 优化延迟
rtmp {
enabled on;
# 减少缓冲区大小,降低延迟
chunk_size 4096;
}
# HLS 配置 - 优化延迟
hls {
enabled on;
hls_fragment 2;
hls_window 10;
hls_path ./objs/nginx/html;
hls_m3u8_file [app]/[stream].m3u8;
hls_ts_file [app]/[stream]-[seq].ts;
# 减少分片时长,降低延迟
hls_fragment 2;
hls_window 6;
# 启用低延迟模式
hls_dispose 30;
}
# HTTP-FLV 配置 (低延迟)
# HTTP-FLV 配置 - 低延迟播放
http_remux {
enabled on;
mount [app]/[stream].flv;
mount [vhost]/[app]/[stream].flv;
# 启用快速启动
fast_cache 10;
}
# HTTP 回调配置
http_hooks {
enabled on;
on_publish http://host.docker.internal:3001/api/srs/on_publish;
on_unpublish http://host.docker.internal:3001/api/srs/on_unpublish;
# 转码配置(可选)
transcode {
enabled off;
}
# GOP 缓存,提高首屏速度
# 播放配置 - 优化延迟
play {
gop_cache on;
# 减少GOP缓存
gop_cache off;
# 启用时间校正
time_jitter full;
# 减少队列长度
queue_length 10;
}
# 发布配置 - 优化延迟
publish {
# 减少首帧等待时间
firstpkt_timeout 20000;
# 减少正常包超时
normal_timeout 5000;
}
}