如何动态的生成某种类型的集合呢_知乎画报」的移动端动态化工程实践

本文基于移动端动态化方案在知乎原生推广落地页「知乎画报」上的实践经验,对该方案技术升级过程中的思考以及技术关键细节做了详尽的解读。
商业化是互联网公司发展的重要阶段,App 端的商业广告业务对移动端动态化能力的需求很强烈,一方面需要灵活的样式调整和 AB 实验提升广告 CTR;另一方面提升功能的上线效率,新的产品功能可以快速的触达用户。基于此商业移动端团队从 2018 年 Q2 开始搭建动态化基础能力,逐步实现了 App 内各个位置广告卡片的动态化开发和上线(为了便于沟通和描述,我们给这个方案起了个比较「动态」的名字:Morph)。
广告推广落地页「Landing Page」是商业化广告的重要组成部分。做商业化广告的同学可能都处理过落地页优化的问题,「落地页打开速度」、「落地页到达率」、「落地页转化效果」几个指标的提升始终是 App 端落地页体验优化的重要挑战。
为解决上述业务痛点,提供更好的客户体验, 2018 年末商业产品提出在知乎 App 中支持原生推广落地页——「知乎画报」的业务需求,落地页内可使用图片、文字、视频等富媒体形式承载原生内容。此时动态化基础能力(Morph)已经基本成熟,对于当时提出的业务需要,我们自然而然的想到了复用 Morph 方案,同时在其基础能力上进行技术升级,将原有的信息流广告动态化扩展为全面的广告动态化。


从业务角度分析,不同于信息流广告卡片入口,落地页作为广告主体内容的承载容器,在呈现方式上更加开放,内容也更丰富;同时,用户对于广告内容的浏览与操作,广告主对于广告效果的获知、转化信息的采集,也都需要依托广告内容落地页来实现。在此过程中,相比于目前第三方 H5 落地页,采用原生落地页在工程能力上需要有如下提升:
1. 「加载速度更快,到达率接近 100%」。「到达率」在这里特指用户点击广告卡片到落地页完全加载的比例,是衡量落地页性能的重要指标。H5 落地页加载速度缓慢,「加载菊花」常常被人诟病,在网络不稳定或服务器异常的情况下有很大几率会导致页面加载缓慢甚至加载失败。除了严重影响用户体验之外,也极大的降低了广告转化率,对广告资源造成浪费;
2. 「支持预加载,实现秒开」。在第三方 H5 落地页,很难进行可靠的内容预加载。第三方服务器性能不一,性能较差的服务器很难承载大规模页面访问带来的服务压力;
3. 「转化信息的全面采集,用户体验升级」。对于很多广告主来说,由于没有自建站平台,只能使用第三方建站平台生成网页,显示效果参差不齐,内容质量难以把控,甚至相关数据的统计与分析也不得不依赖第三方平台,无论是数据准确程度还是学习成本都难以令人满意。对此,新方案在提供全面的转化信息同时,需要提供更低的学习成本与更好的用户使用体验;
4. 「支持样式实验,转化效果可提升」。和广告卡片提升 CTR 一样,通过进行落地页样式实验可以有效并持续地提升转化效果。
因此,对于原生推广落地页的动态化能力升级,成为了整个动态化进程中不可或缺的一环。(同样,为了便于沟通和描述,我们给这个方案起了个名字:Canvas)。
下面从「技术升级选型」、「知乎画报业务流程」、「技术实现细节」三个方面介绍一下此次技术方案改造升级。
扫描下方广告预览小程序码,可以交互式查看本文介绍的「知乎画报」原生推广落地页的效果。

df9c7a0776c57db5653c355ae55ed92d.png
「知乎画报」原生推广落地页预览

有哪些技术选型上的升级,如何考量的?
移动端已实现的动态化基础能力(Morph)主要面向信息流广告卡片的展现,基于 Flexbox 布局编写的样式文件集合保存在云端样式数据库,通过独立的样式服务接口下发。信息流广告数据下发时会根据 App 本地已支持的样式文件子集匹配下发可展示的广告数据,App 端解析样式文件,绑定数据最终呈现广告卡片。
Morph 方案实现中进行了一系列的技术考量,在 Canvas 中针对「布局解析系统」和「样式文件」进行了改造升级,其他部分就不在本文中展开讨论了。
升级布局解析系统,匹配落地页的复杂场景
Morph 方案中从信息流场景出发,iOS 布局解析和视图渲染均基于 ComponentKit 实现,Android 布局解析则基于 google/flexbox-layout 实现,视图渲染基于系统原生控件。Canvas 落地页场景中,页面样式会更加复杂多变,同时需要容纳更丰富的、定制程度高的控件。因此在视图渲染上,直接使用系统原生方案是比较合适的选择。
Android 端布局解析框架 google/flexbox-layout 可以兼容系统原生控件,已满足升级要求。iOS 端既然选择了使用原生 UIKit 框架,那么我们在选择 Flexbox 解析方案时,可以只关注于 Flexbox 布局约束的实现,而无需要求第三方库对基础属性,例如背景颜色的支持。 尤其是想要在较短时间内实现对整体页面约束布局设置,学习成本不宜过高。同时,包体积是知乎 App 特别关注的基础体验,也需要考虑在内。

67c2375e659e21b376f7ccd27488fe0c.png

综合考虑以上几点,我们选择了更轻量级、业务吻合度更高的 YogaKit。
样式文件拆分,支持云端自定义视图布局
样式文件是云端控制 App 端样式展现的关键纽带。在 Morph 中,广告卡片的样式文件是由工程师预先编写,由使用方(广告主)选择后下发到 App 端,换句话说,Morph 的布局能力在广告卡片样式文件生成的时候就确定了。Canvas 在 Morph 的基础上将样式的布局能力进一步暴露给使用方,支持对落地页布局的个性化定制。
因此,与 Morph 中所有样式都写在同一个样式文件中不同,Canvas 样式文件分为:基础组件样式文件(基础样式)和布局样式文件(壳样式)。

  • 基础样式

与 Morph 不同之处在于:基础样式不是最终的样式,只是落地页视图中基础组件的样式,需要结合壳样式共同生效;沿用 Morph 中的样式服务接口单独下发;每个基础样式都有默认样式属性值,会被壳样式中的属性覆盖。

  • 壳样式

落地页的最终样式结构,像「壳」一样将基础样式包裹起来;决定落地页的视图布局,随广告数据下发;支持对基础样式属性进行覆盖更改。


「知乎画报」的业务流程设计
从用户视角上看,「知乎画报」的总体业务流程如下图:

3787addc675ba34a716f8fab4a811c61.png

总体流程下可以分为两个子流程:一、基础样式下发流程

  1. 基础样式存储在云端基础样式数据库
  2. App 启动时,从样式服务获取当前版本的最新基础样式集合;
  3. 数据校验通过后,存入本地基础样式数据库

二、落地页样式展现流程

  1. 以信息流为例,用户刷新信息流展现广告卡片,广告数据中包含了对应的落地页壳样式信息;
  2. 与基础样式数据合并解析,绑定数据,生成最终的样式信息;
  3. 根据样式信息,在用户浏览信息流时预先渲染原生落地页;
  4. 点击广告卡片,展现原生落地页。

同时,Canvas 与广告实验系统深度结合,支持对落地页样式进行细粒度的 AB 测试实验和数据收集,用于 CTR、CVR 提升实验。
下面我们来看一下为了实现上述业务流程,各参与角色做了哪些事情。
广告主需要做什么
广告业务前端为广告主提供专门的落地页建站工具平台。广告主在该平台将已支持的云端基础样式数据库中的基础组件,按照自己的需求进行简单的选择、拼接,组合成完整的落地页样式。然后上传对应的广告素材即可,操作过程非常简单。具体介绍可访问:这里。

a04223fefd4790784f8456869c969398.png

后端做了什么
业务前端将制作好的页面解析生成 App 端可理解的壳样式数据,与广告素材关联后同步存储到广告业务数据库。当 App 端请求广告数据时,广告引擎根据 App 基本信息进行匹配,将满足条件的落地页壳样式数据封装在广告数据中一并下发。
App 端做了什么
App 在安装时会自带一个预埋了最新基础组件样式的本地基础样式数据库,如果云端更新了基础组件样式,可以通过样式服务进行更新。当用户刷新页面并请求到新的广告数据后,取出随广告同时下发的壳样式数据,与之前存储在本地的基础样式合并,生成落地页视图。(样式合并的细节将在后文详述。)
特别的,App 在广告卡片展现的同时,会提前预渲染广告落地页视图,在点击广告之后,落地页打开过程中不需要再次等待页面生成,实现秒开显示,提升落地页到达率。
相比于 H5 落地页对于 App 的黑盒,用户在落地页内的操作均属于对原生控件操作,浏览、填写信息、点击等行为均可收集用于支持 CVR 提升、oCPC 等工作。

6572ad6a315372e957c5131f645e7cb5.png

有哪些值得关注的技术细节?
通过上文的叙述,我们已经对 Canvas 的技术基础和「知乎画报」的业务有了比较完整的认识。在 Canvas 动态化方案技术升级的过程中,移动端研发解决了很多工程设计和实现的问题,积累了宝贵的经验,接下来就把我们认为值得关注的技术细节做一个分享。
基础样式文件与基础组件生成
Canvas 广告落地页中,目前支持的所有组件类型包括:文本、图片、视频、勾选框、文字选择控件、图片选择控件、表单,其中表单内子组件包括文字输入框、下拉选择框。此外,还有两个容器组件:场景和分页。

519e1b560697f366386319fe4ebe5bb2.png
基础样式列表

对于每一种基础组件样式,使用单独的样式名称 canvas_style 来标识,每一种样式名称会一一对应到字段 type 表明该样式所使用的控件类型。因此当 App 端获取到壳样式文件后,通过壳样式中每个元素的样式名称,在数据库中查找到对应的控件类型,从而决定使用哪种基础样式及原生控件进行承载。以 iOS 为例,控件类型映射示意如下:

7363e44585d5c6f1c350cfb673a6f9a3.png

基础样式文件的数据存储分为两个部分:

  • 云端基础样式数据库

基础样式以 JSON 的形式,与其对应的 Canvas 版本、客户端版本一并存储到云端数据库中。

  • 本地基础样式数据库

App 启动时,访问样式服务接口,样式服务根据请求 Header 中的: App 平台、App 版本、 Canvas 版本,以及 App 端现有基础样式及版本信息集合,增量下发基础样式数据;
App 接收到新的基础样式数据后,会依次进行:Hash 校验、JSON 格式校验、实验信息的校验,校验通过后将接收到新的基础样式更新到本地数据库,同时进行对旧版本样式数据进行清理删除。
此外,为减小数据传输量,App 新版本发布时,会将已支持的基础样式数据预埋在数据库中。
最终生成的「知乎画报」页面与基础样式组件的对应关系如下图所示:

71745b889e31106cab8f1a88db00b2fe.png

壳样式文件与样式合并
在上文的介绍中我们已经接触过基础样式和壳样式的概念。布局样式(即壳样式)随广告数据一起下发,和基础样式一起决定了落地页展现的最终样式。

c77b36f7d08f5e96164162a375e3537b.png

对于一个控件来说,相关属性是通过样式模型进行配置的。本地基础样式数据库存储了每个组件最新的默认样式,在客户端收到随广告数据一起下发的壳样式数据后,会将服务器传回的壳样式数据与本地基础样式数据进行对比合并,最终形成包含了各组件相关属性配置、视图层级设置,以及 layout 约束设置的样式模型。
样式合并的过程示意如下:

9cba449c6239f8e2064ff921697b494d.png

在样式的合并过程中,遵循以下几点规则

  • 如果某个属性值,壳样式中没有设置而基础样式中有,则以基础样式中的值为准;
  • 如果某个属性值,壳样式中和基础样式中都有设置,则以壳样式中的值为准;
  • 如果样式中某个组件包含子组件,则依次遍历其中的每个子组件,对其执行该合并过程。

下图中我们将一个本地基础样式属性和壳样式属性合并成了最终样式模型:

ea5546efdf2fc0834bd764042ac92a45.png

整页布局与翻页处理
一个广告落地页的完整显示内容通常会包含图片、文字、表单等多种元素,很多场景下广告落地页全部显示内容会超过一屏。
上文中我们介绍过容器组件场景和分页。在 Canvas 落地页的视图层级中,最底层为一个总视图容器 canvas_scene,用来承载整个落地页内容, canvas_scene 中包含了至少一个 canvas_page,canvas_page 中包含一个 scrollView 视图,支持页面内组件的滚动展示。
canvas_page 的 Flex 布局规则如下:
Page { display: flex; flex-direction: column; justify-content: flex-start; align-items: center; }
canvas_page 支持两种整页布局方式,使用者可以根据具体诉求选择其一进行页面内容展示:

  1. 滑动布局:使用一个不分割的完整长页面,如下图 page one 所示;
  2. 翻页布局:使用多屏页面进行翻页显示,如下图 page two 所示。

c581f992b51f46c5656c3fb119fc52ad.png
  • 滑动布局方式

如果广告主选择只使用一个 canvas_page 来显示内容,canvas_page 生成过程中,会循环遍历其中包含的所有子组件,对其进行数据绑定及约束设置,然后根据所有子组件的约束设置来适配自身包含的滑动视图的内容尺寸大小。以 iOS 为例,在 canvas_page 中包含了一个 UIScrollView,因此在计算出所有子组件约束后,将 scrollView 的 contentSize 设置成完整包括了所有子组件的容器的 size。这样,在这个页面上就可以通过上下滑动来浏览完整内容。

  • 翻页布局方式

既然是「翻页」,也就代表底层容器中会包含多个 canvas_page,而每一个 canvas_page 的大小,可以等于或大于屏幕尺寸。(为了适配设备屏幕高度我们规定:页面内容大于一屏的情况下,分页组件根据内容高度自适应;当页面内容不足一屏时,按照一屏的高度展示,底部留白)。
在翻页方式布局中,当用户在滑动过程中即将切换到下一页时,会有一个 bounce 弹性动画来提示切换到下一页。

  • 如何选择两种布局方式

通常对于广告主建站过程来说,如果所有落地页内容为一个整体,则建议使用滑动布局的方式将所有内容放置在同一页中;而如果整个内容分为数个部分,则可以分别将每个部分设置为一页,然后进行多页组合。
Canvas 的版本控制
从业务发展的角度来说,落地页中展示的组件不可能一次性全部支持,而是在业务迭代中对 Canvas 的基础样式集合进行动态更新和扩展的。因此,不同时期新增的组件,会对应不同的版本支持。一条广告数据也必须通过版本控制以确保下发到满足落地页展示条件的用户端。
Canvas 的版本规则可以分为三个部分来解释:

  • 基础组件支持的 Canvas 版本

每个 Canvas 基础组件都会对应一个 Canvas 版本号(canvas_version),这个版本号写在基础样式云端数据库中,每当一个 Canvas 基础组件发生不向下兼容的修改时,提升对应的 canvas_version 。因此,一个基础组件在基础样式云端数据库可能有多条记录,对应多个 canvas_version。

fd70c1db43f2818fbb6b7420c726798d.png
  • Canvas 版本兼容的最低 App 版本

每个 canvas_version 版本都会对应一个最低 App 版本,样式服务接口调用时,对于每个基础样式组件,会选择⽀持当前客户端版本的最新一条基础样式数据记录下发到 App。

9db0d408e00e1457daa6ff0fffdca117.png
  • 当前 App 支持的 Canvas 版本

用户手机上的 App 以当前预埋或已下发的所有基础样式中,最高的 canvas_version 最为当前 App 支持的 canvas_version。调用广告数据下发接口时,广告引擎端选取落地页壳样式中调用的基础组件 canvas_version 小于等于 App 支持的 canvas_version 的广告数据下发。
其他技术细节

  • 数据绑定

基础样式的主要功能是设置视图显示约束,是与广告内容数据完全独立的存在,其中只包含了与视图显示属性相关的设置,而没有添加真正要显示的内容。因此在壳样式中,还需要进行显示数据的绑定。
数据绑定部分的逻辑沿用了 Morph 的数据绑定方案:

  1. 数据体节点的占位符使用 <? 作为开始标识,?> 作为结束标识,数组直接使用数字下标指定其具体位置;例如:<?ads.0.creatives.asset.brand_name?>
  2. App 在数据绑定时,直接与广告 JSON 数据中的字段映射,无需经过 Native Model 解析,实现 数据 Model 动态化。因此上述数据占位符对应的 JSON 数据子结构为:ads[0].creatives.asset.brand_name
  • 事件处理与控件联动

Morph 方案中的事件处理都包含在 action 字段中,如果有需要额外添加的参数,可以添加在 extra 参数上。
Canvas 落地页在此处沿用了 Morph 的结构,但是在不同组件之间的事件联动上做了升级。以表单组件为例:
部分表单信息支持用户授权后由系统自动填充,当用户勾选授权框时,需要在表单输入框中自动填充相关信息。实现过程要保证两个关键点:
1. 确保在页面中能够获取到联动的组件。一种可行的办法是设置局部唯一标识,添加 stringTag 标签的方式对控件进行「标记」,接收到的壳样式数据中指定需要联动的控件标识;
2. 确保事件能够进行正确完整的传递。当某一控件接收到点击事件时,将这个点击事件消息通过广播出来,监听了这一消息的组件会对事件进行响应。

  • 转场动画的实现

对于一个广告落地页来说,「显示什么」固然是很重要的,而除此之外,「怎么显示」也是一门学问。尤其对于原生广告落地页,要想做到「提升用户体验」,酷炫且恰当的转场动画不失为一个讨巧的选择。Canvas 原生落地页从广告卡片为起点,最终展示为全屏页面。因此,我们选择了一种「卡片展开式」的转场动画作为页面过渡方式。
具体的实现方式是:在用户点击广告卡片时,获取到当前卡片相对于整个手机屏幕的位置坐标,并将该位置作为广告落地页的初始坐标和初始大小,落地页的最终位置坐标以及尺寸则等于手机屏幕。因此能够执行一个从起始位置到最终位置的展开动画。与此同时,在广告卡片当前位置覆盖一个与卡片样式完全一样的截图并执行缩小动画,从初始卡片位置向中心缩小直到消失,就得到了视频中的演示效果。

8e74ae8b130fdef40e33a40b6a69e289.png


因为 Canvas 落地页是预渲染的,在执行动画过程中,不需要额外考虑页面的生成及生命周期。落地页的展开动画与卡片的缩小消失动画同时执行,也让原本枯燥的广告页面打开过程显得耳目一新。
写在最后Canvas 动态化能力升级 是一次很有意义的移动端动态化方案实践,通过这次升级不仅将基于页面组件的动态化能力打造的更加完善,覆盖更全面的应用场景;也很好的满足了「知乎画报」的业务要求,用户体验大幅提升。
落地页预渲染后实现秒开,到达率基本达到 100%,同时,相比于 H5 落地页对于 App 的黑盒,用户在落地页内的操作均属于对原生控件操作,转化打点追踪更加准确,能够细化到广告创意粒度,更好的支撑 CVR 提升、oCPC 等工作的开展。
我们的动态化方案开发人员不多,现有系统功能和技术方案一定还有很多不足之处,欢迎对移动端动态化方案感兴趣的同学在文章评论区一起交流分享知识、经验、见解。后续我们还会对动态化方案的基础能力建设部分进行更多的介绍,最新的动态化方案相关技术文章会在知乎技术专栏和预览小程序的「资讯」页面持续更新。

df9c7a0776c57db5653c355ae55ed92d.png

本文作者: @于鹏洋 @纸西 @二二三三 @于天航

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/305292.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

任正非致歉华为前程序员:回来吧,公司错了

近几日&#xff0c;因着任正非连续签发邮件&#xff0c;无处不在热议华为&#xff0c;其中与所有的技术人可谓密切相关。除了一员工因说真话&#xff0c;被晋升两级&#xff0c;根据其自愿选择工作岗位及地点&#xff0c;并由无线网络产品线总裁邓泰华保护其不受打击报复之外&a…

Asp.Net Core之Identity应用(下篇)

一、前言在上篇中简单介绍了 Asp.Net Core 自带的 Identity,一个负责对用户的身份进行认证的框架&#xff0c;当我们按需选择这个框架作为管理和存储我们应用中的用户账号数据的时候&#xff0c;就会添加到自己的项目当中去。这个时候&#xff0c;默认情况我们会使用自带的数据…

如果每一种语言都对应一种女生,你会喜欢哪一个?

这几天调试都很顺利&#xff0c;今天很意外的不要加班&#xff0c;哥几个看着窗外还是白天&#xff0c;还有点不适应。没想到哥几个突然开始YY&#xff1a;如果每种语言都对应一种女生&#xff0c;你会喜欢哪一个&#xff1f;程序猿寂寞起来&#xff0c;我自己都害怕。碍于人数…

asp.net core安全事项(下)

越权越权是非常严重的安全漏洞&#xff0c;通常状态是开发人员对请求的限制逻辑不严格导致的。如果系统中有角色的概念&#xff0c;越权可能出现不同角色间的越权和同角色间的越权。相同角色&#xff1a;A用户&#xff0c;B用户是相同的角色。A用户和B用户都可以调用 /photo/{i…

[导入]php 安全基础 第八章 共享主机 文件系统浏览

8.4. 文件系统浏览 除了能在共享服务器上读取任意文件之外&#xff0c;攻击者还能建立一个可以浏览文件系统的脚本。由于你的大多数敏感文件不会保存在网站主目录下&#xff0c;此类脚本一般用于找到你的源文件的所在位置。请看下例&#xff1a; <pre> <?php if (iss…

程序员的项目周期(表情包版)

0. 需求审评会议进行中1. 开发阶段进行中….2. 代码复查阶段3. 测试阶段….4. 需求突然要改….5. 项目上线

[导入]php 安全基础 附录B. 函数

附录B. 函数 在我写作本书的时候&#xff0c;http://php.net/quickref.php列出了共3917个函数&#xff0c;其中包括一些类似函数的语法结构&#xff0c;在此我不准备把它们从函数中区分开来&#xff0c;而是把它作为函数看待。 由于函数数量很大&#xff0c;一一说明它们的正确…

6段Python代码刻画深度学习历史:从最小二乘法到深度神经网络

最小二乘法深度学习的一切都起源于这个数学片段&#xff08;我把它用Python 写了出来&#xff09;&#xff1a;这一方法是 1805 年巴黎数学家阿德利昂玛利埃勒让德首次提出的&#xff08;1805&#xff0c;Legendre&#xff09;&#xff0c;勒让德建立了许多重要的定理&#xff…

win7美化_Potplayer64位美化版,无棒子的tv推送

potplayer 64位是一款视频播放器&#xff0c;potplayer 64位目前正在新功能全力开发中&#xff0c;由于采用delphi编译程序kmplayer的一些弊端&#xff0c;姜龙喜先生为改进播放器本身的一些性能而重新用vc进行构架&#xff0c;有需要的伙伴们可以移步简易下载站获取&#xff0…

如何在 C# 8 中使用 Channels

在面对 生产者-消费者 的场景下&#xff0c; netcore 提供了一个新的命名空间 System.Threading.Channels 来帮助我们更高效的处理此类问题&#xff0c;有了这个 Channels 存在, 生产者 和 消费者 可以各自处理自己的任务而不相互干扰&#xff0c;有利于两方的并发处理&#x…

mockito mock void方法_使用 Junit + Mockito 实践单元测试!

一、前言相信做过开发的同学&#xff0c;都多多少少写过下面的代码&#xff0c;很长一段时间我一直以为这就是单元测试...SpringBootTestRunWith(SpringRunner.class)public class UnitTest1 {Autowiredprivate UnitService unitService;Testpublic void test() {System.out.pr…

人为什么会出轨?麻省理工学院告诉你:男女配对的真相

该实验出自麻省理工学院著名经济学家Dan Ariely的《The Upside of Irrationality》。结果很有趣&#xff0c;在我们的生活中也尤为常见。实验人员找来100位正值青春年华的大学生&#xff0c;男女各半。然后制作了100张卡片&#xff0c;卡片上写了从1到100总共一百个数字。单数的…

当 .NET 5 遇上OpenTelemetry,会碰撞出怎样的火花?

OpenTelemetry 介绍我在之前的几篇文章都介绍了 OpenTelemetry, 你可以在这里找到OpenTelemetry - 云原生下可观测性的新标准深入研究.NET 5的开放式遥测OpenTelemetry是谷歌和微软共同推进的云原生监控的新规范&#xff0c; 兼容OpenTracing和OpenCensusOpenTelemetry的终极目…

kotlin中mainactivity无法直接调用xml中的控件_使用52North 客户端接口调用OGC WPS服务...

52North是一个来自研究机构、工业界和公共行政管理界的研究者组成的开放国际合作组织&#xff0c;他们通过协作研发流程促进地理信息学创新。具体来说他们开发新的地理信息概念和技术&#xff0c;例如用于管理时空测量数据&#xff0c;以及通过网络共享地理处理技术。他们评估新…

明天放假,我放价!一个国庆假期教你学会数学建模

原价298元&#xff0c;国庆放价&#xff01;248元即可报名学习&#xff01;数学建模涉及的内容比较广泛&#xff0c;比如碎纸片问题中所涉及的图像识别及神经网络、小区开放问题中所涉及的车流模拟仿真、还有“互联网”时代的出租车资源配置中所涉及的运筹调度。或许数学建模的…

微软开源可扩展存储引擎Extensible Storage Engine

喜欢就关注我们吧&#xff01;昨日&#xff0c;微软副总裁 Scott Van Vliet 在推特上表示&#xff0c;可扩展存储引擎 Extensible Storage Engine&#xff08;ESE&#xff09;现已开源。可扩展存储引擎 Extensible Storage Engine&#xff08;ESE&#xff0c;也称 JET Blue&…

.NET应用程序中异步调用Web Service的几种方法 come from: veryhappy(wx.net)

测试程序界面 图一&#xff0c;调用前界面 图二&#xff0c;调用后界面 详细代码实现 闲言少叙&#xff0c;直接进入主题吧。首先一个声明一个类&#xff08;将来在客户端与服务器间传递&#xff09;&#xff1a; public classClass1 { private int _ID; priv…

完美国际真数苹果_如果给你推荐一款很贵,但好用的苹果手机壳,你会买吗?...

【引言】说到全球最热门的手机&#xff0c;大家都知道一定是iPhone啦&#xff0c;作为系统和功能整合得最优秀的手机&#xff0c;不足的地方也非常明显&#xff0c;比如外壳不耐剐蹭&#xff0c;维修成本很高......&#xff0c;所以大多数果粉都会选择保护壳或者贴膜来保护自己…

使用缓存防击穿,解决微信”被动回复用户消息”重试回复问题

背景做微信公众号开发的时候&#xff0c;其中有个接收普通消息、接收事件推送 API。有这么条规则&#xff0c; ”微信服务器在五秒内收不到响应会断掉连接&#xff0c;并且重新发起请求&#xff0c;总共重试三次。假如服务器无法保证在五秒内处理并回复&#xff0c;可以直接回…