UWP - 介绍App Service 与新功能
App Service 是一种背景工作运行的服务,提供给其他Apps 使用就像Web Service。它本身无使用介面(UI-less),允许Apps 在同一个设备被引用,甚至Windows 10 1607 开始允许remote devices 使用它。
[ 重点观念 ]
Windows 10, version 1607 开始, App Service 支持新模式:
可以与host App 运行在相同的process;(一般属于Background Task 执行在不同的process)
支援从App呼叫Remote Devices中的App Service;
想要App Service每次被启动都是新的instance,在Package.appmanifest加入宣告;uap4:SupportsMultipleInstances="true";但需要Windows 10, version 15063以上才支援
App Service 的生命周期,因为Process 有所不同:
后台任务(进程外):
当它被建立时会进入Run(),随着Run()执行完毕就会被结束
它被启动后,基本会维持活着约有30秒,可搭配呼叫GetDeferral()多加5秒来完成任务
In-app process model:生命周期则跟着呼叫者一起共存,让两个Apps 之间更容易沟通,不用再分成两份code 来串联与维护
App Service 的OnTaskCancel() 被触发有几个原因:
Client app释放AppServiceConnection
Client app 被 suspended
系统关闭或睡眠
系统执行该Task 用过高的资源
大略有概念之后,接着介绍怎么做基本的App Service (two process),再介绍怎么整合到App 的process 里面;
- 如何建立App service 并使用它:
分成两个App 做说明:一个是拥有App Service 的Host App;一个是使用App Service 的Client App;
1建立一个Windows Runtime Component,并且加入AppServiceConnection 的处理逻辑:
public sealed class ServiceTask : IBackgroundTask
{
private BackgroundTaskDeferral backgroundTaskDeferral;
private AppServiceConnection appServiceconnection;
public void Run(IBackgroundTaskInstance taskInstance)
{
// Background Task 被建立時,取得 deferral 拉長生命周期,避免被結束
this.backgroundTaskDeferral = taskInstance.GetDeferral();
// 一定要註冊處理 Canceled 事件來正確釋放用到的資源
taskInstance.Canceled += OnTaskCanceled;
// 根據被啓動的 Instance 類型,建立 App Service Connection,並註冊 Request 事件.
var details = taskInstance.TriggerDetails as AppServiceTriggerDetails;
appServiceconnection = details.AppServiceConnection;
appServiceconnection.RequestReceived += OnRequestReceived;
}
private void OnTaskCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
if (this.backgroundTaskDeferral != null)
{
// Complete the service deferral.
this.backgroundTaskDeferral.Complete();
}
}
private async void OnRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
{
// 當 App Service 收到請求時,該 method 就會被觸發
// 先要求取得 取得 deferral 拉長生命周期
var requestDeferral = args.GetDeferral();
ValueSet message = args.Request.Message;
string cmd = message["cmd"] as string;
string id = message["id"] as string;
ValueSet responseMsg = new ValueSet();
switch (cmd)
{
case "Query":
responseMsg.Add("id", "123456");
responseMsg.Add("name", "pou");
responseMsg.Add("status", "OK");
var result = await args.Request.SendResponseAsync(responseMsg);
break;
}
requestDeferral.Complete();
}
}
2在Host App 的Package.manifest 宣告App Service 并设定Entry Point,记得把App Service 的专案加入到Host App 的专案参考:
<Applications>
<Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="ServiceHost.App">
<uap:VisualElements />
<Extensions>
<uap:Extension Category="windows.appService" EntryPoint="MyAppService.ServiceTask">
<uap:AppService Name="com.pou.MyApService" />
</uap:Extension>
</Extensions>
</Application>
</Applications>
加入专案参考这样在Host App被安装的时候才会一并加入App Service。利用Windows.ApplicationModel.Package.Current.Id.FamilyName在Host App拿到package family name,准备交给Client App。
3在 Client App 利用 AppServiceConnection 呼叫 App Service:
private async void MainPage_Loaded(object sender, RoutedEventArgs e)
{
AppServiceConnection connection = new AppServiceConnection();
connection.AppServiceName = "com.pou.MyApService";
connection.PackageFamilyName = "f9842749-e4c8-4c15-bac8-bc018db1b2ea_s1mb6h805jdtj";
var status = await connection.OpenAsync();
if (status != AppServiceConnectionStatus.Success)
{
Debug.WriteLine("Failed to connect");
return;
}
var message = new ValueSet();
message.Add("cmd", "Query");
message.Add("id", "1234");
AppServiceResponse response = await connection.SendMessageAsync(message);
string result = "";
if (response.Status == AppServiceResponseStatus.Success)
{
if (response.Message["status"] as string == "OK")
{
result = response.Message["name"] as string;
}
}
}
上面介绍的App Service 是比较一般的用法, 把App Service 放到Background Task 的架构。
- 把App Service 合并到App.xaml.cs 里面,作为Same Process:
AppServiceConnection允许其他App叫醒在背景中自己的App并传入指令。它与上方的out-of-process最大不同有两个:
1Package.manifest 宣告 <uap:Extension Category="windows.appService"> 不用 Entry Point,改用 OnBackgroundActivated()。
<Package>
<Applications>
<Application>
<Extensions>
<uap:Extension Category="windows.appService">
<uap:AppService Name="com.pou.MyApService" />
</uap:Extension>
</Extensions>
</Application>
</Applications>
2在App.xaml.cs加入OnBackgroundActivated()的处理逻辑。
sealed partial class App : Application
{
private AppServiceConnection appServiceConnection;
private BackgroundTaskDeferral appServiceDeferral;
protected override void OnBackgroundActivated(BackgroundActivatedEventArgs args)
{
base.OnBackgroundActivated(args);
AppServiceTriggerDetails appService = args.TaskInstance.TriggerDetails as AppServiceTriggerDetails;
if (appService ==null)
{
return;
}
args.TaskInstance.Canceled += OnAppServicesCanceled;
// appServiceDeferral 與 appServiceConnection 需要變成公用變數
// 因爲其他時間需要用到,已維持連線的一致性
appServiceDeferral = args.TaskInstance.GetDeferral();
appServiceConnection = appService.AppServiceConnection;
appServiceConnection.RequestReceived += AppServiceConnection_RequestReceived;
appServiceConnection.ServiceClosed += AppServiceConnection_ServiceClosed;
}
private async void AppServiceConnection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
{
// 當 App Service 收到請求時,該 method 就會被觸發
// 先要求取得 取得 deferral 拉長生命周期
var requestDeferral = args.GetDeferral();
ValueSet message = args.Request.Message;
string cmd = message["cmd"] as string;
string id = message["id"] as string;
ValueSet responseMsg = new ValueSet();
switch (cmd)
{
case "Query":
responseMsg.Add("id", "123456");
responseMsg.Add("name", "pou");
responseMsg.Add("status", "OK");
var result = await args.Request.SendResponseAsync(responseMsg);
break;
}
requestDeferral.Complete();
}
private void AppServiceConnection_ServiceClosed(AppServiceConnection sender, AppServiceClosedEventArgs args)
{
appServiceDeferral?.Complete();
appServiceConnection?.Dispose();
}
private void OnAppServicesCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
appServiceDeferral?.Complete();
appServiceConnection?.Dispose();
}
}
要支援in-process model就是这样简单,而且让原本的App Service逻辑回到App本身,让逻辑更干净。OnBackgroundActivated()负责处理App Service的启用,并储存Deferral保持服务的生命周期,详细可以参考Windows 10通用Windows平台(UWP) app周期。
UWP - 介绍App Service 与新功能的更多相关文章
- 从淘宝 UWP 的新功能 -- 比较页面来谈谈 UWP 的窗口多开功能
前言 之前在 剁手党也有春天 -- 淘宝 UWP ”比较“功能诞生记 这篇随笔中介绍了一下 UWP 淘宝的“比较”新功能呱呱坠地的过程.在鲜活的文字背后,其实都是程序员不眠不休的血泪史(有血有泪有史) ...
- Android 9 新功能 及 API 介绍(提供了实用的模块化的功能支持,包括 人工智能)
Android 9(API 级别 28)为用户和开发者引入了众多新特性和新功能. 本文重点介绍面向开发者的新功能. 要了解新 API,请阅读 API 差异报告或访问 Android API 参考. ...
- Java 14 新功能介绍
不做标题党,认认真真写个文章. 文章已经收录在 Github.com/niumoo/JavaNotes 和未读代码博客,点关注,不迷路. Java 14 早在 2019 年 9 月就已经发布,虽然不是 ...
- Redis4.0支持的新功能说明
本文以华为云DCS for Redis版本为例,介绍Redis4.0的新功能.文章转载自华为云帮助中心. 与Redis3.x版本相比,DCS的Redis4.x以上版本,除了开源Redis增加的特性之外 ...
- WSS存储服务器(Windows Storage Server) 2012新功能解析
虽然最近一段时间有关微软的新闻大多数集中在Windows 8以及Surface平板设备身上,但数周之前Windows Server 2012新版本中所包含的Windows Storage Server ...
- LightningChart最新版 v.8.3 全新发布,新功能使用教程。
LightningChart最新版v.8.3全新发布,主要介绍以下五个新功能及使用教程. 1. 网格模型,三角鼠标追踪 Tracing MeshModels with mouse. Traced ...
- Java 11 新功能来了!
关键时刻,第一时间送达! 目前 Oracle 已经发布了 Java Development Kit 10,下个版本 JDK 11 也即将发布.本文介绍 Java 11 的新功能. 根据Oracle新出 ...
- Java 11新功能抢先了解
目前 Oracle 已经发布了 Java Development Kit 10,下个版本 JDK 11 也即将发布.本文介绍 Java 11 的新功能. 根据Oracle新出台的每6个月发布一次Jav ...
- TFS 2015新功能之一,当前迭代查询标记
TFS 2015发布在即,有幸作为MVP提前获得了TFS的RTM版本,下面就TFS 2015的新功能做一些介绍: TFS 2015新功能之一,当前迭代查询标记 在TFS的查询中,可以将" ...
随机推荐
- C语言经典试题--指针
分享一道C语言的经典的题目.题目要求如下: 利用字符指针实现字符串1"I Love China"与字符串2"So do I"的输出.然后利用字符指针将字符串2的 ...
- ES 基础知识点总结
为什么使用 ES? 在传统的数据库中,如果使用某列记录某件商品的标题或简介.在检索时要想使用关键词来查询某个记录,那么是很困难的,假设搜索关键词 "小米",那么 sql 语句就是 ...
- Docker与k8s的恩怨情仇(六)—— “容器编排”上演“终结者”大片
转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 在上节中,我们为大家介绍了Pod的基础内容,Kubernetes如何站在上帝视角上处理容器和容器之间的关系. ...
- 第一篇 -- 安装和配置PyQt5
我的电脑环境是:Win10 + Python3.6.4 + JetBrains PyCharm 2017.3.2 x64 之前用tkinter写界面,现在学习如何用PyQt5写界面. 安装PyQt5: ...
- TCP通信简单梳理
一.什么是TCP协议 TCP协议是一种面向连接的可靠的通信协议,最重要的两个特点:连接.可靠. 二.TCP是如何进行通信的 TCP通过三次握手建立连接后客户端服务端的内核都分别开辟资源,这时候开始进行 ...
- sql select 1 和 exists
SELECT * FROM LACOMMISION WHERE MANAGECOM LIKE'8694%' AND STATE='1' AND EXISTS(SELECT 1 FROM laagent ...
- 不想用Spring全家桶?试试这个国产JFinal框架
前言 逃离北上广从广州回老家南宁,入职这家公司用的技术是JFinal,借此机会得以学习这个国产的MVC框架,经过一段时间的学习,基于之前的经验搭建一个通用项目jfinal-demo jfinal-de ...
- Aging Cell两篇连发 | 华中科技大学王建枝团队运用蛋白质组学技术发现具有AD早期诊断价值的血小板生物标志物
阿尔茨海默症 (Alzheimer 's disease,AD) 是一种原发性的中枢神经系统退行性疾病.AD的主要临床症状是缓慢的认知功能减退,包括记忆.逻辑推理能力和语言功能的进行性丟失,最后发展为 ...
- 【NLP学习其五】模型保存与载入的注意事项(记问题No module named 'model')
这是一次由于路径问题(找不到模型)引出模型保存问题的记录 最近,我试着把使用GPU训练完成的模型部署至预发布环境时出现了一个错误,以下是log节选 unpickler.load() ModuleNot ...
- 【LeetCode】860. 柠檬水找零
860. 柠檬水找零 知识点:贪心 题目描述 在柠檬水摊上,每一杯柠檬水的售价为 5 美元. 顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯. 每位顾客只买一杯柠檬水,然后向你付 ...