58、多媒体之视频:VideoView播放、MediaController、ExoPlayer集成
视频播放,几乎是每个App都绕不开的功能。从简单的短视频到高清电影,从本地文件到网络流媒体,Android系统提供了多种方案。今天我们就来聊聊最常用的三种方式:VideoView、MediaController,以及目前业界主流的ExoPlayer。
我个人习惯把视频播放方案分成两类:轻量级和重量级。轻量级就是系统自带的VideoView,适合快速实现、功能简单的场景。重量级就是ExoPlayer,它灵活、可定制,适合复杂的播放需求。嗯,我们先从轻量级开始。
一、VideoView:最省事的播放器
VideoView是Android官方提供的一个封装好的View,它内部集成了MediaPlayer和SurfaceView。说白了,你只需要给它一个视频源,它就能播起来。
我在项目中遇到过一个小需求:只是播放一个开屏视频,不需要任何控制按钮。VideoView简直是绝配,几行代码搞定。
1. 基本使用
在布局文件中添加VideoView:
<VideoView
android:id="@+id/videoView"
android:layout_width="match_parent"
android:layout_height="300dp" />
在代码中设置视频源并开始播放:
VideoView videoView = findViewById(R.id.videoView);
// 支持网络视频和本地视频
videoView.setVideoPath("https://example.com/sample.mp4");
// 或者本地文件
// videoView.setVideoURI(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.sample));
videoView.start();
就这么简单。但注意,VideoView默认没有播放控制条,用户无法暂停、快进。这时候就需要MediaController登场了。
2. 配合MediaController
MediaController是一个系统提供的控制视图,包含播放/暂停、进度条、快进/快退等按钮。它和VideoView配合使用非常方便。
VideoView videoView = findViewById(R.id.videoView);
MediaController mediaController = new MediaController(this);
mediaController.setAnchorView(videoView);
videoView.setMediaController(mediaController);
videoView.setVideoPath("https://example.com/sample.mp4");
videoView.start();
你想想看,就这么几行代码,一个带控制条的视频播放器就完成了。但MediaController的UI是固定的,如果你想自定义样式,就得自己写控制布局了。
二、VideoView的局限性
虽然VideoView用起来很爽,但它有几个硬伤:
- 不支持自适应码率:无法根据网络状况切换清晰度
- 不支持DASH、HLS等流媒体协议:只能播放MP4、3GP等格式
- 扩展性差:无法自定义解码器、渲染器等
- 生命周期管理麻烦:需要手动处理暂停、恢复、释放
我记得有一次做直播回放功能,需要支持HLS流,VideoView直接罢工了。嗯,这时候就得请出ExoPlayer了。
三、ExoPlayer:专业级播放器
ExoPlayer是Google官方推荐的播放器库,它基于MediaCodec和AudioTrack实现,支持几乎所有主流格式和协议。说白了,它就是Android上的万能播放器。
1. 集成ExoPlayer
首先在build.gradle中添加依赖:
implementation 'com.google.android.exoplayer:exoplayer:2.19.1'
// 如果只需要核心功能,可以只引入:
// implementation 'com.google.android.exoplayer:exoplayer-core:2.19.1'
// implementation 'com.google.android.exoplayer:exoplayer-ui:2.19.1'
2. 基本使用
ExoPlayer的使用比VideoView稍微复杂一点,但灵活性高得多。
// 1. 创建Player
SimpleExoPlayer player = new SimpleExoPlayer.Builder(context).build();
// 2. 创建MediaItem
MediaItem mediaItem = MediaItem.fromUri("https://example.com/sample.mp4");
// 3. 设置播放源
player.setMediaItem(mediaItem);
// 4. 准备播放
player.prepare();
player.play();
你可能会问:PlayerView呢?别急,ExoPlayer提供了PlayerView来显示视频画面和控制条。
<com.google.android.exoplayer2.ui.PlayerView
android:id="@+id/playerView"
android:layout_width="match_parent"
android:layout_height="300dp"
app:use_controller="true" />
PlayerView playerView = findViewById(R.id.playerView);
playerView.setPlayer(player);
设置app:use_controller="true"后,PlayerView会自动显示播放控制条,包括播放/暂停、进度条、全屏等按钮。而且这个控制条是可以自定义的。
3. 高级功能
ExoPlayer的强大之处在于它的可扩展性。我简单列几个常用功能:
| 功能 | 说明 | 代码示例 |
|---|---|---|
| 自适应码率 | 根据网络自动切换清晰度 | new AdaptiveTrackSelection.Factory() |
| 缓存 | 边播边缓存,节省流量 | CacheDataSourceFactory |
| DRM | 支持Widevine等数字版权管理 | DrmSessionManager |
| 自定义渲染器 | 支持字幕、水印等 | Renderer.Factory |
我曾经做过一个在线教育App,需要支持视频缓存和倍速播放。ExoPlayer的PlaybackParameters直接搞定倍速,配合CacheDataSourceFactory实现边播边存,用户体验非常好。
四、核心知识体系
下面这张图展示了本章的核心知识结构,我建议你保存下来,以后做视频播放功能时对照着看:
五、避坑指南
做视频播放,坑还是挺多的。我分享几个亲身踩过的坑:
我曾经...在Activity的onCreate中直接调用player.play(),结果视频没声音。后来发现是AudioFocus没处理。解决方案:在播放前请求AudioFocus,并在失去焦点时暂停。
小技巧:ExoPlayer的setRepeatMode可以设置循环播放。单曲循环用REPEAT_MODE_ONE,列表循环用REPEAT_MODE_ALL。
注意:VideoView和ExoPlayer都需要在AndroidManifest中声明网络权限。另外,播放网络视频时,记得处理网络切换和断网重连的情况。
六、总结
视频播放这件事,说简单也简单,说复杂也复杂。我的建议是:
- 简单场景(如播放本地视频、开屏广告):用VideoView + MediaController,省时省力
- 复杂场景(如直播、在线教育、短视频App):用ExoPlayer,灵活可控
嗯,其实ExoPlayer还有一个兄弟叫Media3,是ExoPlayer的升级版,但核心思想是一样的。掌握了ExoPlayer,Media3上手就很快了。
最后提醒一句:记得在onStop中暂停播放,在onStart中恢复播放。这是最基本的生命周期管理,但很多人会忘。
公众号:蓝海资料掘金营,微信deep3321