【Win 10 应用开发】在后台播放视频
从 1607 (14393)版本开始,MediaPlayer 类就可以在前台与后台之间无缝播放,你不必再考虑前台与后之间的通信,所以从 14393 开始,你就不需要再用 BackgroundMediaPlayer 类了。无论多媒体资源是前台还是后台播放,都由 MediaPlayer 类负责。与此同时,在 XAML 控件体系中,MediaElement 类也由 MediaPlayerElement 类替代。
这些内容老周就不多说了,因为 SDK 文档的更新日志上都有说明。不管是音频或是视频都统一到 MediaPlayer 类中,正因为如此,实现后台播放视频就显得很是 Easy 了。
不废话,下面咱们来个示例来说明说明。
这个示例简单,老周就不用 Page 了,UI 的根直接来个 Grid 吧。
<Grid
x:Class="App32.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App32"> <Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition />
</Grid.RowDefinitions> <Button Content="打开视频文件" Margin="10,15" Click="OnOpen"/>
<MediaPlayerElement Name="me" Grid.Row="1" Margin="8"/> </Grid>
由于这不是项目默认生成的 Page ,所以注意(看好上面的 x:Class ,它指向对应的类),与它对应的代码文件中的类必须继承 Grid 类,不是 Page 类,代码类的基类就得与 XAML 文档的根元素匹配。
partial class MainView : Grid
{
public MainView()
{
InitializeComponent();
}
}
如果,你觉得有必要密封这个类(不让别人继承财产),就这样修饰。
sealed partial class MainView : Grid
{
public MainView()
{
InitializeComponent();
}
}
按钮是干啥用的呢,这样,咱们待会儿运行后,点击按钮来打开一个视频文件,然后在 MediaPlayerElement 控件中播放(显示)。
private async void OnOpen(object sender, RoutedEventArgs e)
{
FileOpenPicker picker = new FileOpenPicker();
picker.FileTypeFilter.Add(".mp4");
picker.FileTypeFilter.Add(".mkv");
picker.FileTypeFilter.Add(".wmv"); StorageFile file = await picker.PickSingleFileAsync();
if (file == null) return; MediaSource source = MediaSource.CreateFromStorageFile(file);
me.Source = source; // 开始播放
me.MediaPlayer.Play();
}
在文首老周说过,现在 UWP 应用的多媒体播放都统一由 MediaPlayer 大哥负责,因此,MediaPlayerElement 类会公开一个 MediaPlayer 属性,你可以从这个属性获取到关联的 MediaPlayer 类实例(这个类位于 Windows.Media.Playback 命名空间)。
因此你看到了,在上面最后的代码上,老周调用的 Play 方法是 MediaPlayer 类的,实际上视频是在 MediaPlayer 上管理的。MediaPlayerElement 只负责显示(或者 UI 操作,如暂停等)。
行了,代码这么搞就OK了,不过要想让应用能在后台继续播放,清单文件上的配置是少不了的。打开清单文件(默认是以清单设计器打开),切换到“功能”选项卡,勾选“背景媒体播放”。这是翻译问题,其实应该叫“后台媒体播放”才对,不管它,知道是啥意思就行了,别纠结这些无关紧要的事情。

清单文件其实是 XML 文档,所以,如果你觉得直接点两下鼠标没法装逼的话,可以手动写的。
首先,你要引入一个 v3 版本的 UWP 专用命名空间。
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
然后,你才能进行声明,写到 Package / Capabilities 节点下面。
<Capabilities>
<Capability Name="internetClient" />
<uap3:Capability Name="backgroundMediaPlayback" />
</Capabilities>
最后,保存一下文件就完事了。
现在运行,随便找个视频播放,然后把程序最小化,或切换到其他应用,然后再切换回去,你会发现,当程序进入后台后,视频仍然在播放。

其实,上面的实现还不够完善。你想啊,应用移到后台,UI 是看不见的,成了多余的货了,所以,我们妨考虑,在应用扔到后台时销毁 UI,等应用回到前台时再创建 UI。当然了,我们这个例子,界面比较简单,内存占用基本看不出来区别,大约也就是 0.1 MB 的差异。不过为了演示,我们还是处理一下应用程序的这两个事件:
public App()
{
this.InitializeComponent();
EnteredBackground += App_EnteredBackground;
LeavingBackground += App_LeavingBackground;
}
当应用发送到后台,会引发 EnteredBackground 事件,当应用回到前台,则发生 LeavingBackground 事件。
下面我们处理一下。
private void App_LeavingBackground(object sender, LeavingBackgroundEventArgs e)
{
if(Window.Current.Content == null) //这里为什么要判断 null 不 null 呢?
{
CreateUI(); //重建界面
}
} private void App_EnteredBackground(object sender, EnteredBackgroundEventArgs e)
{
Window.Current.Content = null;//取消对 UI 实例的引用
GC.Collect(); //打扫卫生
}
进入后台后,把当前窗口的内容设为 null,可以解除对 XAML 对象的引用,然后扛一根大扫把来,调用GC成员打扫一下,清理内存。
当重新回到前台时,重建界面,这里为啥我要先看看窗口的内容是否为 null 呢?很简单啊,如果不为 null 说明界面创建好了,那就不必要重复创建了,没意义了。为啥会这样,因为有件事你得知道,当启动应用时,会执行 OnLaunched 方法,这个没疑问吧。然后呢,LeavingBackground 事件会发生一次。而我们在很多时候,OnLaunched 方法中已经建好界面了,正因为如此,在处理 LeavingBackground 事件时,一定要判断一下界面是否创建过了,如果已有界面实例,就不必再创建了。
顺便补一下,CreateUI 方法代码如下。
void CreateUI()
{
MainView mv = Window.Current.Content as MainView;
if (mv == null)
mv = new MainView();
Window.Current.Content = mv;
}
然后在你运行实例后,又出现新问题了。还记得吧?我们在 XAML 中放了一个 MediaPlayerElement 控件,现在应用进入后台后界面会释放,所以 MediaPlayerElement 控件的实例也会被干掉,等到应用再回到前台,MediaPlayerElement 控件已经是新创建的实例了,不是刚才的那个实例了,这就造成:回到应用后,视频不再播放了。
要解决这问题,我们只要想办法让 MediaPlayer 实例的生命周期与应用同步就好了,对,把它变成静态变量(static)。所以,我写了这么个类。
class MediaPlayerHelper
{
static MediaPlayer _player; public static MediaPlayer CurrentPlayer
{
get
{
if (_player == null)
_player = new MediaPlayer();
return _player;
}
}
}
这样就可以让它静态了,别忘了,如果 MediaPlayerElement 控件实例是新创建的,会关联地创建一个 MediaPlayer 实例。为了让每个新创建的 MediaPlayerElement 控件实例所关联的 MediaPlayer 实例相同,我们可以调用控件的 SetMediaPlayer 方法。
回到咱们前面那个 Grid 的子类代码中,在构造函数中加上这么一句:
public MainView()
{
InitializeComponent();
me.SetMediaPlayer(MediaPlayerHelper.CurrentPlayer);
}
这样一来,不管咱们在应用生命周期内创建了多少个 MediaPlayerElement 控件实例,其关联的 MediaPlayer 对象都是我们上面公开的那个 CurrentPlayer 了,这确保了 MediaPlayer 实例的全局唯一性。
现在再次运行示例,在界面元素销毁后再次回到应用程序,视频仍能继续播放。
好了,今天的话题聊完了,该用饭了。
【Win 10 应用开发】在后台播放视频的更多相关文章
- 【Win 10 应用开发】Toast通知激活应用——前台&后台
老周最近热衷于讲故事,接下来还是讲故事时间. 有人问我:你上大学的时候,有加入过学生会吗?读大学有没有必要加入学生会? 哎哟,这怎么回答呢,从短期来说,加入学生会有点用,至少可以娱乐一下,运气好的话, ...
- 【Win 10应用开发】延迟共享
延迟共享是啥呢,这么说吧,就是在应用程序打开共享面板选择共享目标时,不会设置要共享的数据,而是等到共享目标请求数据时,才会发送数据,而且,延迟操作可以在后台进行. 这样说似乎过于抽象,最好的诠释方法, ...
- 【Win 10 应用开发】启动远程设备上的应用
这个功能必须在“红石-1”(build 14393)以上的系统版中才能使用,运行在一台设备上的应用,可以通过URI来启动另一台设备上的应用.激活远程应用需要以下前提: 系统必须是build 14393 ...
- 【Win 10 应用开发】导入.pfx证书
这个功能其实并不常用,一般开发较少涉及到证书,不过,简单了解一下还是有必要的. 先来说说制作测试证书的方法,这里老周讲两种方法,可以生成用于测试的.pfx文件. 产生证书,大家都知道有个makecer ...
- 【Win 10应用开发】Adaptive磁贴模板的XML文档结构
在若干天之前,老周给大家讲了Adaptive Toast通知的XML模板,所以相应地,今天老周给大家介绍一下Adaptive磁贴的新XML模板. 同样道理,你依旧可以使用8.1时候的磁贴模板,在win ...
- 【Win 10 应用开发】RTM版的UAP项目解剖
Windows 10 发布后,其实SDK也偷偷地在VS的自定义安装列表中出现了,今天开发人员中心也更新了下载.正式版的SDK在API结构上和以前预览的时候是一样的,只是版本变成10240罢了,所以大家 ...
- 【Win 10应用开发】认识一下UAP项目
Windows 10 SDK预览版需要10030以上版本号的Win 10预览版系统才能使用.之前我安装的9926的系统,然后安装VS 2015 CTP 6,再装Win 10 SDK,但是在新建项目后, ...
- 【Win 10 应用开发】在代码中加载文本资源
记得前一次,老周给大伙,不,小伙伴们介绍了如何填写 .resw 文件,并且在 XAML 中使用 x:Uid 标记来加载.也顺便给大伙儿分析了运行时是如何解析 .resw 文件的. 本来说好了,后续老周 ...
- 在iOS开发中如何播放视频
技术博客http://www.cnblogs.com/ChenYilong/ 新浪微博http://weibo.com/luohanchenyilong 如何播放视频 •iOS提供了叫做MPMo ...
随机推荐
- Servlet 笔记-生命周期
Servlet 生命周期可被定义为从创建直到毁灭的整个过程.以下是 Servlet 遵循的过程: Servlet 通过调用 init () 方法进行初始化. Servlet 调用 service() ...
- WPF ListBox 一些小知识点
页面代码: <Grid Grid.Row="0" Grid.Column="2"> <ListBox x:Name="lvStep& ...
- C#匹配标签正则,获取标签的值
比如要获取: <color=#50cccc>头盔坐标:(-0.6, 1.0, 1.2)</color><color=#3d85c6>头盔方向(-0.2, 0.1, ...
- R学习笔记 第三篇:数据框
数据框(data.frame)用于存储二维表(即关系表)的数据,每一列存储的数据类型必须相同,不同的数据列的数据类型可以相同,也可以不同,但是,每列的长度必须相同.数据框的每列可以有唯一的命名,在已创 ...
- scp命令,用来在本地和远程相互传递文件,非常方便
scp是secure copy的简写,用于在Linux下进行远程拷贝文件的命令,和它类似的命令有cp,不过cp只是在本机进行拷贝不能跨服务器,而且scp传输是加密的.可能会稍微影响一下速度.当你服务器 ...
- Ubuntu配置OpenStack 二:配置时间同步NTP和安装数据库Maridb以及问题总结
继上一节Ubuntu配置OpenStack 一:配置主机环境,下面继续为安装时间同步,以及配置openstack的安装包源和安装数据库Maridb.(全文截图都是由自己徒手搭建完成并且截图) 一.安装 ...
- VS2008 C++ 利用WinHttp API获取任意Http网址的源码
最近一直在看有关Http的知识,对其基本的理论知识已经有所掌握,想通过一个C++具体的例子进行实际操作..于是上网查找了很多资料,发现在Windows系统上,可以通过WinHttp API接口开啊Ht ...
- SSH服务详解
第1章 SSH服务 1.1 SSH服务协议说明 SSH 是 Secure Shell Protocol 的简写,由 IETF 网络工作小组(Network Working Group )制定:在进行数 ...
- 交换知识 VLAN VTP STP 单臂路由
第1章 交换基础 1.1 园区网分层结构 层次 作用 出口层 广域网接入 出口策略 带宽控制 核心层 高速转发 服务器接入 路由选择 汇聚层 流量汇聚 链路冗余 设备冗余 路由选择 接入层 用户接入 ...
- eclipse中删除多余的tomcat server
在eclipse菜单中选择Window--Show View--Server--Servers,打开这个服务窗口,将多余的服务删除即可. 如果每次启动中太卡没反应,那就是服务没选择好,或是端口冲突的原 ...