Android视频播放与画中画模式全解析
1. Android视频播放基础
1.1 Android视频播放类介绍
在Android应用开发中, VideoView 和 MediaController 这两个类为实现视频播放提供了便捷的途径。
- VideoView类 :是在Android应用中显示视频的最简单方式。它作为一个可视化组件,添加到活动布局后,能提供播放视频的界面。目前,Android支持多种视频格式,如H.263、H.264 AVC、H.265 HEVC、MPEG - 4 SP、VP8和VP9。其常用方法如下:
| 方法 | 描述 |
| ---- | ---- |
| setVideoPath(String path) | 指定要播放的视频媒体路径(字符串形式),可以是远程视频文件URL或设备本地视频文件 |
| setVideoUri(Uri uri) | 与 setVideoPath() 方法功能相同,但接受 Uri 对象作为参数 |
| start() | 开始视频播放 |
| stopPlayback() | 停止视频播放 |
| pause() | 暂停视频播放 |
| isPlaying() | 返回布尔值,指示视频是否正在播放 |
| setOnPreparedListener(MediaPlayer.OnPreparedListener) | 当视频准备好播放时,调用回调方法 |
| setOnErrorListener(MediaPlayer.OnErrorListener) | 视频播放过程中出现错误时,调用回调方法 |
| setOnCompletionListener(MediaPlayer.OnCompletionListener) | 视频播放结束时,调用回调方法 |
| getDuration() | 返回视频的时长,通常在 OnPreparedListener() 回调方法中调用才会返回正确值,否则返回 -1 |
| getCurrentPosition() | 返回一个整数值,表示当前播放位置 |
| setMediaController(MediaController) | 指定一个 MediaController 实例,允许向用户显示播放控件 |
- MediaController类 :如果仅使用
VideoView类播放视频,用户将无法控制播放,视频会一直播放到结束。而将MediaController类的实例附加到VideoView实例上,就能解决这个问题。它提供了一组控件,让用户可以管理播放(如暂停、在视频时间轴上前后快进)。该类的关键方法如下:
| 方法 | 描述 |
| ---- | ---- |
|setAnchorView(View view)| 指定控制器要锚定的视图,从而确定控件在屏幕上的位置 |
|show()| 显示控件 |
|show(int timeout)| 控件显示指定的持续时间(以毫秒为单位) |
|hide()| 对用户隐藏控制器 |
|isShowing()| 返回布尔值,指示控件当前是否对用户可见 |
1.2 创建视频播放示例
下面我们将创建一个使用 VideoView 和 MediaController 类播放MPEG - 4视频文件的示例应用。
1.2.1 创建项目
- 从欢迎屏幕中选择“New Project”选项。
- 在新的项目对话框中,选择“Empty Views Activity”模板,然后点击“Next”按钮。
- 在“Name”字段中输入“VideoPlayer”,并指定“com.ebookfrenzy.videoplayer”作为包名。
- 在点击“Finish”按钮之前,将“Minimum API level”设置为“API 33: Android 13 (Tiramisu)”,并将“Language”菜单设置为“Java”。
- 按照相关步骤启用项目的视图绑定。
1.2.2 设计布局
- 使用项目工具窗口定位到
app -> res -> layout -> activity_main.xml文件,双击打开。 - 将布局编辑器工具切换到“Design”模式,删除默认的
TextView小部件。 - 从“Palette”面板的“Widgets”类别中,拖放一个
VideoView实例到布局中,填充可用的画布区域。 - 使用“Attributes”面板,将
layout_width和layout_height属性分别更改为match_constraint和wrap_content。 - 移除
VideoView底部与父ConstraintLayout底部的约束。 - 将组件的ID更改为
videoView1。
1.2.3 下载视频文件
- 使用网络浏览器,导航到
https://www.ebookfrenzy.com/android_book/demo.mp4播放视频。 - 在浏览器窗口中,右键单击视频播放区域,选择保存或下载视频到本地文件,并选择合适的临时文件系统位置,将文件命名为
demo.mp4。 - 在Android Studio中,使用项目工具窗口定位到
res文件夹,右键单击它,选择“New -> Directory”菜单选项,输入raw作为目录名,然后按回车键。 - 使用操作系统的文件系统导航器,找到上面下载的
demo.mp4文件并复制。 - 返回Android Studio,右键单击新创建的
raw目录,选择“Paste”选项,将视频文件复制到项目中。
1.2.4 配置VideoView
以下是配置 VideoView 并开始播放视频的代码:
package com.ebookfrenzy.videoplayer;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.net.Uri;
import android.view.View;
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
configureVideoView();
}
private void configureVideoView() {
binding.videoView1.setVideoURI(Uri.parse("android.resource://"
+ getPackageName() + "/" + R.raw.demo));
binding.videoView1.start();
}
}
1.3 添加MediaController
当前的“VideoPlayer”应用中,用户无法控制视频播放。我们可以通过修改 configureVideoView() 方法来添加 MediaController :
package com.ebookfrenzy.videoplayer;
import android.widget.MediaController;
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding binding;
private MediaController mediaController;
private void configureVideoView() {
binding.videoView1.setVideoURI(Uri.parse("android.resource://"
+ getPackageName() + "/" + R.raw.demo));
mediaController = new MediaController(this);
mediaController.setAnchorView(binding.videoView1);
binding.videoView1.setMediaController(mediaController);
binding.videoView1.start();
}
}
1.4 设置onPreparedListener
为了展示视频媒体的更多功能,我们实现一个监听器,用于在Android Studio的Logcat面板中输出视频时长,并配置视频循环播放:
package com.ebookfrenzy.videoplayer;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding binding;
private MediaController mediaController;
String TAG = "VideoPlayer";
private void configureVideoView() {
binding.videoView1.setVideoURI(Uri.parse("android.resource://"
+ getPackageName() + "/" + R.raw.demo));
MediaController mediaController = new MediaController(this);
mediaController.setAnchorView(binding.videoView1);
binding.videoView1.setMediaController(mediaController);
binding.videoView1.setOnPreparedListener(mp -> {
mp.setLooping(true);
Log.i(TAG, "Duration = " + binding.videoView1.getDuration());
});
binding.videoView1.start();
}
}
2. Android画中画模式
2.1 画中画模式概述
画中画(PiP)模式主要用于视频播放,允许将活动屏幕缩小并定位在屏幕的任何位置。在这种状态下,活动继续运行,窗口保持可见,使用户可以在执行其他任务(如查看电子邮件或处理电子表格)的同时继续观看视频播放。
2.2 画中画模式功能
- 模式切换 :通过运行应用内的API调用将活动置于PiP模式。
- 配置选项 :可以指定配置选项,控制PiP窗口的宽高比,并定义要包含的活动屏幕区域。
- 窗口交互 :用户点击PiP窗口时,窗口会变大,中心有全屏操作按钮,点击可将窗口恢复到全屏模式;右上角有退出按钮,点击可关闭窗口并将应用置于后台。自定义操作按钮也会显示在屏幕上。
2.3 启用画中画模式
PiP模式目前仅在运行API 26(Android 8.0 Oreo)或更高版本的设备上受支持。要在项目的清单文件中启用PiP模式,需要为每个需要PiP支持的活动元素添加以下代码:
<activity
android:name=".MainActivity"
android:supportsPictureInPicture="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
其中, android:supportsPictureInPicture 条目为活动启用PiP模式, android:configChanges 属性通知Android活动可以处理布局配置更改。
2.4 配置画中画参数
PiP行为通过 PictureInPictureParams 类定义,可以使用 Builder 类创建其实例:
PictureInPictureParams params = new PictureInPictureParams.Builder().build();
可以使用以下可选方法调用自定义参数:
- setActions() :定义在活动处于PiP模式时,PiP窗口内可以执行的操作。
- setAspectRatio() :声明PiP窗口外观的首选宽高比,接受一个包含宽高比的 Rational 对象作为参数。
- setSourceRectHint() :接受一个 Rect 对象,定义要在PiP窗口中显示的活动屏幕区域。
以下代码示例展示了如何配置宽高比和操作参数:
Rational rational = new Rational(videoView.getWidth(), videoView.getHeight());
PictureInPictureParams params = new PictureInPictureParams.Builder()
.setAspectRatio(rational)
.setActions(actions)
.build();
setPictureInPictureParams(params);
2.5 进入画中画模式
通过调用 enterPictureInPictureMode() 方法并传递 PictureInPictureParams 对象,将活动置于PiP模式:
enterPictureInPictureMode(params);
如果不需要参数,可以创建一个默认的 PictureInPictureParams 对象。如果之前使用 setPictureInPictureParams() 方法设置了参数,这些参数将与 enterPictureInPictureMode() 方法调用时指定的参数合并。
2.6 检测画中画模式变化
通过重写 onPictureInPictureModeChanged() 方法,可以处理活动在PiP模式和全屏模式之间转换时的任务:
@Override
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
super.onPictureInPictureModeChanged(isInPictureInPictureMode);
if (isInPictureInPictureMode) {
// 活动进入画中画模式
} else {
// 活动进入全屏模式
}
}
2.7 添加画中画操作
PiP操作以图标形式出现在用户点击PiP窗口时。实现PiP操作是一个多步骤过程:
- 设置广播接收器,用于接收PiP窗口通知活动某个操作已被选择的信息。
- 在PiP操作中创建待定意图,配置为广播广播接收器正在监听的意图。
- 当意图触发广播接收器时,使用意图中存储的数据识别执行的操作,并在活动中采取必要的操作。
以下代码片段展示了如何创建 Intent 、 PendingIntent 和 RemoteAction 对象,以及如何应用PiP设置:
final ArrayList<RemoteAction> actions = new ArrayList<>();
Intent actionIntent = new Intent("MY_PIP_ACTION");
final PendingIntent pendingIntent = PendingIntent.getBroadcast(MyActivity.this,
REQUEST_CODE, actionIntent, FLAG_IMMUTABLE);
final Icon icon = Icon.createWithResource(MyActivity.this, R.drawable.action_icon);
RemoteAction remoteAction = new RemoteAction(icon, "My Action Title",
"My Action Description", pendingIntent);
actions.add(remoteAction);
PictureInPictureParams params = new PictureInPictureParams.Builder()
.setActions(actions)
.build();
setPictureInPictureParams(params);
2.8 画中画模式在项目中的应用示例
2.8.1 添加画中画支持到清单文件
在 AndroidManifest.xml 文件中,为 MainActivity 启用PiP支持:
<activity
android:name=".MainActivity"
android:supportsPictureInPicture="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
2.8.2 添加画中画按钮
- 加载
activity_main.xml文件到布局编辑器。 - 从调色板中拖放一个
Button对象到布局中,使其位置符合要求。 - 将按钮上的文本更改为“Enter PiP Mode”,并将字符串提取到名为
enter_pip_mode的资源中。 - 将按钮的ID更改为
pipButton,并配置onClick属性以调用名为enterPipMode的方法。
通过以上步骤,我们可以在Android应用中实现视频播放和画中画模式的功能。这种方式使得用户在使用应用时能够更加灵活地观看视频,提高了用户体验。
3. 总结与展望
3.1 技术总结
在本次的技术探索中,我们深入研究了 Android 平台上的视频播放与画中画模式的实现。以下是对关键技术点的总结:
| 技术点 | 描述 |
|---|---|
| VideoView 类 | 用于在 Android 应用中显示视频,支持多种视频格式,提供了丰富的方法来控制视频播放,如开始、暂停、停止等。 |
| MediaController 类 | 为 VideoView 提供播放控制功能,用户可以通过它来管理视频的播放进度、暂停和继续等操作。 |
| 画中画模式 | 允许用户在执行其他任务的同时继续观看视频,通过配置清单文件、设置参数和处理模式变化等步骤实现。 |
3.2 代码回顾
我们通过一系列代码示例展示了如何实现视频播放和画中画模式:
- 视频播放示例 :
package com.ebookfrenzy.videoplayer;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.net.Uri;
import android.view.View;
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
configureVideoView();
}
private void configureVideoView() {
binding.videoView1.setVideoURI(Uri.parse("android.resource://"
+ getPackageName() + "/" + R.raw.demo));
binding.videoView1.start();
}
}
- 添加 MediaController :
package com.ebookfrenzy.videoplayer;
import android.widget.MediaController;
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding binding;
private MediaController mediaController;
private void configureVideoView() {
binding.videoView1.setVideoURI(Uri.parse("android.resource://"
+ getPackageName() + "/" + R.raw.demo));
mediaController = new MediaController(this);
mediaController.setAnchorView(binding.videoView1);
binding.videoView1.setMediaController(mediaController);
binding.videoView1.start();
}
}
- 设置 onPreparedListener :
package com.ebookfrenzy.videoplayer;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding binding;
private MediaController mediaController;
String TAG = "VideoPlayer";
private void configureVideoView() {
binding.videoView1.setVideoURI(Uri.parse("android.resource://"
+ getPackageName() + "/" + R.raw.demo));
MediaController mediaController = new MediaController(this);
mediaController.setAnchorView(binding.videoView1);
binding.videoView1.setMediaController(mediaController);
binding.videoView1.setOnPreparedListener(mp -> {
mp.setLooping(true);
Log.i(TAG, "Duration = " + binding.videoView1.getDuration());
});
binding.videoView1.start();
}
}
- 画中画模式相关代码 :
- 启用画中画模式的清单文件配置:
<activity
android:name=".MainActivity"
android:supportsPictureInPicture="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- 配置画中画参数:
Rational rational = new Rational(videoView.getWidth(), videoView.getHeight());
PictureInPictureParams params = new PictureInPictureParams.Builder()
.setAspectRatio(rational)
.setActions(actions)
.build();
setPictureInPictureParams(params);
- 进入画中画模式:
enterPictureInPictureMode(params);
- 检测画中画模式变化:
@Override
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
super.onPictureInPictureModeChanged(isInPictureInPictureMode);
if (isInPictureInPictureMode) {
// 活动进入画中画模式
} else {
// 活动进入全屏模式
}
}
- 添加画中画操作:
final ArrayList<RemoteAction> actions = new ArrayList<>();
Intent actionIntent = new Intent("MY_PIP_ACTION");
final PendingIntent pendingIntent = PendingIntent.getBroadcast(MyActivity.this,
REQUEST_CODE, actionIntent, FLAG_IMMUTABLE);
final Icon icon = Icon.createWithResource(MyActivity.this, R.drawable.action_icon);
RemoteAction remoteAction = new RemoteAction(icon, "My Action Title",
"My Action Description", pendingIntent);
actions.add(remoteAction);
PictureInPictureParams params = new PictureInPictureParams.Builder()
.setActions(actions)
.build();
setPictureInPictureParams(params);
3.3 未来展望
随着 Android 系统的不断发展,视频播放和画中画模式可能会迎来更多的优化和新功能。例如:
- 更高的视频质量支持 :随着网络和硬件的不断提升,未来可能会支持更高分辨率、更高帧率的视频播放。
- 更智能的画中画模式 :画中画模式可能会更加智能,例如根据用户的使用习惯自动调整窗口大小和位置,或者与其他应用进行更深度的交互。
- 增强的用户交互体验 :可能会引入更多的交互方式,如手势控制、语音控制等,让用户更加便捷地操作视频播放和画中画模式。
3.4 流程图总结
下面是一个 mermaid 格式的流程图,展示了实现视频播放和画中画模式的主要步骤:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
A([开始]):::startend --> B(创建项目):::process
B --> C(设计布局):::process
C --> D(下载视频文件):::process
D --> E(配置 VideoView):::process
E --> F(添加 MediaController):::process
F --> G(设置 onPreparedListener):::process
G --> H(启用画中画模式):::process
H --> I(配置画中画参数):::process
I --> J(进入画中画模式):::process
J --> K(检测画中画模式变化):::process
K --> L(添加画中画操作):::process
L --> M([结束]):::startend
通过这个流程图,我们可以清晰地看到实现视频播放和画中画模式的整个流程,从项目创建到最终功能的实现,每个步骤都紧密相连。
3.5 实际应用建议
在实际开发中,我们可以根据具体的需求对这些技术进行灵活运用。例如:
- 视频类应用 :对于专门的视频播放应用,可以充分利用 VideoView 和 MediaController 提供的功能,为用户提供流畅的视频播放体验。同时,画中画模式可以让用户在切换到其他应用时继续观看视频,提高用户的使用效率。
- 多媒体应用 :在多媒体应用中,视频播放可能只是其中的一部分功能。可以将视频播放与其他功能(如音频播放、图片展示等)结合起来,为用户提供更加丰富的多媒体体验。
- 教育类应用 :在教育类应用中,视频教学是一种常见的方式。通过实现画中画模式,学生可以在学习视频的同时查看相关的资料或进行笔记记录,提高学习效果。
总之,Android 平台上的视频播放和画中画模式为开发者提供了强大的工具,能够帮助我们开发出更加优秀的应用,满足用户多样化的需求。通过不断地学习和实践,我们可以更好地掌握这些技术,为用户带来更好的体验。

6000

被折叠的 条评论
为什么被折叠?



