【跟Z学开发】1.2 做一个更简陋的播放器

zcxsythenew UID.911687
2017-07-12 发表

本帖最后由 zcxsythenew 于 2017-7-12 19:50 编辑

专题一 开发一个媒体播放应用
课题2 做一个更简陋的播放器

语言:C#
想要学习XAML的可以继续关注后续课程。
上节课我们已经做了最简陋的播放器,但是这节课我们还要做一个更简陋的。“最简陋”,是从代码的角度上看;“更简陋”,是从用户的角度看。面向用户,是我们写程序的最终目的。

本节包含:
后台任务

首先,我们来揭晓上节课的答案。

[backcolor=red]请通过电脑网页版来浏览此教程。[/backcolor][page]专题一 开发一个媒体播放应用
课题2 做一个更简陋的播放器

其实,哪里有答案?

在写程序的领域里面,没有正确答案,只有更好的答案和不太好的答案。我们举个例子,可能学习了算法的人会觉得比较熟悉:

将1、4、7、2、9、3、5、8、6按从小到大排序。

一种可能的解决方案是:
先找到第1个最小的,然后再找到第2个最小的,以此类推。

另外一种是:
1. 随机选取一个数。
2. 将比这个数小的数放在这个数的左边。
3. 将比这个数大的数放在这个数的右边。
4. 分别对这个数的左、右两边重复第1至4步,直到排好为止。

哪种方法是对的呢?两种都是对的。当我们有多于一种的解决方案的时候,我们必须选择较好的那一个。如果我们要用电脑来给1x10^9个数尽可能快地排序,我们应该采用后一种解决方案;但是,如果我们要给一个幼儿园的小朋友教排序的时候,我们最好选择前一种。

讲了那么久,还是没有揭晓答案。其实我就是想说,我们要有一种意识,要主动地去想更多的解决方案,然后再在里面选最好的一种。下节课开始,我们会碰到更多的这种问题。下一页,我会给出2种解决方案。[page]专题一 开发一个媒体播放应用
课题2 做一个更简陋的播放器

方案1 将player改为全局变量[mw_shl_code=csharp,true] public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
}

MediaPlayer player = new MediaPlayer();

/// <summary>
/// 在应用程序由最终用户正常启动时进行调用。
/// 将在启动应用程序以打开特定文件等情况下使用。
/// </summary>
/// <param name="e">有关启动请求和过程的详细信息。</param>
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
if (e.PrelaunchActivated == false && (player.PlaybackSession.PlaybackState == MediaPlaybackState.None || player.PlaybackSession.PlaybackState == MediaPlaybackState.Paused))
{
player.Source = MediaSource.CreateFromUri(new Uri("http://ngcdn003.cnr.cn/live/yyzs48/index.m3u8"));
player.Play();
}

//其它代码
}[/mw_shl_code]因为当应用正在运行的时候,再去点击它的磁贴,并不会再新建一个App,只是将OnLaunched再执行一次,全局变量的值没有更改,所以此方案可行。player.PlaybackSession.PlaybackState表示播放器的当前状态。

方案2 把代码下移至合适的位置[mw_shl_code=csharp,true] protected override void OnLaunched(LaunchActivatedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;

// 不要在窗口已包含内容时重复应用程序初始化,
// 只需确保窗口处于活动状态
if (rootFrame == null)
{
// 创建要充当导航上下文的框架,并导航到第一页
rootFrame = new Frame();

rootFrame.NavigationFailed += OnNavigationFailed;

if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: 从之前挂起的应用程序加载状态
}

// 将框架放在当前窗口中
Window.Current.Content = rootFrame;
}

if (e.PrelaunchActivated == false)
{
if (rootFrame.Content == null)
{
// 当导航堆栈尚未还原时,导航到第一页,
// 并通过将所需信息作为导航参数传入来配置
// 参数
MediaPlayer player = new MediaPlayer()
{
Source = MediaSource.CreateFromUri(new Uri("http://ngcdn003.cnr.cn/live/yyzs48/index.m3u8"))
};
player.Play();
rootFrame.Navigate(typeof(MainPage), e.Arguments);
}
// 确保当前窗口处于活动状态
Window.Current.Activate();
}
}[/mw_shl_code]这里是利用了微软预置的代码。微软其实挺精明,它已经设置了仅当非预启动的时候,才加载首页(MainPage)。我们可以利用现有的代码,在加载首页的时候,顺便开始播放。[page]专题一 开发一个媒体播放应用
课题2 做一个更简陋的播放器

在上节课做的播放器当中,如果你按了一下音量键,就会发现系统已经帮你做好了控制条:

***附件停止解析***

***附件停止解析***

有了这个控制条,我们仿佛觉得打开的空白窗口实在是太多余了。我们打算把这个空白窗口干掉,以实现“更简陋”的目标。
这个时候,我们需要把单进程的后台播放分离出来,改为传统的双进程。双进程由前台UI和后台任务构成。
注意:在后续的学习过程中,我们会遇到很多的后台任务。因此这节课很重要。

第1部分 添加后台任务

第1步 向现有解决方案中添加项目(新建项目)。

***附件停止解析***

第2步 选择“Windows运行时组件”。你可以使用任意名称(最好只包括英文字母和数字),但是要留意,这个名称后面会用到。

第3步 选择版本时,“目标版本”和“最低版本”最好和你上一节课选择的保持一致。

第4步 (可选)你可以给“Class1”改名(最好只包括英文字母和数字)。改名后,点击灯泡,然后选择“将文件名改为xx.cs”。

***附件停止解析***

第5步 在这个名字后面,输入“:IBackgroundTask”。按上节课的方法,利用灯泡,添加using。

第6步 再次点击灯泡。选择“实现接口”或“显式实现接口”均可,因为我们很少会在其它地方再用到这些代码。如果需要,那么我们就要考虑显式和隐式的问题。

第7步 在“throw new NotImplementedException();”前面加上“//”。这一行代码用来指示“这个方法被调用了”,而我们目前的项目结构比较简单,暂时还不需要它。

现在你的代码看起来像这样:(以显式实现接口为例)

***附件停止解析***

第8步 把我们上节课的代码移动过去。(原来的App.xaml.cs不保留这些代码。)

***附件停止解析***

记下第1至7步。每次你要用到后台任务,都要重复这些步骤。[page]专题一 开发一个媒体播放应用
课题2 做一个更简陋的播放器

第2部分 请求延时

在UWP开发当中,你可能经常碰到这两个东西:GetDeferral和IsHandled。IsHandled在后面会讲到。

GetDeferral表示请求延时。一般来讲,用到“await”这个词的代码都需要请求延时。我们做的是一个后台播放器,即使没有await,也要请求延时。不过,我的习惯是:凡是见到GetDeferral,不管三七二十一,请求延时了再说。

GetDeferral的用法是:[mw_shl_code=csharp,true]BackgroundTaskDeferral def = taskInstance.GetDeferral();

//在这行插入要执行的代码

def.Complete();[/mw_shl_code]现在的代码看起来像这样:

***附件停止解析***

但是有什么地方不对。def.Complete();之后,后台任务将会终止。player.Play();只是一瞬间的动作,表示让播放器开始播放,后面紧跟着def.Complete();,关掉后台进程以后,等于整个player都要被“铲掉”,那么这个后台播放还有效果吗?

我们下面就要学到事件处理。

在BackgroundTaskDeferral def = taskInstance.GetDeferral();的下一行,输入:taskInstance.Canceled+=

***附件停止解析***

然后按Tab。

***附件停止解析***

你可以选择给突出显示的部分改名(最好只包括英文字母和数字),改完点“应用”就可以了。把“throw new NotImplementedException();”注释掉。

这部分的代码表示系统已经“忍无可忍”了,要强行把你的后台任务终止掉。在终止掉之前,问一问这个后台任务有什么“遗言”要说。我们把def设置为全局变量,然后把“def.Complete();”放到“遗言”里面。

系统:“你实在是太磨叽了,我得把你干掉。”
后台任务:“你看,我已经搞完了。”(假装自己是个好人。)
系统:“……”

***附件停止解析***

当然,对于后台音频,系统还是非常通情达理的。一般情况下,不会把它终止。
最后我们再作一个小的更改。由于我们用的是传统的双进程模型,那么我们的MediaPlayer可以使用BackgroundMediaPlayer.Current,方便两个进程的通信。

***附件停止解析***[page]专题一 开发一个媒体播放应用
课题2 做一个更简陋的播放器

现在,我们已经把后台任务写好了。我们需要在前台里面放一些代码,以启动这个后台任务。

第3部分 声明后台任务

第1步 打开Package.appxmanifest。

第2步 点击“声明”。

第3步 在“可用声明”处,添加“后台任务”。

第4步 在“属性”里面勾选“音频”。

第5步 填写“入口点”,然后保存。还记得之前那张图吗?

***附件停止解析***

以上图为例,则填入SampleBackground.StartMagic。

第4部分 注册后台任务

微软建议,每次“启动”应用的时候,重新注册后台任务。“启动”,“点开”,似曾相识。你可以选择每一次“点开”的时候就重新注册,也可以只在每一次“启动”的时候才重新注册。如果你要选择后者,可以翻开这篇教程的第3页回顾一下那两种方法。

这里只介绍前者,但是我强烈建议你也试一试后者怎么做。经常复习,对你写程序很有帮助。[page]专题一 开发一个媒体播放应用
课题2 做一个更简陋的播放器

第4部分 注册后台任务

“重新注册后台任务”包含两步,一步是把现有的删掉,另一步是注册一个新的。

在OnLaunched下面插入以下代码。如果Visual Studio提示出错,请按上节课的例子添加必要的using。

第1步 删掉现有的后台任务(如果有)[mw_shl_code=csharp,true]string exampleTaskName = "StartMagic";
//后台任务的名字。在本案例中,你可以任意更改它(但最好只包括英文字母和数字)。

foreach (KeyValuePair<Guid,IBackgroundTaskRegistration> task in BackgroundTaskRegistration.AllTasks)
//搜索已注册的所有后台任务。对于每一个后台任务,进行以下操作。
{
if (task.Value.Name == exampleTaskName)
//找到同名的后台任务。
{
task.Value.Unregister(false);
//取消注册。false表示允许正在进行的任务完成(如果有),true表示立即终止。
break;
//如果你确信你没有反复地注册同一个后台任务,你可以用break;结束循环,以示你的自信。
}
}
BackgroundExecutionManager.RemoveAccess();
//向Windows说明你已经把后台任务清空了。[/mw_shl_code]第2步 注册新的后台任务
输入:[mw_shl_code=csharp,true]BackgroundAccessStatus status = await BackgroundExecutionManager.RequestAccessAsync();[/mw_shl_code]这里是我们第一次接触await。我们需要返回到上面,将[mw_shl_code=csharp,true]protected override void OnLaunched(LaunchActivatedEventArgs e)[/mw_shl_code]改为[mw_shl_code=csharp,true]protected override async void OnLaunched(LaunchActivatedEventArgs e)[/mw_shl_code]使await“合法化”。

一般来讲,名称包含“Async”的函数可以异步执行。如果不用await,那么应用将会一边执行BackgroundExecutionManager.RequestAccessAsync(),一边继续执行下面的代码。在本例中,并不合适。

补全代码如下:[mw_shl_code=csharp,true]BackgroundAccessStatus status = await BackgroundExecutionManager.RequestAccessAsync();
//向Windows请求注册后台任务。
if(status != BackgroundAccessStatus.Denied && status != BackgroundAccessStatus.DeniedBySystemPolicy && status != BackgroundAccessStatus.DeniedByUser)
//如果Windows表示“可以”,则继续执行以下代码。
//你有没有发现这一段if太长了?你可以用switch代替。还记得switch怎么写吗?
{
BackgroundTaskBuilder builder = new BackgroundTaskBuilder()
{
Name = exampleTaskName,
TaskEntryPoint = "SampleBackground.StartMagic"//这里改为你在Package.appxmanifest中填写的入口点。
};
builder.SetTrigger(new ToastNotificationActionTrigger());
//启动后台任务的条件。此处以交互式通知为例。
builder.Register();
//注册后台任务。
}[/mw_shl_code][page]专题一 开发一个媒体播放应用
课题2 做一个更简陋的播放器

第5部分 添加引用

在App.xaml.cs所在的项目,点右键,选择“添加”>“引用”。

***附件停止解析***

勾选,然后点确定。

***附件停止解析***

第6部分 等等,还有几步……

我们已经把后台任务准备好了。但是,我们到现在,还没有启动它。

下节课:2017年7月14日19:00。我们继续讲。

[backcolor=red]请投票选择“打卡签到”,谢谢。[/backcolor]

敬告:
为防止不可控的内容风险,本站已关闭新用户注册,新贴的发表及评论;
你现在看到的内容只是互联网用户曾经发表的言论快照,仅用于老用户留存纪念,且仅与科技行业相关,全部内容不代表本站观点及立场;
本站重新开放前已针对包括用户隐私、版权保护、信息安全、国家政策在内的各种互联网法律法规要求,执行了隐患内容的自查、屏蔽和删除;
本站目前所属个人主体,未有任何盈利安排与计划,且与原WFUN.COM所属公司不存在任何关联关系;
如果本帖内容或者相关资源侵犯到您的合法权益,或者您认为存在问题,那么请您务必点此举报或投诉!
全部回复:
zhangshengyou UID.302226
2017-07-12 回复

谁能告诉我开发这玩意英语要几级

zcxsythenew UID.911687
2017-07-12 回复

Quote***链接停止解析***
谁能告诉我开发这玩意英语要几级


我注意到你好像并没有在第一节课(***链接停止解析***)签到。你可以从那里开始。
英语对编程确实有帮助,不过并不起决定性因素,并不需要考级。编程中遇到的英语可以慢慢学。
起决定性因素的,我认为是对编程的兴趣。

忘水草 UID.2837260
2017-07-12 回复

这节课太难了{:6_226:}先mark一下

ho****ns UID.2847685
2017-07-12 使用 Lumia 950 XL 回复

先收藏,等这段时间事情忙完学

AFAN-World UID.2879093
2017-07-13 使用 Lumia 640 XL 回复

加油。。 嗯,大概是当局者迷吧,我不知如何评价。 加油就好。

无效用户名 UID.2891265
2017-07-13 使用 Lumia 950 回复

额。。我看到了标题 。然后 到底在干什么

小张qq UID.1257492
2017-07-13 使用 Lumia 640 XL 回复

支持支持

zcxsythenew UID.911687
2017-07-13 回复

QuoteAFAN-World 发表于 2017-7-13 00:13
加油。。 嗯,大概是当局者迷吧,我不知如何评价。 加油就好。


此话怎讲?

AFAN-World UID.2879093
2017-07-13 使用 Lumia 640 XL 回复

Quotezcxsythenew 发表于 2017-7-13 10:53
此话怎讲?


嗯? 因为此类教材因人而异,各有不同。 也不能说“精通xx”那本书就是标准。 (不过你确定论坛上想学的人都能看懂?建议你问一下{:6_230:})

zcxsythenew UID.911687
2017-07-13 回复

QuoteAFAN-World 发表于 2017-7-13 11:32
嗯? 因为此类教材因人而异,各有不同。 也不能说“精通xx”那本书就是标准。 (不过你确定论坛上想学的人都 ...


其实我早有心理准备。你可以到***链接停止解析***的18楼参观一下。 另外也可以给你一些参考,如果你还打算更新《次元之内》的话。***链接停止解析***5楼。(我是真的觉得写控制台程序没什么用。)

AFAN-World UID.2879093
2017-07-13 使用 Lumia 640 XL 回复

Quotezcxsythenew 发表于 2017-7-13 11:51
其实我早有心理准备。你可以到第一节课的18楼参观一下。 另外也可以给你一些参考,如果你还打算更新《次元 ...


为你点赞 主要是怕你走不出这个坑,最后抑郁{:6_230:} 有心理准备就好。 所以我的itd也是挂在那里,想起来就更一更。 大概干这事的最后都逃不出这个坑吧。

AFAN-World UID.2879093
2017-07-13 使用 Lumia 640 XL 回复

Quotezcxsythenew 发表于 2017-7-13 11:51
其实我早有心理准备。你可以到第一节课的18楼参观一下。 另外也可以给你一些参考,如果你还打算更新《次元 ...


我还是觉得两个一起学会累死。所以先来console,不是因为我喜欢黑框框,而是只来cs比较容易接受。

zcxsythenew UID.911687
2017-07-13 回复

Quote***链接停止解析***
我还是觉得两个一起学会累死。所以先来console,不是因为我喜欢黑框框,而是只来cs比较容易接受。 ...


这两节课我都避开了XAML了,所以我说可以给你一些参考,不必要写什么控制台。

AFAN-World UID.2879093
2017-07-13 使用 Lumia 640 XL 回复

Quotezcxsythenew 发表于 2017-7-13 12:16
这两节课我都避开了XAML了,所以我说可以给你一些参考,不必要写什么控制台。 ...


不过对于强迫症的我来说第一节课有个Program()已经足够。 总感觉wpf也好uwp也好干了很多事,,可我第一节课只要一个入口点,,,

zcxsythenew UID.911687
2017-07-13 回复

QuoteAFAN-World 发表于 2017-7-13 12:35
不过对于强迫症的我来说第一节课有个Program()已经足够。
总感觉wpf也好uwp也好干了很多事,,可我第一 ...


也对。你的课是零基础的,而我的要求了解C#语法。普及C#语法的重担我实在挑不起来……

AFAN-World UID.2879093
2017-07-13 使用 Lumia 640 XL 回复

Quotezcxsythenew 发表于 2017-7-13 12:46
也对。你的课是零基础的,而我的要求了解C#语法。普及C#语法的重担我实在挑不起来…… ...


就照各大“精通”书籍cs一百年也无法普及。实在气的不行,所以决定从零基础开始。 然而我的更新速度让我自己都想打我自己。

zcxsythenew UID.911687
2017-07-13 回复

Quote***链接停止解析***
就照各大“精通”书籍cs一百年也无法普及。实在气的不行,所以决定从零基础开始。
然而我的更新速度让我自 ...


可能你要做的项目太多了吧,一会Longhorn,一会CreativeProgram,一会Media Center,一会次元之内。毕竟你不像我一个准大一学生有那么长的假期,我感觉你要做一做计划。

薛定谔的cat UID.1010293
2017-07-13 回复

Quotezhangshengyou 发表于 2017-7-12 19:50
谁能告诉我开发这玩意英语要几级


就那么几个,用的多了,你英语都好了,哈哈

AFAN-World UID.2879093
2017-07-13 使用 Lumia 640 XL 回复

Quotezcxsythenew 发表于 2017-7-13 14:35
可能你要做的项目太多了吧,一会Longhorn,一会CreativeProgram,一会Media Center,一会次元之内。毕竟 ...


{:6_230:} 对于每天晚上0点-5点开发的人来说,我的计划都是长期的,并不打算在某某期限内完成。 然而我比较,作,?发的预告贴太多了,于是被骂的很惨。 现在基本潜水了,有时间就更itd。 {:6_230:}

AFAN-World UID.2879093
2017-07-13 使用 Lumia 640 XL 回复

Quotezcxsythenew 发表于 2017-7-13 14:35
可能你要做的项目太多了吧,一会Longhorn,一会CreativeProgram,一会Media Center,一会次元之内。毕竟 ...


谢谢提醒,这真的是对我非常好的建议。

vbfool UID.352791
2017-07-13 回复

你们俩啊,真的是蛋疼。
为什么要学控制台,为什么要接触这玩意儿,因为这个是当一个真正的程序员的必经之路。
不想当程序员的当然懒得学这个了,甚至我认为真的要学UWP之前,先在控制台摸索几个月是必须的。
如果只是自己写着玩,控制台啊XAML啊API啊各种基础啊这些玩意儿,不用怎么懂也不怕,那些用按键精灵做外挂的人,不也不懂怎么写程序么。

笨丶苽苽 UID.1017039
2017-07-13 回复

老铁,哎,WPF和UWP区别大吗??

zcxsythenew UID.911687
2017-07-13 回复

Quote***链接停止解析***
你们俩啊,真的是蛋疼。
为什么要学控制台,为什么要接触这玩意儿,因为这个是当一个真正的程序员的必经之 ...


反正我也不打算讲怎么当“真正”的程序员。这些课还是留给高校去讲吧,我也要马上就进高校学习了,所以我不担心。

如果你有了解《次元之内》的话,你会发现他主张不要看书,主张实用主义。我也是实用主义,我也就打算教一教怎么玩API,就类似于你讲的“精灵外挂”,有兴趣的玩一玩罢了。如果有人打算去学当真正的程序员,却来看我这个课,那肯定是脑抽风了。

控制台我也摸过(主要是学算法),在高中的信息学竞赛班,摸了两年,学习了各种算法,但是仍然感到力不从心。确实不是那么好学的。

zcxsythenew UID.911687
2017-07-13 回复

Quote笨丶苽苽 发表于 2017-7-13 23:17
老铁,哎,WPF和UWP区别大吗??


此话怎讲?
如果从字面意义上解,你是想说WPF和UWP区别较小(但仍有区别),是并列关系,而不是UWP以WPF为基础或相反,那么为什么不直接学UWP?

笨丶苽苽 UID.1017039
2017-07-14 回复

Quotezcxsythenew 发表于 2017-7-13 23:58
此话怎讲?
如果从字面意义上解,你是想说WPF和UWP区别较小(但仍有区别),是并列关系,而不是UWP以WPF ...


是这样的,我目前学了c#基础,然后接触到了wpf和winForm ,现在是到了一个十字路口,不知道走哪条路下去?有朋友让我学习MVC,不推荐学winForm 和WPF。我也看了下uwp和wpf有很多相似之处。所以很纠结啊,学得也不是很深。而且是自学,比较慢

zcxsythenew UID.911687
2017-07-14 回复

Quote笨丶苽苽 发表于 2017-7-14 09:16
是这样的,我目前学了c#基础,然后接触到了wpf和winForm ,现在是到了一个十字路口,不知道走哪条路下去 ...


你的目标是什么?你是想做专业的、业余纯兴趣的还是靠这个吃饭的程序员?

vbfool UID.352791
2017-07-14 回复

Quote***链接停止解析***
是这样的,我目前学了c#基础,然后接触到了wpf和winForm ,现在是到了一个十字路口,不知道走哪条路下去 ...


做网站是现在的主流,所以学会ASP.NET Core是最容易混到饭吃的。
WPF和UWP这俩,认真说没啥区别,因为那些区别还没到南辕北辙的地步,你可以把这个当作业余时间接触的东西,在保证饿不死的时候学学。招WPF的人,一般都要求你有两把刷子的,初学者靠这个混饭吃并不容易。
winform这玩意儿,我做了这么多年WPF之后,winform都忘光了,现在回过头来再用,只有一种想法,打死我算了。但是这玩意儿还有大把的公司在用,用来做企业应用之类的玩意儿,也算是个混饭吃的路子,毕竟要求比WPF低。

笨丶苽苽 UID.1017039
2017-07-14 回复

Quotezcxsythenew 发表于 2017-7-14 09:57
你的目标是什么?你是想做专业的、业余纯兴趣的还是靠这个吃饭的程序员? ...


算业余的吧,我目前做硬件的工作,也没打算靠这个吃饭,只是为自己多准备点知识。所以你有没有什么建议呢?

zcxsythenew UID.911687
2017-07-14 回复

Quote笨丶苽苽 发表于 2017-7-14 10:20
算业余的吧,我目前做硬件的工作,也没打算靠这个吃饭,只是为自己多准备点知识。所以你有没有什么建议呢 ...


业余的话,我觉得想学什么就学什么。因为我对UWP感兴趣,所以我才学了半吊子的UWP。 IT行业变化快,要随时做好学新东西的准备。不过既然业余,那就没什么所谓了。

max****ker UID.2903974
2017-07-15 回复

Quote***链接停止解析***
做网站是现在的主流,所以学会ASP.NET Core是最容易混到饭吃的。
WPF和UWP这俩,认真说没啥区别,因为那 ...


握手,学WPF之前,Winform用得很熟练,学WPF之后,从此抛弃Winform,回头来搞Winform突然变得无所适从,不知道该怎么搞了。

另外,WPF跟UWP的XAML,如果说区别,是有很大区别的,UWP的XAML跟Silverlight差不多,功能特性比WPF少很多。

本站使用Golang构建,点击此处申请开源鄂ICP备18029942号-4联系站长投诉/举报