华为HarmonyOS打造开放、合规的广告生态 - 贴片广告

场景介绍

贴片广告是一种在视频播放前、视频播放中或视频播放结束后插入的视频或图片广告。

接口说明

接口名

描述

loadAd(adParam: AdRequestParams, adOptions: AdOptions, listener: AdLoadListener): void

请求单广告位广告,通过AdRequestParams、AdOptions进行广告请求参数设置,通过AdLoadListener监听广告请求回调。

AdComponent(ads: advertising.Advertisement[], displayOptions: advertising.AdDisplayOptions, interactionListener: advertising.AdInteractionListener, @BuilderParam adRenderer?: () => void): void

展示广告,通过AdDisplayOptions进行广告展示参数设置,通过AdInteractionListener监听广告状态回调。

开发步骤

  1. 获取OAID。

    如果想要为用户更精准的推送广告,可以在请求参数AdRequestParams中添加oaid属性。

    如何获取OAID参见获取OAID信息。

    说明

    使用以下示例中提供的测试广告位必须先获取OAID信息。

  2. 请求单广告位广告。

    需要创建一个AdLoader对象,通过AdLoader的loadAd方法请求广告,最后通过AdLoadListener来监听广告的加载状态。

    在请求贴片广告时,需要在AdOptions中设置两个参数:totalDuration和placementAdCountDownDesc。

    请求广告关键参数如下所示:

    请求广告参数名

    类型

    必填

    说明

    adType

    number

    请求广告类型,贴片广告类型为60。

    adId

    string

    广告位ID。

    • 如果仅调测广告,可使用测试广告位ID:testy3cglm3pj0。
    • 如果要接入正式广告,则需要申请正式的广告位ID。可在应用发布前进入流量变现官网,点击“开始变现”,登录鲸鸿动能媒体服务平台进行申请,具体操作详情请参见展示位创建。

    oaid

    string

    开放匿名设备标识符,用于精准推送广告。不填无法获取到个性化广告。

    示例代码如下所示:
     
    1. import { advertising, identifier } from '@kit.AdsKit';
    2. import { common } from '@kit.AbilityKit';
    3. import { hilog } from '@kit.PerformanceAnalysisKit';
    4. import { BusinessError } from '@kit.BasicServicesKit';
    5. import { router } from '@kit.ArkUI';
    6. @Entry
    7. @Component
    8. struct Index {
    9. private context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
    10. // 获取到的OAID
    11. private oaid: string = '';
    12. aboutToAppear() {
    13. try {
    14. // 使用Promise回调方式获取OAID
    15. identifier.getOAID().then((data: string) => {
    16. this.oaid = data;
    17. hilog.info(0x0000, 'testTag', '%{public}s', 'Succeeded in getting adsIdentifierInfo by promise');
    18. }).catch((error: BusinessError) => {
    19. hilog.error(0x0000, 'testTag', '%{public}s',
    20. `Failed to get adsIdentifierInfo, code: ${error.code}, message: ${error.message}`);
    21. })
    22. } catch (error) {
    23. hilog.error(0x0000, 'testTag', '%{public}s', `Catch err, code: ${error.code}, message: ${error.message}`);
    24. }
    25. }
    26. build() {
    27. Row() {
    28. Button('加载广告', { type: ButtonType.Normal, stateEffect: true })
    29. .onClick(() => {
    30. // 调用加载广告方法
    31. requestAd(this.context, this.oaid);
    32. })
    33. .borderRadius(8)
    34. .backgroundColor(0x317aff)
    35. .width(90)
    36. .height(40)
    37. }
    38. .height('100%')
    39. }
    40. }
    41. /**
    42. * 加载广告
    43. *
    44. * @param context 上下文环境
    45. * @param oaid OAID信息
    46. */
    47. function requestAd(context: common.Context, oaid: string): void {
    48. const adRequestParam: advertising.AdRequestParams = {
    49. // 广告类型
    50. adType: 60,
    51. // 'testy3cglm3pj0'为测试专用的广告位ID,App正式发布时需要改为正式的广告位ID
    52. adId: 'testy3cglm3pj0',
    53. // 在AdRequestParams中添加oaid参数
    54. oaid: oaid,
    55. // 用于区分普通请求和预加载请求,默认值false代表普通请求,true代表预加载请求
    56. isPreload: false
    57. };
    58. const adOptions: advertising.AdOptions = {
    59. // 在AdOptions中添加totalDuration参数,用于设置贴片广告展示时长(贴片广告必填)
    60. totalDuration: 30,
    61. // 在AdOptions中添加placementAdCountDownDesc参数,设置贴片广告倒计时文案(可选,填写了则展示文案,不填写则只展示倒计时)
    62. placementAdCountDownDesc: encodeURI('VIP免广告'),
    63. // 是否允许流量下载 0不允许 1允许,不设置以广告主设置为准
    64. allowMobileTraffic: 0,
    65. // 是否希望根据 COPPA 的规定将您的内容视为面向儿童的内容: -1默认值,不确定 0不希望 1希望
    66. tagForChildProtection: -1,
    67. // 是否希望按适合未达到法定承诺年龄的欧洲经济区 (EEA) 用户的方式处理该广告请求: -1默认值,不确定 0不希望 1希望
    68. tagForUnderAgeOfPromise: -1,
    69. // 设置广告内容分级上限: W: 3+,所有受众 PI: 7+,家长指导 J:12+,青少年 A: 16+/18+,成人受众
    70. adContentClassification: 'A'
    71. };
    72. // 广告请求回调监听
    73. const adLoaderListener: advertising.AdLoadListener = {
    74. // 广告请求失败回调
    75. onAdLoadFailure: (errorCode: number, errorMsg: string) => {
    76. hilog.error(0x0000, 'testTag', '%{public}s',
    77. `Failed to request single ad, errorCode is: ${errorCode}, errorMsg is: ${errorMsg}`);
    78. },
    79. // 广告请求成功回调
    80. onAdLoadSuccess: (ads: Array<advertising.Advertisement>) => {
    81. hilog.info(0x0000, 'testTag', '%{public}s', 'Succeeded in requesting single ad!');
    82. // 保存请求到的广告内容用于展示
    83. const returnAds = ads;
    84. // 路由到广告展示页面
    85. routePage('pages/PlacementAdPage', returnAds);
    86. }
    87. };
    88. // 创建AdLoader广告对象
    89. const load: advertising.AdLoader = new advertising.AdLoader(context);
    90. // 调用广告请求接口
    91. hilog.info(0x0000, 'testTag', '%{public}s', 'Request single ad!');
    92. load.loadAd(adRequestParam, adOptions, adLoaderListener);
    93. }
    94. /**
    95. * 路由跳转
    96. *
    97. * @param pageUri 要路由到的页面
    98. */
    99. async function routePage(pageUri: string, ads: Array<advertising.Advertisement | null>) {
    100. let options: router.RouterOptions = {
    101. url: pageUri,
    102. params: {
    103. ads: ads
    104. }
    105. }
    106. try {
    107. hilog.info(0x0000, 'testTag', '%{public}s', `RoutePage: ${pageUri}`);
    108. router.pushUrl(options);
    109. } catch (error) {
    110. hilog.error(0x0000, 'testTag', '%{public}s',
    111. `Failed to routePage callback, code: ${error.code}, msg: ${error.message}`);
    112. }
    113. }

  3. 展示广告。

    在您的页面中使用AdComponent组件展示贴片广告,由媒体判断流量场景下,可以自动播放则展示广告,反之则不展示。以前贴广告为例,前贴广告播放完成后进入正片播放。您需要在entry/src/main/resources/base/profile/main_pages.json文件中添加页面,如下图所示。

    您需要在media和rawfile目录下分别指定正片未播放时的预览图video_preview.PNG和对应的正片文件videoTest.mp4,如下图所示。

    示例代码如下所示:
     
    1. import { router, window } from '@kit.ArkUI';
    2. import { BusinessError } from '@kit.BasicServicesKit';
    3. import { advertising, AdComponent } from '@kit.AdsKit';
    4. import { hilog } from '@kit.PerformanceAnalysisKit';
    5. @Entry
    6. @Component
    7. export struct PlacementAdPage {
    8. // 是否竖屏
    9. private portrait: boolean = true;
    10. // 请求到的广告内容
    11. private ads: Array<advertising.Advertisement> = [];
    12. // 广告展示参数
    13. private adDisplayOptions: advertising.AdDisplayOptions = {
    14. // 是否静音,默认不静音
    15. mute: false
    16. }
    17. // 广告参数
    18. private adOptions: advertising.AdOptions = {
    19. // 设置贴片广告展示时长(贴片广告必填)
    20. totalDuration: 30,
    21. // 设置贴片广告倒计时文案,文案需要使用encodeURI编码(可选,填写了则展示文案,不填写则只展示倒计时)
    22. placementAdCountDownDesc: encodeURI('VIP免广告'),
    23. // 是否希望根据 COPPA 的规定将您的内容视为面向儿童的内容: -1默认值,不确定 0不希望 1希望
    24. tagForChildProtection: -1,
    25. // 是否希望按适合未达到法定承诺年龄的欧洲经济区 (EEA) 用户的方式处理该广告请求: -1默认值,不确定 0不希望 1希望
    26. tagForUnderAgeOfPromise: -1,
    27. // 设置广告内容分级上限: W: 3+,所有受众 PI: 7+,家长指导 J:12+,青少年 A: 16+/18+,成人受众
    28. adContentClassification: 'A'
    29. }
    30. // 已经播放的贴片广告数量
    31. private playedAdSize: number = 0;
    32. // 是否播放正片
    33. @State isPlayVideo: boolean = false;
    34. // 视频播放控制器
    35. private controller: VideoController = new VideoController();
    36. // 指定视频未播放时的预览图片路径
    37. private previewUris: Resource = $r('app.media.video_preview');
    38. // 指定视频播放源的路径,这里取本地视频资源
    39. private innerResource: Resource = $rawfile('videoTest.mp4');
    40. // 用于渲染右上角倒计时
    41. private countDownTxtPlaceholder: string = '%d | %s';
    42. @State countDownTxt: string = '';
    43. aboutToAppear() {
    44. const params: Record<string, Object> = router.getParams() as Record<string, Object>;
    45. if (params && params.ads as Array<advertising.Advertisement>) {
    46. this.ads = params.ads as Array<advertising.Advertisement>;
    47. this.adOptions = params.adOptions as advertising.AdOptions;
    48. this.initData();
    49. }
    50. }
    51. build() {
    52. Stack({ alignContent: Alignment.TopEnd }) {
    53. // AdComponent组件用于展示非全屏广告
    54. AdComponent({
    55. ads: this.ads, displayOptions: this.adDisplayOptions,
    56. interactionListener: {
    57. // 广告状态变化回调
    58. onStatusChanged: (status: string, ad: advertising.Advertisement, data: string) => {
    59. switch (status) {
    60. case 'onPortrait':
    61. hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onPortrait');
    62. // 设置屏幕方向为竖屏或返回上一页
    63. this.setWindowPortrait();
    64. break;
    65. case 'onLandscape':
    66. hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onLandscape');
    67. // 设置屏幕方向为横屏
    68. this.setWindowLandscape();
    69. break;
    70. case 'onMediaProgress':
    71. hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onMediaProgress');
    72. break;
    73. case 'onMediaStart':
    74. hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onMediaStart');
    75. break;
    76. case 'onMediaPause':
    77. hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onMediaPause');
    78. break;
    79. case 'onMediaStop':
    80. hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onMediaStop');
    81. break;
    82. case 'onMediaComplete':
    83. hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onMediaComplete');
    84. // 所有广告都播放完毕后,开始播放正片
    85. this.playedAdSize++;
    86. if (this.playedAdSize === this.ads.length) {
    87. this.isPlayVideo = true;
    88. }
    89. break;
    90. case 'onMediaError':
    91. hilog.error(0x0000, 'testTag', '%{public}s', 'Status is onMediaError');
    92. break;
    93. case 'onMediaCountdown':
    94. try {
    95. hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onMediaCountdown');
    96. const parseData: Record<string, number> = JSON.parse(JSON.stringify(data));
    97. this.updateCountDownTxt(parseData.countdownTime);
    98. } catch (e) {
    99. hilog.error(0x0000, 'testTag', '%{public}s',
    100. `Failed to parse data, code: ${e.code}, msg: ${e.message}`);
    101. }
    102. break;
    103. }
    104. }
    105. }
    106. })
    107. .visibility(!this.isPlayVideo ? Visibility.Visible : Visibility.None)
    108. .width('100%')
    109. .height('100%')
    110. Row() {
    111. if (this.countDownTxt) {
    112. Text(this.countDownTxt.split('').join('\u200B'))
    113. .fontSize(12)
    114. .textAlign(TextAlign.Center)
    115. .maxLines(1)
    116. .fontColor(Color.White)
    117. .lineHeight(12)
    118. .textOverflow({ overflow: TextOverflow.Ellipsis })
    119. .maxLines(1)
    120. .backgroundColor('#66000000')
    121. .border({ radius: 25 })
    122. .padding({
    123. left: 8,
    124. right: 8,
    125. top: 6,
    126. bottom: 6
    127. })
    128. .margin({ right: 16, top: 16 })
    129. .height(24)
    130. .constraintSize({ minWidth: 60, maxWidth: 100 })
    131. .onClick((event: ClickEvent) => {
    132. hilog.info(0x0000, 'testTag', '%{public}s', 'OnVipClicked, do something...');
    133. })
    134. }
    135. }
    136. .alignItems(VerticalAlign.Top)
    137. .justifyContent(FlexAlign.End)
    138. Video({
    139. src: this.innerResource,
    140. previewUri: this.previewUris,
    141. controller: this.controller
    142. })
    143. .visibility(this.isPlayVideo ? Visibility.Visible : Visibility.None)
    144. .autoPlay(this.isPlayVideo ? true : false)
    145. .controls(false)
    146. .width('100%')
    147. .height('100%')
    148. }.width('100%').height('100%')
    149. }
    150. /**
    151. * 设置竖屏或返回上一页
    152. */
    153. private setWindowPortrait() {
    154. hilog.info(0x0000, 'testTag', '%{public}s', `Set WindowPortrait, portrait: ${this.portrait}`);
    155. if (!this.portrait) {
    156. window.getLastWindow(getContext(this), (err: BusinessError, win) => {
    157. win.setPreferredOrientation(window.Orientation.PORTRAIT)
    158. });
    159. this.portrait = true;
    160. } else {
    161. router.back();
    162. }
    163. }
    164. /**
    165. * 设置横屏(正向)
    166. */
    167. private setWindowLandscape() {
    168. hilog.info(0x0000, 'testTag', '%{public}s', `Set WindowLandscape, portrait: ${this.portrait}`);
    169. if (this.portrait) {
    170. window.getLastWindow(getContext(this), (err: BusinessError, win) => {
    171. win.setPreferredOrientation(window.Orientation.LANDSCAPE)
    172. });
    173. this.portrait = false;
    174. }
    175. }
    176. private initData() {
    177. this.initCountDownText();
    178. }
    179. private initCountDownText() {
    180. const decodeText = this.decodeString(this.adOptions?.placementAdCountDownDesc as string);
    181. if (!this.isBlank(decodeText)) {
    182. this.countDownTxtPlaceholder = this.countDownTxtPlaceholder.replace('%s', decodeText);
    183. } else {
    184. this.countDownTxtPlaceholder = '%d';
    185. }
    186. }
    187. private updateCountDownTxt(leftTime: number) {
    188. hilog.info(0x0000, 'testTag', '%{public}s', `Show LeftTime: ${leftTime}`);
    189. this.countDownTxt = this.countDownTxtPlaceholder.replace('%d', leftTime + '');
    190. }
    191. private decodeString(str: string): string {
    192. if (!str) {
    193. return str;
    194. }
    195. let decodeUrl = str;
    196. try {
    197. decodeUrl = decodeURIComponent(str.replace(/\+/g, '%20'));
    198. } catch (e) {
    199. hilog.error(0x0000, 'testTag', '%{public}s', `Failed to decodeURIComponent, code:${e.code}, msg: ${e.message}`);
    200. }
    201. return decodeUrl;
    202. }
    203. private isBlank(str: string): boolean {
    204. if (str === null || str === undefined) {
    205. return true;
    206. }
    207. if (typeof str === 'string') {
    208. return str.trim().length === 0;
    209. }
    210. return false;
    211. }
    212. }

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

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

相关文章

Leetcode137只出现一次的数字|| 及其拓展

简述&#xff1a; 虽然标题是这么描述的&#xff0c;但是我们不是一上来就解这道题&#xff0c;先看一下他的子题和扩展 子题&#xff1a;136. 只出现一次的数字 - 力扣&#xff08;LeetCode&#xff09; 扩展题&#xff1a; 所以我们由易到难&#xff0c;先来看第一道&#x…

【解决办法】无法使用右键“通过VSCode打开文件夹”

个人博客&#xff1a;苏三有春的博客 前言 作者的编程环境为VScode&#xff0c;工作时常使用VScode打开整个工程文件夹。如果先打开VScode再从VScode中选择文件夹打开效率太慢&#xff0c;作者一般使用的方式是右键文件夹&#xff0c;直接选择"通过code打开文件夹"…

数据揭秘:掌握K-means聚类算法的精髓与实践

数据揭秘&#xff1a;掌握K-means聚类算法的精髓与实践 在机器学习领域&#xff0c;聚类是一种探索性的数据挖掘技术&#xff0c;用于将数据集中的样本划分成若干个簇&#xff0c;使得同一簇内的样本相似度高&#xff0c;而不同簇之间的样本相似度低。本文将深入探讨聚类分析的…

ADNI蛋白质数据集下载

&#xff08;我发现这个网站最近又更新了界面&#xff0c;现在变得很好看很简洁&#xff0c;但是有一些入口变了&#xff09; 1.官网链接 https://ida.loni.usc.edu/home/projectPage.jsp?projectADNI 2.登录 选择ADNI&#xff08;其实PPMI数据也是这样下的&#xff09;&a…

【数据分享】2024年我国省市县三级的生活服务设施数量(46类设施/Excel/Shp格式)

人才市场、售票处、旅行社等生活服务设施的配置情况是一个城市公共基础设施完善程度的重要体现&#xff0c;一个城市生活服务设施种类越丰富&#xff0c;数量越多&#xff0c;通常能表示这个城市的公共服务水平越高&#xff01; 本次我们为大家带来的是我国各省份、各地级市、…

彻底解决idea不识别java项目

需求背景 下载了一个java swing的项目,通过idea导入后,项目无法识别。打开java文件,也不会报错,也不编译。 无法识别效果图 可以看到左侧的菜单,项目是没有被识别。 打开java文件,可以看到没有识别,java的图标也没有出现。 解决方法 1、打开Project Structure 2、修改…

HTMLCSS:打造酷炫下载安装模拟按钮

效果演示 这段代码通过HTML和CSS创建了一个具有交互效果的下载按钮&#xff0c;当复选框被选中时&#xff0c;会触发一系列动画和样式变化&#xff0c;模拟了一个下载和安装的过程&#xff0c;包括圆形的动画、文本的显示和隐藏等。 HTML <div class"container&quo…

Multi Agents协作机制设计及实践

01 多智能体协作机制的背景概述 在前述博客中&#xff0c;我们利用LangChain、AutoGen等开发框架构建了一个数据多智能体的平台&#xff0c;并使用了LangChain的Multi-Agents框架。然而&#xff0c;在实施过程中&#xff0c;我们发现现有的框架存在一些局限性&#xff0c;这些…

ML2001-1 机器学习/深度学习 Introduction of Machine / Deep Learning

图片说明来自李宏毅老师视频的学习笔记&#xff0c;如有侵权&#xff0c;请通知下架 影片参考 【李宏毅】3.第一节 - (上) - 机器学习基本概念简介_哔哩哔哩_bilibili 1. 机器学习的概念与任务类型 概念&#xff1a;机器学习近似于寻找函数&#xff0c;用于处理不同类型的任…

90%会展主办方都会用的6款数字化工具

在会展行业&#xff0c;数字化转型已成为提升竞争力的关键。面对日益增长的运营成本和收入增长的瓶颈&#xff0c;主办方需要借助数字化工具来实现效率提升和成本控制。 今天介绍几种常见的数字化工具和应用方式。 一、线上展览平台 构建线上展览平台是会展主办方拓展线上销…

JMeter快速造数之数据导入导出

导入数据 输入表格格式如下 创建CSV Data Set Config 在Body Data中调用 { "username": "${email}", "password": "123456", "client_id": "00bb9dbfc67439a5d42e0e19f448c7de310df4c7fcde6feb5bd95c6fac5a5afc"…

渗透测试-快速获取目标中存在的漏洞(小白版)

《Java代码审计》http://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247484219&idx1&sn73564e316a4c9794019f15dd6b3ba9f6&chksmc0e47a67f793f371e9f6a4fbc06e7929cb1480b7320fae34c32563307df3a28aca49d1a4addd&scene21#wechat_redirect 《Web安全》h…

[免费]基于Python的Django+Vue3在线考试系统【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的基于Python的DjangoVue3在线考试系统&#xff0c;分享下哈。 项目视频演示 【免费】基于Python的DjangoVue3在线考试系统 Python毕业设计_哔哩哔哩_bilibili 项目介绍 本论文提出并实现了一种基于Python…

Unity3D学习FPS游戏(9)武器音效添加、创建敌人模型和血条

前言&#xff1a;虽然已经实现了基本玩家操作&#xff0c;但是游戏运行起来并没有音效。既然是FPS游戏有了玩家和武器&#xff0c;肯定还得有敌人。本篇演示如何给武器添加音效和创建敌人。 武器音效添加和创建敌人 武器音效添加Audio Source代码控制 创建敌人目标敌人模型敌人…

雷池社区版新版本功能防绕过人机验证解析

前两天&#xff0c;2024.10.31&#xff0c;雷池社区版更新7.1版本&#xff0c;其中有一个功能&#xff0c;新增请求防重放 更新记录&#xff1a;hhttps://docs.waf-ce.chaitin.cn/zh/%E7%89%88%E6%9C%AC%E6%9B%B4%E6%96%B0%E8%AE%B0%E5%BD%95 仔细研究了这个需求&#xff0c;…

PyCharm中pylint安装与使用

目录 1. 安装插件2. pycharm中使用该功能3. 命令行使用 1. 安装插件 然后重启 2. pycharm中使用该功能 3. 命令行使用 前提是先 pip install pylint pylint demo01.py下面红框内容的意思是&#xff0c;得到10分/ 满分10分&#xff0c;上次运行获得8.33分&#xff0c;经调整…

IDEA加载通义灵码插件及使用指南

安装通义灵码插件 登录通义灵码IDE插件 下载登录参考教程 https://help.aliyun.com/zh/lingma/user-guide/download-the-installation-guide 本地工程和企业知识库准备 请下载本地工程和知识库压缩包&#xff0c;并在本地解压缩&#xff0c;其中包含demoProject和知识库文件…

只因把 https 改成 http,带宽减少了 70%!

起因 是一个高并发的采集服务上线后&#xff0c;100m的上行很快就被打满了。因为这是一条专线&#xff0c;并且只有这一个服务在使用&#xff0c;所以可以确定就是它导致的。 但是&#xff01;这个请求只是一个 GET 请求&#xff0c;同时并没有很大的请求体&#xff0c;这是为…

黑马官网最新2024前端就业课V8.5笔记---CSS篇(2)

盒子模型 画盒子 目标:使用合适的选择器画盒子 属性 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"view…

认识单双链表

认识单双链表 前置知识&#xff1a;无&#xff0c;会的可以直接跳过。 基本概念 内存空间是所有程序的公共资源&#xff0c;在一个复杂的系统运行环境下&#xff0c;空闲的内存空间可能散落在内存各处。我们知道&#xff0c;存储数组的内存空间必须是连续的&#xff0c;而当…