从 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 应用开发】在后台播放视频的更多相关文章

  1. 【Win 10 应用开发】Toast通知激活应用——前台&后台

    老周最近热衷于讲故事,接下来还是讲故事时间. 有人问我:你上大学的时候,有加入过学生会吗?读大学有没有必要加入学生会? 哎哟,这怎么回答呢,从短期来说,加入学生会有点用,至少可以娱乐一下,运气好的话, ...

  2. 【Win 10应用开发】延迟共享

    延迟共享是啥呢,这么说吧,就是在应用程序打开共享面板选择共享目标时,不会设置要共享的数据,而是等到共享目标请求数据时,才会发送数据,而且,延迟操作可以在后台进行. 这样说似乎过于抽象,最好的诠释方法, ...

  3. 【Win 10 应用开发】启动远程设备上的应用

    这个功能必须在“红石-1”(build 14393)以上的系统版中才能使用,运行在一台设备上的应用,可以通过URI来启动另一台设备上的应用.激活远程应用需要以下前提: 系统必须是build 14393 ...

  4. 【Win 10 应用开发】导入.pfx证书

    这个功能其实并不常用,一般开发较少涉及到证书,不过,简单了解一下还是有必要的. 先来说说制作测试证书的方法,这里老周讲两种方法,可以生成用于测试的.pfx文件. 产生证书,大家都知道有个makecer ...

  5. 【Win 10应用开发】Adaptive磁贴模板的XML文档结构

    在若干天之前,老周给大家讲了Adaptive Toast通知的XML模板,所以相应地,今天老周给大家介绍一下Adaptive磁贴的新XML模板. 同样道理,你依旧可以使用8.1时候的磁贴模板,在win ...

  6. 【Win 10 应用开发】RTM版的UAP项目解剖

    Windows 10 发布后,其实SDK也偷偷地在VS的自定义安装列表中出现了,今天开发人员中心也更新了下载.正式版的SDK在API结构上和以前预览的时候是一样的,只是版本变成10240罢了,所以大家 ...

  7. 【Win 10应用开发】认识一下UAP项目

    Windows 10 SDK预览版需要10030以上版本号的Win 10预览版系统才能使用.之前我安装的9926的系统,然后安装VS 2015 CTP 6,再装Win 10 SDK,但是在新建项目后, ...

  8. 【Win 10 应用开发】在代码中加载文本资源

    记得前一次,老周给大伙,不,小伙伴们介绍了如何填写 .resw 文件,并且在 XAML 中使用 x:Uid 标记来加载.也顺便给大伙儿分析了运行时是如何解析 .resw 文件的. 本来说好了,后续老周 ...

  9. 在iOS开发中如何播放视频

     技术博客http://www.cnblogs.com/ChenYilong/  新浪微博http://weibo.com/luohanchenyilong  如何播放视频 •iOS提供了叫做MPMo ...

随机推荐

  1. Servlet 笔记-生命周期

    Servlet 生命周期可被定义为从创建直到毁灭的整个过程.以下是 Servlet 遵循的过程: Servlet 通过调用 init () 方法进行初始化. Servlet 调用 service()  ...

  2. WPF ListBox 一些小知识点

    页面代码: <Grid Grid.Row="0" Grid.Column="2"> <ListBox x:Name="lvStep& ...

  3. C#匹配标签正则,获取标签的值

    比如要获取: <color=#50cccc>头盔坐标:(-0.6, 1.0, 1.2)</color><color=#3d85c6>头盔方向(-0.2, 0.1, ...

  4. R学习笔记 第三篇:数据框

    数据框(data.frame)用于存储二维表(即关系表)的数据,每一列存储的数据类型必须相同,不同的数据列的数据类型可以相同,也可以不同,但是,每列的长度必须相同.数据框的每列可以有唯一的命名,在已创 ...

  5. scp命令,用来在本地和远程相互传递文件,非常方便

    scp是secure copy的简写,用于在Linux下进行远程拷贝文件的命令,和它类似的命令有cp,不过cp只是在本机进行拷贝不能跨服务器,而且scp传输是加密的.可能会稍微影响一下速度.当你服务器 ...

  6. Ubuntu配置OpenStack 二:配置时间同步NTP和安装数据库Maridb以及问题总结

    继上一节Ubuntu配置OpenStack 一:配置主机环境,下面继续为安装时间同步,以及配置openstack的安装包源和安装数据库Maridb.(全文截图都是由自己徒手搭建完成并且截图) 一.安装 ...

  7. VS2008 C++ 利用WinHttp API获取任意Http网址的源码

    最近一直在看有关Http的知识,对其基本的理论知识已经有所掌握,想通过一个C++具体的例子进行实际操作..于是上网查找了很多资料,发现在Windows系统上,可以通过WinHttp API接口开啊Ht ...

  8. SSH服务详解

    第1章 SSH服务 1.1 SSH服务协议说明 SSH 是 Secure Shell Protocol 的简写,由 IETF 网络工作小组(Network Working Group )制定:在进行数 ...

  9. 交换知识 VLAN VTP STP 单臂路由

    第1章 交换基础 1.1 园区网分层结构 层次 作用 出口层 广域网接入 出口策略 带宽控制 核心层 高速转发 服务器接入 路由选择 汇聚层 流量汇聚 链路冗余 设备冗余 路由选择 接入层 用户接入 ...

  10. eclipse中删除多余的tomcat server

    在eclipse菜单中选择Window--Show View--Server--Servers,打开这个服务窗口,将多余的服务删除即可. 如果每次启动中太卡没反应,那就是服务没选择好,或是端口冲突的原 ...