android开发与架构设计课件

上传人:文**** 文档编号:240743928 上传时间:2024-05-04 格式:PPT 页数:93 大小:2.49MB
返回 下载 相关 举报
android开发与架构设计课件_第1页
第1页 / 共93页
android开发与架构设计课件_第2页
第2页 / 共93页
android开发与架构设计课件_第3页
第3页 / 共93页
点击查看更多>>
资源描述
androidandroidandroidandroid开发与架构设计开发与架构设计开发与架构设计开发与架构设计1架构1、架构图直观2、架构详解2.1、2.1、2.3、2.4、2.5、21、架构图直观、架构图直观 32、架构详解、架构详解 2.1、基于基于 2.6提供核心系统服务,例如:安全、内存管理、进程管理、网络堆栈、驱提供核心系统服务,例如:安全、内存管理、进程管理、网络堆栈、驱动模型。动模型。也作为硬件和软件之间的抽象层,它隐藏具体硬件细节而为上层提供统一的服也作为硬件和软件之间的抽象层,它隐藏具体硬件细节而为上层提供统一的服务。务。知道,便知道分层的好处就是使用下层提供的服务而为上层提供统一的服务,屏知道,便知道分层的好处就是使用下层提供的服务而为上层提供统一的服务,屏蔽本层及以下层的差异,当本层及以下层发生了变化不会影响到上层。也就是说各层各蔽本层及以下层的差异,当本层及以下层发生了变化不会影响到上层。也就是说各层各司其职,各层提供固定的(司其职,各层提供固定的(),专业点可以说是高内专业点可以说是高内 聚、低耦合。聚、低耦合。42.2、包含一个核心库的集合,提供大部分在编程语言核心类库中可用的功能。每一包含一个核心库的集合,提供大部分在编程语言核心类库中可用的功能。每一个应用程序是虚拟机中的实例,运行在他们自己的进程中。虚拟机设计成,在一个设个应用程序是虚拟机中的实例,运行在他们自己的进程中。虚拟机设计成,在一个设备可以高效地运行多个虚拟机。虚拟机可执行文件格式是,格式是专为设计的一种压备可以高效地运行多个虚拟机。虚拟机可执行文件格式是,格式是专为设计的一种压缩格式,适合内存和处理器速度有限的系统。缩格式,适合内存和处理器速度有限的系统。大多数虚拟机包括都是基于栈的,而虚拟机则是基于寄存器的。两种架构各有优大多数虚拟机包括都是基于栈的,而虚拟机则是基于寄存器的。两种架构各有优劣,一般而言,基于栈的机器需要更多指令,而基于寄存器的机器指令更大。劣,一般而言,基于栈的机器需要更多指令,而基于寄存器的机器指令更大。是一套是一套工具,可以將工具,可以將 转换成转换成 格式。一个文件通常会有多个。由于有時必须进行最佳化,格式。一个文件通常会有多个。由于有時必须进行最佳化,会使文件大小增加会使文件大小增加1-4倍,以结尾。倍,以结尾。虚拟机依赖于虚拟机依赖于 内核提供基本功能内核提供基本功能,如线程和底层内存管理。如线程和底层内存管理。52.3、包含一个库的集合,供系统的各个组件使用。这些功能通过的应用程序框架(包含一个库的集合,供系统的各个组件使用。这些功能通过的应用程序框架()暴露)暴露给开发者。下面列出一些核心库:给开发者。下面列出一些核心库:系统系统C库库标准标准C系统库()的衍生,调整为基于嵌入式设备系统库()的衍生,调整为基于嵌入式设备 媒体库媒体库基于的。这些库支持播放和录制许多流行的音频和视频格式,以及静态图像文件,包基于的。这些库支持播放和录制许多流行的音频和视频格式,以及静态图像文件,包括括4、H.264、3、界面管理界面管理管理访问显示子系统和无缝组合多个应用程序的二维和三维图形层管理访问显示子系统和无缝组合多个应用程序的二维和三维图形层 新式的浏览器引擎新式的浏览器引擎,驱动驱动 浏览器和内嵌的视图浏览器和内嵌的视图 基本的基本的2D图形引擎图形引擎 3D库库基于基于 1.0 的实现。库使用硬件的实现。库使用硬件3D加速或包含高度优化的加速或包含高度优化的3D软件光栅软件光栅 位图和矢量字体渲染位图和矢量字体渲染 所有应用程序都可以使用的强大而轻量级的关系数据库引擎所有应用程序都可以使用的强大而轻量级的关系数据库引擎 62.4、通过提供开放的开发平台,使开发者能够编制极其丰富和新颖的应用程序。开发者可以自由通过提供开放的开发平台,使开发者能够编制极其丰富和新颖的应用程序。开发者可以自由地利用设备硬件优势、访问位置信息、运行后台服务、设置闹钟、向状态栏添加通知等等,地利用设备硬件优势、访问位置信息、运行后台服务、设置闹钟、向状态栏添加通知等等,很多很多。很多很多。开发者可以完全使用核心应用程序所使用的框架。应用程序的体系结构旨在简化组件的重用,开发者可以完全使用核心应用程序所使用的框架。应用程序的体系结构旨在简化组件的重用,任何应用程序都能发布他的功能且任何其他应用程序可以使用这些功能(需要服从框架执行任何应用程序都能发布他的功能且任何其他应用程序可以使用这些功能(需要服从框架执行的安全限制)。这一机制允许用户替换组件。的安全限制)。这一机制允许用户替换组件。所有的应用程序其实是一组服务和系统,包括:所有的应用程序其实是一组服务和系统,包括:视图()视图()丰富的、可扩展的视图集合,可用于构建一个应用程序。包括包括列表、网格、丰富的、可扩展的视图集合,可用于构建一个应用程序。包括包括列表、网格、文本框、按钮,甚至是内嵌的网页浏览器文本框、按钮,甚至是内嵌的网页浏览器 内容提供者(内容提供者()使应用程序能访问其他应用程序(如通讯录)的数据,或共享自己的数使应用程序能访问其他应用程序(如通讯录)的数据,或共享自己的数据据 资源管理器(资源管理器()提供访问非代码资源,如本地化字符串、图形和布局文件提供访问非代码资源,如本地化字符串、图形和布局文件 通知管理器(通知管理器()使所有的应用程序能够在状态栏显示自定义警告使所有的应用程序能够在状态栏显示自定义警告 活动管理器(活动管理器()管理应用程序生命周期管理应用程序生命周期,提供通用的导航回退功能提供通用的导航回退功能 72.5、装配一个核心应用程序集合,包括电子装配一个核心应用程序集合,包括电子邮件客户端、程序、日历、地图、浏览邮件客户端、程序、日历、地图、浏览器、联系人和其他设置。所有应用程序器、联系人和其他设置。所有应用程序都是用编程语言写的。都是用编程语言写的。8环境搭建及1、环境搭建1.1、安装1.2、安装1.3、安装1.4、安装1.5、创建2、91、环境搭建、环境搭建 1.1、安装、安装 如果你还没有的话,先去下载,接下来的工作就是安装提示一步一步走。设置环境变量步如果你还没有的话,先去下载,接下来的工作就是安装提示一步一步走。设置环境变量步骤如下:骤如下:a.我的电脑我的电脑-属性属性-高级高级-环境变量环境变量-系统变量中添加以下环境变量:系统变量中添加以下环境变量:b.值为:值为:D:1.6.0_18(你安装的目录)(你安装的目录)c.值为:值为:;:在开始追加在开始追加;:前面四步设置环境变量对搭建开发环境不是必须的,可以跳过。:前面四步设置环境变量对搭建开发环境不是必须的,可以跳过。10 安装完成之后,可以在检查是否安装成功。打开窗口,输入 查看的版本信息。出现类似下面的画面表示安装成功了:111.2、安装安装 如果你还没有的话,可以先去下载,下载如下图所示的如果你还没有的话,可以先去下载,下载如下图所示的 (92M)的)的 32版:版:解压之后既可使用。解压之后既可使用。121.3、安装安装在在 下载下载05,下载完成后解压到任意路径。,下载完成后解压到任意路径。运行运行,点击,点击。如果没有出现可安装的包,请。如果没有出现可安装的包,请点击,选中中的点击,选中中的.这项,再点击这项,再点击 。选择希望安装的及其文档或者其它包,点击选择希望安装的及其文档或者其它包,点击、,开始下载安装所选包,开始下载安装所选包。在用户变量中新建值为:在用户变量中新建值为:中的绝对路径(本机中的绝对路径(本机为为D:)。)。13 “确定”后,重新启动计算机。重启计算机以后,进入命令窗口,检查是不是安装成功。运行 h 如果有类似以下的输出,表明安装成功:141.4、安装、安装打开打开 ,进入菜单中的,进入菜单中的 -点击点击.按钮,弹出对话框要求输入和:自己随便取,输入。如下图所示:按钮,弹出对话框要求输入和:自己随便取,输入。如下图所示:15确定返回后,在 后的下拉列表中选择我们刚才添加的,我们会看到下面出有,展开它会有 和 ,勾选他们。如右图所示:完成之后:选择 .在左边的面板选择,然后在右侧点击.并选中路径,本机为:D:点击、。配置完成。161.5、创建、创建为使应用程序可以在模拟器上运行,必须创建。为使应用程序可以在模拟器上运行,必须创建。a、在中。选择、在中。选择 b、点击左侧面板的、点击左侧面板的,再右侧点击,再右侧点击 c、填入,选择的,、填入,选择的,大小任意,随便选,目前保持默认值大小任意,随便选,目前保持默认值d、点击、点击 即可完成创建即可完成创建 注意:如果你点击左侧面板的注意:如果你点击左侧面板的,再右侧点击,再右侧点击,而下拉列表没有可选项时,这时候你:,而下拉列表没有可选项时,这时候你:a)点击左侧面板的点击左侧面板的,在右侧勾选,如下图所示:,在右侧勾选,如下图所示:b)然后点击然后点击 按钮,接下来就是按提示做就行了按钮,接下来就是按提示做就行了 要做这两步,原因是在要做这两步,原因是在1.3、安装中没有安装一些必要的可用包(安装中没有安装一些必要的可用包()。)。172、a.通过-菜单,建立新项目 b.然后填写必要的参数,如下图所示:(注意这里我勾选的是,你可以选你喜欢的,但你要创建相应的)18c.点击后,点击的菜单选择 d.选择“”,点击在左上角(按钮像一张纸上有个“+”号)或者双击“”,有个新的选项“”(可以改为我们喜欢的名字)。e.在右侧面板中点击,选择 19f.在面板的中勾选相应的,如果没有可用的的话,你需要点击右下角的,然后新建相应的。如下图所示:20g.然后点按钮即可,运行成功的话会有的模拟器界面,如下图所示:21相关参数的说明:A.:包含这个项目的文件夹的名称。B.:包名,遵循规范,用包名来区分不同的类是很重要的,我用的是。C.:这是项目的主类名,这个类将会是的类的子类。一个类是一个简单的启动程序和控制程序的类。它可以根据需要创建界面,但不是必须的。D.:一个易读的标题在你的应用程序上。E.在选择栏的 选项,允许你选择一个已存在的项目。22项目的目录结构1、项目的目录结构1.1、文件夹1.2、文件夹1.3、2.1文件夹1.4、1.5、文件夹1.6、1.7、231、项目的目录结构、项目的目录结构(这个项目是基于 2.1的)在的左侧展开项目,可以看到如下图的目录结构:241.1、文件夹、文件夹 ,该文件夹是放项目的源代码的。打开文件会看到如下代码:该文件夹是放项目的源代码的。打开文件会看到如下代码:;/*.*/()();();可以知道:我们新建一个简单的项目,系统为我们生成了一个文件。他导入了两个类和,可以知道:我们新建一个简单的项目,系统为我们生成了一个文件。他导入了两个类和,类继承自且重写了方法。类继承自且重写了方法。25以下说明针对没有学过或者基础薄弱的人在重写父类的时,在方法前面加上 系统可以帮你检查方法的正确性。例如,().这种写法是正确的,如果你写成 ().这样编译器回报如下错误 ()a ,以确保你正确重写方法。(因为应该为)而如果你不加,则编译器将不会检测出错误,而是会认为你新定义了一个方法26类:因为几乎所有的活动()都是与用户交互的,所以类关注创建窗口,你可以用方法()将自己的放到里面。然而活动通常以全屏的方式展示给用户,也可以以浮动窗口或嵌入在另外一个活动中。有两个方法是几乎所有的子类都实现的:():初始化你的活动(),比如完成一些图形的绘制。最重要的是,在这个方法里你通常将用布局资源()调用()方法定义你的,和用()在你的中检索你需要编程地交互的小部件()。指定由哪个文件指定布局(),可以将这个界面显示出来,然后我们进行相关操作,我们的操作会被包装成为一个意图,然后这个意图对应有相关的进行处理。():处理当离开你的活动时要做的事情。最重要的是,用户做的所有改变应该在这里提交(通常保存数据)。类:从字符串值映射各种可打包的()类型(单词就是捆绑的意思,所有这个 类很好理解和记忆)。如该类提供了公有方法 (),如果给定的包含在的映射中返回,否则返回。该类实现了和接口,所以它具有这两者的特性。271.2、文件夹、文件夹该文件夹下面有个文件,是在建立项目时自动生成的,这个文件是只读模式的,不能更改。文件该文件夹下面有个文件,是在建立项目时自动生成的,这个文件是只读模式的,不能更改。文件中定义了一个类中定义了一个类R,R类中包含很多静态类,且静态类的名字都与中的一个名字对应,即类中包含很多静态类,且静态类的名字都与中的一个名字对应,即R类定义该项目所有资源的索引。看我们的项目是不是如此,如下图:类定义该项目所有资源的索引。看我们的项目是不是如此,如下图:281.3、2.1文件夹文件夹该文件夹下包含文件,这是一个该文件夹下包含文件,这是一个 归档归档文件,其中包含构建应用程序所需的所有的文件,其中包含构建应用程序所需的所有的 库(如、)和。通过将自己的应用程序绑定库(如、)和。通过将自己的应用程序绑定到到 和和,这允许你使用所有的库和包,且使你的应用程序在适当的环境中调试。例如,这允许你使用所有的库和包,且使你的应用程序在适当的环境中调试。例如上面的源文件中的:上面的源文件中的:;这里两行代码就是从导入包。这里两行代码就是从导入包。1.4、包含应用系统需要使用到的诸如包含应用系统需要使用到的诸如3、视频类的文件。、视频类的文件。1.5、文件夹、文件夹资源目录,包含你项目中的资源文件并将编译进资源目录,包含你项目中的资源文件并将编译进应用程序。向此目录添应用程序。向此目录添加加资源时,会被自动记录。新建一个项目,目录下资源时,会被自动记录。新建一个项目,目录下会有三个子目录:、。会有三个子目录:、。29:包含一些你的应用程序可以用的图标文件(*、*):界面布局文件()与应用中的类同,没修改过的文件如下(的就没有修改过):软件上所需要显示的各种文字。可以存放多个*文件,还可以存放不同类型的数据。比如、301.6、项目的总配置文件,记录应用中所使用的各种组件。这个文件列出了项目的总配置文件,记录应用中所使用的各种组件。这个文件列出了应用程序所提供的功能,在这个文件中,你可以指定应用程序使用到的应用程序所提供的功能,在这个文件中,你可以指定应用程序使用到的服务服务(如电话服务、互联网服务、短信服务、服务等等如电话服务、互联网服务、短信服务、服务等等)。另外当你新添加。另外当你新添加一个的时候,也需要在这个文件中进行相应配置,只有配置好后,才能一个的时候,也需要在这个文件中进行相应配置,只有配置好后,才能调用此。将包含如下设置:调用此。将包含如下设置:、等。等。31项目的如下所示:321.7、记录项目中所需要的环境信息,比如的版本等。记录项目中所需要的环境信息,比如的版本等。的文件代码如下所示,的文件代码如下所示,代码中的注释已经把解释得很清楚了:代码中的注释已经把解释得很清楚了:#.#!#.#,#,#.#.#.7 33应用程序基础及组件1、应用程序基础2、应用程序组件2.1、活动()2.2、服务()2.3、广播接收者()2.4、内容提供者()341、应用程序基础、应用程序基础 应用程序是用编程语言写的。编译后的代码包括应用程序要求的任何数据和资源文件,通过工具捆绑成一个包,归档文件以为后缀。这个文件是分发应用程序和安装到移动设备的中介或工具,用户下载这个文件到他们的设备上。一个文件中的所有代码被认为是一个应用程序。在许多方面,每个应用程序生活在它自己的世界:默认情况下,每一个应用程序运行在它自己的进程中。当应用程序中的任何代码需要执行时,将启动进程;当它不在需要和系统资源被其他应用程序请求时,将关闭进程。每个应用程序都有他自己的虚拟机(),因此应用程序代码独立于其他所有应用程序的代码运行。默认情况下,每个应用程序分配一个唯一的用户的。权限设置为每个应用程序的文件仅对用户和应用程序本身可见虽然也有一些方法可以暴露他们给其他应用程序。有可能设置两个应用程序共享一个用户,这种情况下,他们能够看到对方的文件。为了节省系统资源,具有相同的应 用程序也可以安排在同一个进程中,共享同一个。352、应用程序组件、应用程序组件 的一个主要特点是,一个应用程序可以利用其他应用程序的元素(假设这些应用程序允许的话)。例如,如果你的应用程序需要显示一个图像的滚动列表,且其他应用程序已经开发了一个合适的滚动条并可以提供给别的应用程序用,你可以调用这个滚动条来工作,而不用自己开发一个。你的应用程序不用并入其他应用程序的代码或链接到它。相反,当需求产生时它只是启动其他应用程序块。对于这个工作,当应用程序的任何部分被请求时,系统必须能够启动一个应用程序的进程,并实例化该部分的对象。因此,不像其他大多数系统的应用程序,应用程序没有一个单一的入口点(例如,没有()函数)。相反,系统能够实例化和运行需要几个必要的组件。有四种类型的组件:活动()服务()广播接收者()内容提供者()然而,并不是所有的应用程序都必须包含上面的四个部分,你的应用程序可以由上面的一个或几个来组建。当你决定使用以上哪些组件来构建应用程序时,你应该将它们列在文件中,在这个文件中你可以声明应用程序 组件以及它们的特性和要求。362.1、活动()、活动()一个活动表示一个可视化的用户界面,关注一个用户从事的事件。例如,一个活动一个活动表示一个可视化的用户界面,关注一个用户从事的事件。例如,一个活动可能表示一个用户可选择的菜单项列表,或者可能显示照片连同它的标题。一个文本短信可能表示一个用户可选择的菜单项列表,或者可能显示照片连同它的标题。一个文本短信应用程序可能有一个活动,显示联系人的名单发送信息;第二个活动,写信息给选定的联应用程序可能有一个活动,显示联系人的名单发送信息;第二个活动,写信息给选定的联系人;其他活动,重新查看旧信息或更改设置。虽然他们一起工作形成一个整体的用户界系人;其他活动,重新查看旧信息或更改设置。虽然他们一起工作形成一个整体的用户界面,但是每个活动是独立于其他活动的。每一个都是作为基类的一个子类的实现。面,但是每个活动是独立于其他活动的。每一个都是作为基类的一个子类的实现。类:因为几乎所有的活动()都是与用户交互的,所以类关注创建窗口,你可以用方法类:因为几乎所有的活动()都是与用户交互的,所以类关注创建窗口,你可以用方法()将自己将自己的放到里面。然而活动通常以全屏的方式展示给用户,也可以以浮动窗口或嵌入在另外一的放到里面。然而活动通常以全屏的方式展示给用户,也可以以浮动窗口或嵌入在另外一个活动中。有两个方法是几乎所有的子类都实现的:个活动中。有两个方法是几乎所有的子类都实现的:():初始化你的活动(),比如完成一些图形的绘制。最重要的是,在这个方法里你通常将用布:初始化你的活动(),比如完成一些图形的绘制。最重要的是,在这个方法里你通常将用布局资源(局资源()调用)调用()方法定义你的,和用方法定义你的,和用()在你的中检索你需要编程地交互的小部件()。在你的中检索你需要编程地交互的小部件()。指定由哪个文件指定布局(),可以将这个界面显示出来,然后我们进行相关操作,我们指定由哪个文件指定布局(),可以将这个界面显示出来,然后我们进行相关操作,我们的操作会被包装成为一个意图(),然后这个意图对应有相关的进行处理。的操作会被包装成为一个意图(),然后这个意图对应有相关的进行处理。():处理当离开你的活动时要做的事情。最重要的是,用户做的所有改变应该在这里提交(通常:处理当离开你的活动时要做的事情。最重要的是,用户做的所有改变应该在这里提交(通常保存数据)。保存数据)。37一个应用程序可能只包含一个活动,或者像刚才提到的短信应用,它可能包含几个活动。这些活动是什么,以及有多少,当然这取决于它的应用和设计。一般来讲,当应用程序被启动时,被标记为第一个的活动应该展示给用户。从一个活动移动到另一个活动由当前的活动完成开始下一个每一个活动都有一个默认的窗口。一般来讲,窗口会填满整个屏幕,但是它可能比屏幕小或浮在其他窗口上。一个活动还可以使用额外的窗口例如弹出式对话框,或当一用户选择屏幕上一个特定的项时一个窗口显示给用户重要的信息。窗口的可视内容是由继承自基类的一个分层的视图对象提供。每个视图控件是窗口内的一个特定的矩形空间。父视图包含和组织子女视图的布局。叶子视图(在分层的底层)绘制的矩形直接控制和响应用户的操作。因此,一个视图是活动与用户交互发生的地方。例如,一个视图可能显示一个小的图片和当用户点击图片时发起一个行为。有一些现成的视图你可以使用,包括按钮()、文本域()、滚动条()、菜单项()、复选框()等等。38通过()方法放置一个视图层次在一个活动窗口中。内容视图()是层次结构的根视图对象。层次结构如下图所示:“()方法:():根据布局资源 设置活动的界面。资源将被夸大,添加布局资源文件中所有的最高层的视图()到活动.”392.2、服务()服务()一个服务没有一个可视化用户界面,而是在后台无期限一个服务没有一个可视化用户界面,而是在后台无期限 地运行。例如一个服务可能是播放背景音乐而用户做其他一些地运行。例如一个服务可能是播放背景音乐而用户做其他一些 事情,或者它可能从网络获取数据,或计算一些东西并提供结事情,或者它可能从网络获取数据,或计算一些东西并提供结 果给需要的活动()。每个服务都继承自基类。果给需要的活动()。每个服务都继承自基类。一个典型的例子是一个媒体播放器播放一个播放列表中的歌曲。该播放器应用程序将一个典型的例子是一个媒体播放器播放一个播放列表中的歌曲。该播放器应用程序将可能有一个或多个活动(),允许用户选择歌曲和开始播放。然而,音乐播放本身不会被一可能有一个或多个活动(),允许用户选择歌曲和开始播放。然而,音乐播放本身不会被一个活动处理,因为用户希望保持音乐继续播放,当用户离开播放器去做其他事情时。为了保个活动处理,因为用户希望保持音乐继续播放,当用户离开播放器去做其他事情时。为了保持音乐继续播放,媒体播放器活动可以启动一个服务运行在后台。系统将保持音乐播放服务持音乐继续播放,媒体播放器活动可以启动一个服务运行在后台。系统将保持音乐播放服务运行,甚至媒体播放器离开屏幕时。运行,甚至媒体播放器离开屏幕时。可以连接到(绑定到)一个持续运行的服务(并启动服务,如果它尚未运行)。连接可以连接到(绑定到)一个持续运行的服务(并启动服务,如果它尚未运行)。连接之后,你可以通过服务暴露的接口与服务交流。对于音乐服务,这个接口可以允许用户暂停、之后,你可以通过服务暴露的接口与服务交流。对于音乐服务,这个接口可以允许用户暂停、倒带、停止和重新播放。倒带、停止和重新播放。像活动()和其他组件一样,服务()运行在应用程序进程中的主线程中。因此,他像活动()和其他组件一样,服务()运行在应用程序进程中的主线程中。因此,他们将不会阻止其他组件或用户界面,他们往往产生其他一些耗时的任务(如音乐播放)。们将不会阻止其他组件或用户界面,他们往往产生其他一些耗时的任务(如音乐播放)。402.3、广播接收者(、广播接收者()一个广播接收者是这样一个组件,它不做什么事,仅是接受广播公告并作出相应的反应。许多广一个广播接收者是这样一个组件,它不做什么事,仅是接受广播公告并作出相应的反应。许多广播源自于系统代码,例如公告时区的改变、电池电量低、已采取图片、用户改变了语言偏播源自于系统代码,例如公告时区的改变、电池电量低、已采取图片、用户改变了语言偏好。应用程序也可以发起广播,例如为了他其他程序知道某些数据已经下载到设备且他们好。应用程序也可以发起广播,例如为了他其他程序知道某些数据已经下载到设备且他们可以使用这些数据。可以使用这些数据。一个应用程序可以有任意数量的广播接收者去反应任何它认为重要的公告。所有的接受者继承自一个应用程序可以有任意数量的广播接收者去反应任何它认为重要的公告。所有的接受者继承自基类。基类。类:类:是接受是接受()发送的意图()的基类。可以用发送的意图()的基类。可以用()动态地注册这个类的实例,或者通过中动态地注册这个类的实例,或者通过中标签标签静态发布。静态发布。注意:如果你在注意:如果你在()注册一个接受者,你应该在注册一个接受者,你应该在()注销它。因为当暂停时你不会收到意图,注销它注销它。因为当暂停时你不会收到意图,注销它将削减不必要的系统开销。不要在将削减不必要的系统开销。不要在()中注销它,因为它将不会被调用,如果用户移动到先中注销它,因为它将不会被调用,如果用户移动到先前的堆栈。前的堆栈。41有两种主要的可接受广播类型:正常广播(由发送)是完全异步的。所有的广播接收者以无序方式运行,往往在同一时间接收。这样效率较高,但是意味着接受者不能使用结果或终止广播数据传播。有序广播(由发送)一次传递给一个接收者。由于每个接收者依次执行,因此它可以传播到下一个接收器,也可以完全终止传播以便他不会传递给其他接收者。接收者的运行顺序可由匹配的意图过滤器()的属性控制。广播接收者不显示一个用户界面。然而,它们启动一个活动去响应收到的信息,或者他们可能使用去通知用户。通知可以使用多种方式获得用户的注意闪烁的背光、振动设备、播放声音等等。典型的是放在一个持久的图标在状态栏,用户可以打开获取信息。422.4、内容提供者(、内容提供者()内容提供者(内容提供者()使一个应用程序的指定数据集提供给其他应用程序。这些数据可以存)使一个应用程序的指定数据集提供给其他应用程序。这些数据可以存储在文件系统中、在一个数据库、或以任何其他合理的方式。内容提供者继承自储在文件系统中、在一个数据库、或以任何其他合理的方式。内容提供者继承自 基类并实现基类并实现了一个标准的方法集,使得其他应用程序可以检索和存储数据。然而,应用程序并不直接调了一个标准的方法集,使得其他应用程序可以检索和存储数据。然而,应用程序并不直接调用这些方法。相反,替代的是它们使用一个对象并调用它的方法。能与任何内容提供者通信,用这些方法。相反,替代的是它们使用一个对象并调用它的方法。能与任何内容提供者通信,它与提供者合作来管理参与进来的进程间的通信。它与提供者合作来管理参与进来的进程间的通信。“内容提供者是应用程序的主要组成部分之一,提供内容给应用程序。他们封装数据且通过单个内容提供者是应用程序的主要组成部分之一,提供内容给应用程序。他们封装数据且通过单个接口提供给应用程序。只有需要在多个应用程序间共享数据是才需要内容提供者。例如,通接口提供给应用程序。只有需要在多个应用程序间共享数据是才需要内容提供者。例如,通讯录数据被多个应用程序使用,且必须存储在一个内容提供者中。如果你不需要在多个应用讯录数据被多个应用程序使用,且必须存储在一个内容提供者中。如果你不需要在多个应用程序间共享数据,你可以直接使用。程序间共享数据,你可以直接使用。当发出一个请求时,系统检查给定的的权限并传递请求给内容提供者注册。内容提供者能理解想当发出一个请求时,系统检查给定的的权限并传递请求给内容提供者注册。内容提供者能理解想要的东西。要的东西。类用于帮组解析。类用于帮组解析。需要实现的方法主要如下:需要实现的方法主要如下:(,)返回数据给调用者返回数据给调用者(,)插入数据到内容提供者插入数据到内容提供者(,)更新内容提供者已存在的数据更新内容提供者已存在的数据(,)从内容提供者中删除数据从内容提供者中删除数据()返回内容提供者中的返回内容提供者中的 类型数据类型数据“43应用程序基础及组件(续)应用程序基础及组件(续)1、激活组件:意图()1.1、活动()组件的激活1.2、服务()组件的激活1.3、广播接收者()组件的激活2、关闭组件3、清单文件4、过滤器441、激活组件:意图()、激活组件:意图()当接收到发出的请求后,内容提供者被激活。而其它三种组件活动、服务和广播接收者,被一种叫做意图()的异步消息激活。意图是一个保存着消息内容的对象。对于活动和服务来说,对象指明了请求的操作名称以及作为操作对象的数据的和其它一些信息。例如,它可以传递对活动的一个请求,让它为用户显示一张图片,或者让用户编辑一些文本。而对于广播接收者而言,对象指明了广播的行为。例如当照相按钮被按下,它可以对所有感兴趣的对象广播.451.1、活动()组件的激活、活动()组件的激活通过传递一个对象至通过传递一个对象至()或或()以载入(或指定新工作给)一个活动。相应的活动可以载入(或指定新工作给)一个活动。相应的活动可以看到初始的意图,这个意图通过以看到初始的意图,这个意图通过()方法来查看激活活动。调用活动的方法来查看激活活动。调用活动的()方法传递任方法传递任何后续的意图。何后续的意图。一个活动经常启动了下一个。如果它期望它所启动的那个活动返回一个结果,一个活动经常启动了下一个。如果它期望它所启动的那个活动返回一个结果,它会调用它会调用()而不是而不是()。例如,如果它启动了一个活动让用户挑选一张照片,它可能会返。例如,如果它启动了一个活动让用户挑选一张照片,它可能会返回被选中的照片。结果以一个对象传递调用活动的回被选中的照片。结果以一个对象传递调用活动的()方法。方法。461.2、服务()组件的激活、服务()组件的激活通过传递一个对象至通过传递一个对象至()以启动一个服务(或给予正在运行的服务以一个新的指以启动一个服务(或给予正在运行的服务以一个新的指令)。调用服务的令)。调用服务的()方法并将对象传递给它。方法并将对象传递给它。与此类似,一个可以传递给与此类似,一个可以传递给()以在调用的组件和目标服务之间建立持续的连接。以在调用的组件和目标服务之间建立持续的连接。这个服务会在调用这个服务会在调用()方法中接受这个对象(如果服务尚未启动,方法中接受这个对象(如果服务尚未启动,()会先启动它)。例会先启动它)。例如,一个活动可以连接至前面讲到的音乐播放服务,并提供给用户一个可操作的(用如,一个活动可以连接至前面讲到的音乐播放服务,并提供给用户一个可操作的(用户界面)以对播放进行控制。这个活动可以调用户界面)以对播放进行控制。这个活动可以调用()来建立连接,然后调用服务中定义来建立连接,然后调用服务中定义的对象来控制播放。的对象来控制播放。471.3、广播接收者(、广播接收者()组件的激活)组件的激活应用程序可以通过将对象传递给应用程序可以通过将对象传递给()()()及其它类似方法来产生一个广播。会通过及其它类似方法来产生一个广播。会通过()方法方法将将传递给所有对此广播有传递给所有对此广播有兴兴趣的广播接收者。趣的广播接收者。482、关闭组件、关闭组件内容提供者仅在响应提出请求的时候激活。而一个广播接收者仅在响应广播信息的时候激活。所以,没有必要去显式的关闭这些组件。而活动则不同,它提供了用户界面。与用户进行会话,所以只要会话依然持续,哪怕对话进程空闲,它都会一直保持激活状态。与此相似,服务也会在很长一段时间内保持运行。所以提供方法有序地关闭活动和服务。当组件不再被使用的时候或者必须要为更多活跃的组件回收内存时,组件也可能会被系统关闭。493、清单()文件、清单()文件 当启动一个应用程序组件之前,它必须知道那个组件是存在的。所以,应用程序会在一个清单()文件中声明它的组件,这个文件会被打包到包中。这个文件还将包括应用程序的代码、文件以及其它资源。这个清单文件是结构的文件,且所有的应用程序都把它叫做。为声明一个应用程序组件,它还会做很多额外工作,比如指明应用程序所需链接到的库的名称(除了默认的库之外)以及声明应用程序期望获得的各种权限。但清单文件的主要功能仍然是向声明应用程序的组件。举例说明,一个活动可以如下声明:50 .元素的属性指定了实现了这个活动的类的子类,和属性指向了包含展示给用户的此活动的图标和标签的资源文件。其它组件也以类似的方法声明 元素用于声明服务,元素用于声明广播接收者,而元素用于声明内容提供者。清单文件中未进行声明的活动、服务以及内容提供者将不为系统所见,从而也就不会被运行。然而,广播接收者既可以在清单文件中声明,也可以在代码中动态的创建(作为对象)且调用()方式注册到系统。514、过滤器、过滤器 对象可以显式地指定目标组件。如果进行了这种指定,会找到这个组件(依据清单文件中的声明)并激活它。但如果没有进行显式的指定,就必须为它找到对于来说最合适的组件。这个过程是通过比较对象和所有可能对象的过滤器完成的。组件的过滤器会告知它所能处理的类型。如同其它关于组件的必要信息一样,它们在清单文件中进行声明的。这里是上面示例的一个扩展,其中加入了针对活动的两个过滤器声明:(下页)示例中的第一个过滤器:“”和:“”的组合,是常见的。它标记这个活动显示在应用程序启动器中,用户在设备上看到的可启动的应用程序列表。换句话说,这个活动是应用程序的入口,是用户选择运行这个应用程序后所见到的第一个活动。第二个过滤器声明了这个活动针对特定类型的数据。一个组件可以拥有任意数量的过滤器,每个声明一系列不同的能力。如果它没有包含任何过滤器,它将只能被显式声明了目标组件名称的意图激活。对于广播接收者,它在代码中创建并注册过滤器,直接作为的对象实例化。其它过滤器则在清单文件中设置。52 .53活动与任务1、活动与任务概述2、亲和度和新任务()3、启动模式()4、清除栈()5、启动任务(541、活动与任务概述、活动与任务概述 如前所述,一个活动()能启动另一个活动,包括定义在别的应用程序中的活动。再次举例说明,假设你想让用户显示某地的街道地图。而且已经有了一个活动能做这个事情(假设这个活动叫做地图查看器),因此你的活动要做的就是将请求信息放进一个对象,然后将它传给()。地图查看器就启动并显示出地图。当用户点击返回按钮之后,你的活动就会重新出现在屏幕上。对用户来说,这个地图查看器就好像是你的应用程序的活动一样,虽然它定义在其他的应用程序中且运行在那个应用程序的进程中。将这些活动保持在同一个任务()中以维持用户的体验。简单地讲,任务是用户体验上的一个“应用程序”,是排成堆栈的一组相关活动。栈底的活动(根活动)是起始活动一般来讲,它是用户在应用程序启动器(也称应用程序列表,下同)中选择的一个活动。栈顶的活动是正在运行的活动它关注用户的行为(操作)。当一个活动启动另一个,新的活动被压入栈顶,变为正在运行的活动。前面那个活动保存在栈中。当用户点击返回按钮时,当前活动从栈顶中弹出,且前面那个活动恢复成为正在运行的活动。55栈中包含对象,因此如果一个活动(再次说明:活动是的子类)启动了多个实例例如多个地图查看器,则栈对每个实例有一个独立的入口。(可以这样理解:假设有四个活动以这样的顺序排在栈中,现在又有一个C的实例,则栈变成,这两个C的实例是独立的。)栈中的活动从不会被重新排列,只会被压入、弹出。这点很好理解,因为活动的调用顺序是固定的。任务是一栈的活动,而不是清单文件中声明的某个类或元素,因此无法独立于它的活动为任务赋值。整个任务的值是在栈底活动(根活动)设置的。例如,下节将讨论的“任务亲和度”,亲和度信息就是从任务的根活动中获取的。一个任务的所有活动作为一个整体运行。整个任务(整个活动栈)可置于前台或发送到后台。例如,假设当前任务有四个活动在栈中三个活动在当前活动下面。用户按下键,切换到程序启动器,并选择一个新的应用程序(实际上是一个新的任务)。当前任务进入后台,新任务的根活动将显示。接着,过了一会,用户回到主屏幕并再次选择之前的应用程序(之前的任务)。那个任务栈中的所有四个活动都变为前台运行。当用户按下返回键时,不是离开当前任务回到之前任务的根活动。相反,栈顶的活动被移除且栈中的下一个活动将显示。56上面所描述的是活动和任务的默认行为,但是有方法来改变所有这些行为。活动与任务之间的联系及任务中活动的行为,是由启动活动的对象的标志()和清单文件中活动元素的属性共同决定的。在这方面,主要的标志有:主要的属性有:572、亲和度和新任务(、亲和度和新任务()默认情况下,一个应用程序的所有活动互相之间都有一个亲和度()也就是说,他们属于同一个任务的偏好()。然而,也可以通过元素的属性为每个活动设置个体亲和度。定义在不同应用程序中的活动能够共享亲和度,同一个应用程序中的活动可以分配不一样的亲和度。亲和度发挥作用的两种情况:1)启动活动的对象包含标志时;2)一个活动的属性为“”时。标志 如前所述,默认情况下,一个新的活动被启动到调用()方法的活动所在的任务。它被压入调用它的活动的栈中。但是,如果传递给方法的对象包含标志,系统找一个不同的任务容纳活动。通常,顾名思义它表示一个新任务。但是,他并非一定如此。如果已经存在一个任务与新活动亲和度一样,该活动将启动到该任务。如果不是,则启动一个新任务。58属性 如果一个活动的属性为,它可以从启动它的任务转移到与它有亲和度并转到前台运行的任务中。例如,假设一个天气预报的活动,但选择城市是一个旅游应用程序的一部分。它与同一个应用程序中的其他活动具有相同的亲和度,且允许重新选择父活动()。你的一个活动启动天气预报活动,因此他初始是跟你的活动属于同一个任务。但是,当旅游应用程序切换到前台运行时,天气预报活动将被重新分配和显示到该任务。如果一个文件,从用户的角度看包含不止一个“应用程序”,你可能要为与他们有关的些活动指定不一样的亲和度。593、启动模式(、启动模式()有四种不同的启动模式可以分配到元素的属性:(默认模式)这些模式的在以下四方面不同:哪个任务将持有响应意图()的活动。对和 模式,是产生意图的任务(调用()方法)除非对象包含标志。在那种情况下,像上一节亲和度和新任务()所描述的那样选择一个不同的任务。相反,和模式,总是将活动标记为一个任务的根活动。他们定义一个任务,而从不启动到其他任务。活动是否可以实例化多次。或 活动可以实例化多次。这些实例可以属于多个任务,且一个给定任务可以包含同一个活动的多个实例。相反,和活动仅可以被实例化一次。因为这些活动是一个任务的根,这个限制意味着设备上一个时间只有不多于一个任务的实例。60是否允许实例所在任务有其他活动。是否允许实例所在任务有其他活动。活动所在任务只有它一个活动。如果他启动别的活动,活动所在任务只有它一个活动。如果他启动别的活动,那些活动将启动到不同的任务中,无论它的模式如何那些活动将启动到不同的任务中,无论它的模式如何就好像对象包含标志。在所有其他就好像对象包含标志。在所有其他方面,方面,模式等同于模式等同于模式。模式。其它三种模式允许多个活动属于一个任务。其它三种模式允许多个活动属于一个任务。活动总是任务的根活动,但是它能启动其他活活动总是任务的根活动,但是它能启动其他活动到它的任务。动到它的任务。或或 活动的实例可以出现的栈中的任何位置。活动的实例可以出现的栈中的任何位置。响应一个意图时是否需要生成类的新实例。对于默认的响应一个意图时是否需要生成类的新实例。对于默认的“”模式,创建新的实例去响应每一模式,创建新的实例去响应每一个新的意图。每个实例仅处理一个意图。对于个新的意图。每个实例仅处理一个意图。对于“”模式,一个类已存在的实例可以重新用了模式,一个类已存在的实例可以重新用了处理新的意图,如果它位于目标任务的活动栈的栈顶。如果不是在栈顶,就不可以重用。相处理新的意图,如果它位于目标任务的活动栈的栈顶。如果不是在栈顶,就不可以重用。相反,将创建一个新的实例并压入栈顶。反,将创建一个新的实例并压入栈顶。例如,一个任务的活动栈由根活动例如,一个任务的活动栈由根活动A、B、C和和D组成,顺序为。当一个意图到达请求类型组成,顺序为。当一个意图到达请求类型D时,时,如果如果D是默认的是默认的“”模式,将产生模式,将产生D类的新实例且栈变为。然而,如果类的新实例且栈变为。然而,如果D的启动模式是的启动模式是“”,已存在的,已存在的D实例将去处理新的意图(因为它在栈顶)且栈仍然是。实例将去处理新的意图(因为它在栈顶)且栈仍然是。61如果,另一方面,到达的意图是请求类型B时,一个B的新实例将启动而不管B的模式是“”还是“”(因为B不是在栈顶),因此栈的结构为。如前所述,“”和“”活动仅可以被实例化一次,因此他们的实例将处理所有的新意图。一个“”活动总是在栈顶(因为仅有一个活动在任务中),因此它总是在可以处理意图的位置。然而,一个“”活动在栈中可能有或可能没有其他活动在它上面。如果有,即它不在处理意图的位置,意图会被丢弃(即使意图被丢弃了,它的到来使任务转到并保持在前台运行)当一个已存在的活动被请求处理一个新的意图,对象将通过()调用传到活动。(产生启动活动的意图对象可以由()获取。)注意到当一个活动的新实例被创建去处理新意图时,用户总是可以按返回键返回到之前的状态(之前的活动)。但是当一个已存在的活动实例去处理新意图是,用户不可以按返回键返回到意图到达之前的状态。624、清除栈(、清除栈()如果用户离开一个任务很长时间,系统将会清除根活动之外的活动。当用户再次返回到这个任务时,像用户离开时一样,仅显示初始的活动。这个想法是,一段时间后,用户可能已经放弃之前做的东西,及返回任务做新的事情。这是默认情况,有些活动属性可以用来控制和改变这个行为。属性 如果在任务的根活动中这个属性被设置为,刚才描述的默认行为将不会发生。任务将保留所有的活动在它的栈中,甚至是离开很长一段时间。属性 如果在任务的根活动中这个属性被设置为,只有用户离开就清除根活动之外的活动。换句话说,它与截然相反。用户总是返回到任务的初始状态,甚至是只离开一会。63属性 这个属性类似于,但是它作用于单个活动,而不是整个任务。而且它能移除任何活动,包括根活动。当它被设置为“”,任务本次会话的活动的部分还存在,如果用户离开并返回到任务时,它将不再存在。有其他的方法强制从栈中移除活动。如果对象包含标志,目标任务已经有一个指定类型的活动实例,栈中该实例上面的其它活动将被移除而使它置于栈顶响应意图。如果指定的活动的启动类型是,它自己也将被移除出栈,且一个新的实例将被启动去处理到来的意图。这是因为当模式是时,总是创建一个新的实例去处理新的意图。标志经常与一起使用。当一起使用时,这些标志的方式是定位到另一个任务中的已存在的活动并把它放到可以处理意图的位置。645、启动任务(、启动任务()通过给定活动一个意图过滤器作为指定行为()和指定种类(),活动就被设置为任务的入口点了。上篇应用程序基础及组件(续)第四节过滤器中我们举了这样一个例子,它将导致该活动的图标()和标签()显示在应用程序启动器,给用户启动它或启动之后任意时候返回到它。它的第二个功能非常重要:用户可以离开任务且之后可以返回到它。基于这个原因,两个启动模式和标记活动总是初始化一个任务来响应意图,仅可以使用在有和过滤器的活动中。想象一下,如果没有这个过滤器将会发生什么:一个意图启动一个活动,开始一个新任务,用户在任务中做一些操作。然后用户按下键,任务现在退到后台运行且被主屏幕遮蔽住。而且,由于活动不在应用程序启动器中显示,用户无法再返回。类似的困难也出现在标志。如果这个标志导致一个活动开始一个新的任务且用户按键离开它,就必须要有某种方法是用户能够导航回来。一些实体(如通知管理器)总是在外部任务启动活动,从不作为他们自己的一部分,因此他们总是将带标志的意图传到()方法启动活动。如果你有活动能调用外部实体,可以使用此标志,注意用户有一个独立的方式返回到开始的任务。如果您希望用户离开活动后就不能再回到这个活动,可以将元素的属性设置为。可以参见清除栈那节。65进程与线程1、进程2、线程2.1、远程过程调用(,)2.2、线程安全方法661、进程、进程 组件运行于哪个进程中由清单文件控制。组件元素、,都有一个属性可以指定组件运行在哪个进程中。这个属性可以设置为每个组件运行在自己的进程中,或者某些组件共享一个进程而其他的不共享。他们还可以设置为不同应用程序的组件运行在同一个进程中假设这些应用程序共享同一个用户且被分配了同样的权限。元素也有属性,为所有的组件设置一个默认值。所有的组件都在特定进程的主线程中实例化,且系统调用组件是由主线程派遣。不会为每个实例创建单独的线程,因此,对应这些调用的方法诸如()报告用用户的行为和生命周期通知,总是运行在进程的主线程中。这意味着,没有组件当被系统调用时应该执行很长时间或阻塞操作(如网络操作或循环计算),因为这将阻塞进程中的其它组件。你可以为长操作衍生独立的线程。“():默认实现(),当按下视图的或然后释放时执行,如果视图可用且可点击。参数表示按钮被按下的键码,来自 定义了按钮动作的对象67返回值 如果你处理事件,返回;如果你想下一个接收者处理事件,返回。“”当内存剩余较小且其它进程请求较大内存并需要立即分配,要回收某些进程,进程中的应用程序组件会被销毁。当他们再次运行时,会重新开始一个进程。当决定终结哪个进程时,会权衡他们对用户重要性的相对权值。例如,与运行在屏幕可见的活动进程相比(前台进程),它更容易关闭一个进程,它的活动在屏幕是不可见(后台进程)。决定是否终结进程,取决于运行在进程中的组件状态。关于组件的状态,将在后面一篇组件生命周期中介绍。682、线程、线程 虽然你可能会将你的应用程序限制在一个进程中,但有时候你会需要衍生一个线程做一些后台工作。因为用户界面必须很快地响应用户的操作,所以活动寄宿的线程不应该做一些耗时的操作如网络下载。任何不可能在短时间完成的操作应该分配到别的线程。线程在代码中是用标准的线程对象创建的,提供了一些方便的类来管理线程用于在线程中运行消息循环、用户处理消息、用户设置一个消息循环的线程。类该类用户在线程中运行消息循环。线程默认没有消息循环,可以在线程中调用()创建一个运行循环;然后调用()处理消息直到循环结束。大部分消息循环交互是通过类。下面是一个典型的执行一个线程的例子,分别使用()和()创建一个初始的与交互:;()();=()();();692.1、远程过程调用(、远程过程调用(,),)有一个轻量级的远程过程调用机制有一个轻量级的远程过程调用机制方法在本地调用却在远程(另外一个进程中)方法在本地调用却在远程(另外一个进程中)执行,结果返回给调用者。这需要将方法调用和它伴随的数据分解为操作系统能够理解的层执行,结果返回给调用者。这需要将方法调用和它伴随的数据分解为操作系统能够理解的层次,从本地进程和地址空间传输到远程进程和地址空间,并重新组装调用。返回值以相反方次,从本地进程和地址空间传输到远程进程和地址空间,并重新组装调用。返回值以相反方向传输。提供了做这些工作的所有代码,这样我们可以专注于定义和执行接口本身。向传输。提供了做这些工作的所有代码,这样我们可以专注于定义和执行接口本身。一个接口仅包含方法。所有的方法同步地执行(本地方法阻塞直到远程方法执行完成)一个接口仅包含方法。所有的方法同步地执行(本地方法阻塞直到远程方法执行完成),即使是没有返回值。简言之,该机制工作原理如下:首先,你用简单的(,即使是没有返回值。简言之,该机制工作原理如下:首先,你用简单的(,接口定义语,接口定义语言)声明一个你想实现的接口。从这个声明中,工具生成一个接口定义,提供给本地和远程言)声明一个你想实现的接口。从这个声明中,工具生成一个接口定义,提供给本地和远程进程。它包含两个内部类,如下图所示:进程。它包含两个内部类,如下图所示:70内部类有管理你用定义的接口的远程过程调用所需要的所有代码。这两个内部类都实现了接口。其中之一就是在本地由系统内部使用,你写代码可以忽略它。另外一个是,扩展自类。除了用于有效地()调用的内部代码,内部类在接口声明中还包含方法声明。你可以定义的子类实现这些方法,如图中所示。通常情况下,远程过程有一个服务管理(因为服务能通知系统关于进程和它连接的其它进程的信息)。它有由工具生成的接口文件和子类实现的方法。服务的客户端仅有由工具生成的接口文件。下面介绍服务如何与它的客户端建立连接:服务的客户端(在本地端的)应该实现()和()方法,因此当与远程服务建立连接成功和断
展开阅读全文
相关资源
相关搜索

最新文档


当前位置:首页 > 办公文档 > 教学培训


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!