【Win 10 应用开发】在后台播放视频
2017-12-02 18:11
399 查看
从 1607 (14393)版本开始,MediaPlayer 类就可以在前台与后台之间无缝播放,你不必再考虑前台与后之间的通信,所以从 14393 开始,你就不需要再用 BackgroundMediaPlayer 类了。无论多媒体资源是前台还是后台播放,都由 MediaPlayer 类负责。与此同时,在 XAML 控件体系中,MediaElement 类也由 MediaPlayerElement 类替代。
这些内容老周就不多说了,因为 SDK 文档的更新日志上都有说明。不管是音频或是视频都统一到 MediaPlayer 类中,正因为如此,实现后台播放视频就显得很是 Easy 了。
不废话,下面咱们来个示例来说明说明。
这个示例简单,老周就不用 Page 了,UI 的根直接来个 Grid 吧。
由于这不是项目默认生成的 Page ,所以注意(看好上面的 x:Class ,它指向对应的类),与它对应的代码文件中的类必须继承 Grid 类,不是 Page 类,代码类的基类就得与 XAML 文档的根元素匹配。
如果,你觉得有必要密封这个类(不让别人继承财产),就这样修饰。
按钮是干啥用的呢,这样,咱们待会儿运行后,点击按钮来打开一个视频文件,然后在 MediaPlayerElement 控件中播放(显示)。
在文首老周说过,现在 UWP 应用的多媒体播放都统一由 MediaPlayer 大哥负责,因此,MediaPlayerElement 类会公开一个 MediaPlayer 属性,你可以从这个属性获取到关联的 MediaPlayer 类实例(这个类位于 Windows.Media.Playback 命名空间)。
因此你看到了,在上面最后的代码上,老周调用的 Play 方法是 MediaPlayer 类的,实际上视频是在 MediaPlayer 上管理的。MediaPlayerElement 只负责显示(或者 UI 操作,如暂停等)。
行了,代码这么搞就OK了,不过要想让应用能在后台继续播放,清单文件上的配置是少不了的。打开清单文件(默认是以清单设计器打开),切换到“功能”选项卡,勾选“背景媒体播放”。这是翻译问题,其实应该叫“后台媒体播放”才对,不管它,知道是啥意思就行了,别纠结这些无关紧要的事情。
![](https://oscdn.geek-share.com/Uploads/Images/Content/202002/22/460048bb54d4cbb65266b1dc10f24be0.png)
清单文件其实是 XML 文档,所以,如果你觉得直接点两下鼠标没法装逼的话,可以手动写的。
首先,你要引入一个 v3 版本的 UWP 专用命名空间。
然后,你才能进行声明,写到 Package / Capabilities 节点下面。
最后,保存一下文件就完事了。
现在运行,随便找个视频播放,然后把程序最小化,或切换到其他应用,然后再切换回去,你会发现,当程序进入后台后,视频仍然在播放。
![](https://oscdn.geek-share.com/Uploads/Images/Content/202002/22/73644b51dd1834e7fa5b8163575029f7.gif)
其实,上面的实现还不够完善。你想啊,应用移到后台,UI 是看不见的,成了多余的货了,所以,我们妨考虑,在应用扔到后台时销毁 UI,等应用回到前台时再创建 UI。当然了,我们这个例子,界面比较简单,内存占用基本看不出来区别,大约也就是 0.1 MB 的差异。不过为了演示,我们还是处理一下应用程序的这两个事件:
当应用发送到后台,会引发 EnteredBackground 事件,当应用回到前台,则发生 LeavingBackground 事件。
下面我们处理一下。
进入后台后,把当前窗口的内容设为 null,可以解除对 XAML 对象的引用,然后扛一根大扫把来,调用GC成员打扫一下,清理内存。
当重新回到前台时,重建界面,这里为啥我要先看看窗口的内容是否为 null 呢?很简单啊,如果不为 null 说明界面创建好了,那就不必要重复创建了,没意义了。为啥会这样,因为有件事你得知道,当启动应用时,会执行 OnLaunched 方法,这个没疑问吧。然后呢,LeavingBackground 事件会发生一次。而我们在很多时候,OnLaunched 方法中已经建好界面了,正因为如此,在处理 LeavingBackground 事件时,一定要判断一下界面是否创建过了,如果已有界面实例,就不必再创建了。
顺便补一下,CreateUI 方法代码如下。
然后在你运行实例后,又出现新问题了。还记得吧?我们在 XAML 中放了一个 MediaPlayerElement 控件,现在应用进入后台后界面会释放,所以 MediaPlayerElement 控件的实例也会被干掉,等到应用再回到前台,MediaPlayerElement 控件已经是新创建的实例了,不是刚才的那个实例了,这就造成:回到应用后,视频不再播放了。
要解决这问题,我们只要想办法让 MediaPlayer 实例的生命周期与应用同步就好了,对,把它变成静态变量(static)。所以,我写了这么个类。
这样就可以让它静态了,别忘了,如果 MediaPlayerElement 控件实例是新创建的,会关联地创建一个 MediaPlayer 实例。为了让每个新创建的 MediaPlayerElement 控件实例所关联的 MediaPlayer 实例相同,我们可以调用控件的 SetMediaPlayer 方法。
回到咱们前面那个 Grid 的子类代码中,在构造函数中加上这么一句:
这样一来,不管咱们在应用生命周期内创建了多少个 MediaPlayerElement 控件实例,其关联的 MediaPlayer 对象都是我们上面公开的那个 CurrentPlayer 了,这确保了 MediaPlayer 实例的全局唯一性。
现在再次运行示例,在界面元素销毁后再次回到应用程序,视频仍能继续播放。
好了,今天的话题聊完了,该用饭了。
这些内容老周就不多说了,因为 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了,不过要想让应用能在后台继续播放,清单文件上的配置是少不了的。打开清单文件(默认是以清单设计器打开),切换到“功能”选项卡,勾选“背景媒体播放”。这是翻译问题,其实应该叫“后台媒体播放”才对,不管它,知道是啥意思就行了,别纠结这些无关紧要的事情。
![](https://oscdn.geek-share.com/Uploads/Images/Content/202002/22/460048bb54d4cbb65266b1dc10f24be0.png)
清单文件其实是 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>
最后,保存一下文件就完事了。
现在运行,随便找个视频播放,然后把程序最小化,或切换到其他应用,然后再切换回去,你会发现,当程序进入后台后,视频仍然在播放。
![](https://oscdn.geek-share.com/Uploads/Images/Content/202002/22/73644b51dd1834e7fa5b8163575029f7.gif)
其实,上面的实现还不够完善。你想啊,应用移到后台,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 应用开发】在后台进行多媒体转码
- 【Win 10 应用开发】Toast通知激活应用——前台&后台
- 【Win 10 应用开发】Toast通知激活应用——前台&后台
- 【Win 10 应用开发】在App所在的进程中执行后台任务
- 【Win 10应用开发】实现全屏播放的方法
- 【Win 10 应用开发】Sqlite 数据库的简单用法
- 【Win 10应用开发】SplitView控件
- 【Win 10 应用开发】手写识别
- 【Win 10 应用开发】获取本机的IP地址
- 【Win 10应用开发】SplitView控件
- 【Win 10 应用开发】在代码中加载文本资源
- 【Win 10应用开发】手动调用WCF服务
- 【Win 10应用开发】如何知道UAP在哪个平台上运行
- 【Win 10 应用开发】InkToolBar——涂鸦如此简单
- UWP应用开发系列视频教程简介 - Built for Windows 10
- iOS开发网络篇—实现一个视频播放客户端小应用
- 【Win 10 应用开发】RTM版的UAP项目解剖
- 【Win 10应用开发】提供建议列表的输入控件(AutoSuggestBox)
- iOS开发网络篇—实现一个视频播放客户端小应用(一)