Android应用开发以及设计思想深度剖析2Word文档下载推荐.docx
- 文档编号:6492451
- 上传时间:2023-05-06
- 格式:DOCX
- 页数:15
- 大小:228.67KB
Android应用开发以及设计思想深度剖析2Word文档下载推荐.docx
《Android应用开发以及设计思想深度剖析2Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《Android应用开发以及设计思想深度剖析2Word文档下载推荐.docx(15页珍藏版)》请在冰点文库上搜索。
从运行态来看,所谓的应用程序,也只是承载某些功能的进程。
1.1
所谓的Android应用程序
我们从前面的例子中看到,无论是编写的代码,还是最后生成的.apk文件,都是没有所谓的应用程序的。
应用程序本身是一种虚无的概念,只是一种以zip格式进行压缩的一个文件,一种容器而已。
如我们前面的Helloworld的例子里所看到的那样,其实一个应用程序里最重要的一个配置文件就是AndroidManifest.xml文件。
一个最简单的项目,除了基本的代码与UI资源,也会需要有个AndroidManifest.xml文件。
甚至一些极端一点的例子,我们去市场上下载一些什么主题包、插件包、权限包之类的.apk文件,解压开,这时可以发现这样的.apk文件里,连代码都没有,只有一些图片之类的文件。
于是,我们可以得到Android里关于应用程序的第一个印象,作为Android应用程序的载体,.apk文件只是一种进行包装与传输的格式,而每个.apk文件必然包含一个AndroidManifest.xml文件,由这一文件来描述该.apk文件提供的内容。
当然,我们在稍后会看到,这一文件里,还会包含一些权限控制的信息。
我们可以给我们的应用程序创建两个一模一样的图形界面,直接从我们的前面的HelloWorld开始下手,比如将HelloWorld.java在Eclipse里拷贝到HelloAgain.java(这样可以减少改代码的麻烦)。
这时可以得到两个界面的应用程序,然后我们再把我们的AndoridManifest.xml文件,改成如下的样子:
<
?
xml
version="
1.0"
encoding="
utf-8"
>
manifest
xmlns:
android="
package="
org.lianlab.hello"
android:
versionCode="
1"
versionName="
applicationandroid:
label="
@string/app_name"
activity
name="
.Helloworld"
intent-filter>
action
android.intent.action.MAIN"
/>
category
android.intent.category.LAUNCHER"
/intent-filter>
/activity>
.HelloAgain"
android:
/application>
/manifest>
这时我们编译、安装到Android设备(或者是虚拟机)里,这时再打开主界面查看安装过的应用程序,这时是不是发生了什么很奇怪的现象?
这时界面上会出现两个叫Helloworld的应用程序。
我们这时如果在设备里去“设置”à
“应用程序”,我们仍只看到一个应用程序。
通过对AndroidManifest.xml的小恶作剧,我们可以看到Android应用程序的第二个特点,就是没有所谓的主入口(即我们点击的图标时触发的执行效果)。
应用程序在安装完成后,只是通过AndroidManifest.xml来决定在系统上应该表现成什么样子。
如果希望应用程序可以表现不如此变态,这时,我们可以回到AndroidManifest.xml里,把<
activityandroid:
…这个标签里的<
标签删掉,这时应用程序的表现就正常了。
到目前为止,我们就已经接触了android编程里的两个概念,一个是Activity,另一个是Intent(而我们AndroidManifest.xml文件里的IntentFilter实际是辅助Intent的)。
Android毕竟是种图形界面的编程环境,我们常见的应用程序里,可能绝大部分只会与这两种概念打交道。
而两者的概念组合,就很容易体现出Android应用程序在编程上的“无界化”思想。
1.2
Android世界里的共享
作为一个智能手机操作系统,其用户可能在功能上有各种各样的功能组合。
比如最简单的打电话,则后续动作会有保存联系人,同时需要给联系人拍照做来电大头贴。
又比如需要来了个短信通信用户到某个地方干什么事情,这时,用户需要打开地图,搜索一下地址,然后还有可能需要定位到那个位置。
用户在主界面里点击相应功能的应用程序之后,就可能有非常多的功能性的组合,因为用户的想法是不可预估的。
我们当然也可以限制用户当前菜单下可以干什么事情,但这样就失去了智能系统的意义。
我们也可以假设用户都会按一个“Home”键回到主界面,这时原来的执行的程序就会被锁定当前状态,用户重新打开另外一个应用程序,操作完再按“Home”键可以退回到原来的应用程序。
通过这种“应用程序”到“Home”到“应用程序”的循环,我们也可以达到我们想要达到的目的。
但这时,出于交互性的考虑,我们也还是需要有限地提供一些交互手段,比如“短信”应用程序里包含地址信息,一点击可以直接打开“地图”进行后续操作,但这些有限交互是可以在系统设计阶段被固化。
这时,我们是不是就得到了我们想要的能够应付用户任何操作组合的系统?
是的,恭喜您,您得到了iPhone的设计思路。
但此时的用户交互流程则被改变成这个样子:
这种解决问题的办法也不是不可以,但需要很固化的设计,应用程序的行为比较受限。
虽然通过横扫全世界的iPhone证明了这样的设计可能是比较合乎用户体验之道的(不容易出错),但这样的解决思路从系统设计角度来看,并不是很灵活。
另外一个麻烦是必须要有苹果级设计功底的“Home”键,山寨货则用不了多久就会因为键盘失灵而失效。
当然即使苹果级设计,iPhone里的“Home”键还是会失效,于是又不得不在屏幕上加上触摸的Home手势。
作为开源系统的Android,当然不可能基于iOS的交互思路来解决问题,何这种交互时多了一步不停要回到主界面这一步。
在Android的设计里,最重要的是能够解决一个应用程序之间进行交互的问题,然后可以实现我们想要在Android系统里完成某种操作时,可以享受从一路顺畅完成的快感。
Android的解决之道,则是将传统意义上的应用程序,细化成一个个完成某项功能的部分,这种功能部分,在Android世界里被称为Activity。
Activity都应该被设计成可以独立地被执行以解决某个问题,当它完成或是用户选择退出执行时,又会自动跳回到调用这一Activity的界面,当然这时跳回的位置肯定是另外一个Activity。
当然,在一个Android系统里有可能存在无限多的Activity,在他们进行跳转切换时,我们就需要一种很灵活的消息传输机制(因为我们必须兼容系统里所有可能的互相调用的情况)。
而且这种传输机制还必须能够跨进程,不然,我们所有的涉及Activity互相调用部分都必须在同一进程里完成。
于是,Android系统里又有了Intent,用于解决交互通信。
这样的编程模型也需要有一定前提,那就是我们Application概念必须被弱化,我们不能有main函数入口(如果系统执行依赖main作入口,则不能实现Activity之间互相调用了,所有的Activity执行之前,必须先通过main入口来初始化环境)。
出于这样的设计,所以Application必须只是一个容器,将各种不同的Activity实现包装起来加载到系统里。
当然,将功能拆分成一个个的单一功能界面之后,我们需要有种机制可以将用户一路点击过去历史记录下来,当用户处理完时,可以退回到他们之前操作过的界面,这次就可以由多个应用程序组合出像是在用同一个应用程序的效果。
有了Activity,有了Activity之间起到调用作用的Intent,这时所有界面间操作变得有点像是函数调用一样,于是我们可以找函数调用时的基本数据结构—栈来帮忙,发生调用时,需要退出的Activity及其状态压栈,当从调用退出时则进行栈的弹出操作,这时我们的Activity管理就演变成如下图所示的简单栈管理。
有了这样的概念,于是我们响应用户点击操作的问题便迎刃而解,我们在设计应用程序时,不再是设计一个复杂的功能实现,而是实现一组完成单项功能的实现,也就是Activity。
然后这些Activity,只会通过用户点击来驱动它们之间是如何进行交互的。
比如,我们前面看到的地图、搜索、定位三个功能,虽然它都会被包装到同一个地图的应用程序里,但在实现上会是地图、搜索、定位三个不同的Activity。
因为现在我们的界面上的互相调用,已经变成了一种函数式的调用,这样,整个手机上的功能都被切分成各个单一的小功能,而真正要在Android系统上完整地实现某复杂个操作,则会提交由用户的点击来组合生成。
这样的复杂功能,则已经不是一个编程上的概念了,在Android系统里,这种需要完成什么事情的操作被抽象成一个虚拟的概念Task。
比如我们前面提到的打电话加拍大头贴的操作组合,就构成一个Task,这一Task需要由Launcher.apk,Contacts.apk,Gallery.apk来协同完成。
如果我们有两个能够提供同样功能的Activity,这种执行模式的灵活性表现得会更加明显。
比如中间打电话的功能,我们系统里有三个Activit(CallScreen,SipPhone,Dialer)都可以完成电话呼叫的功能,这时执行上的路径则会有三种可能性,会在进行跳转时弹出圣对话框由用户来选择:
通过Activity的这种可以动态被用户选择的特点,当用户对某一功能不满意时,完全就有可能通过下载另一个能实现这种功能的应用程序进行替换,甚至可以自己写一个。
事实上,Android系统里除了系统状态条与锁屏界面之后,没有任何的不可被替换的功能,这也是Android设备总是会长得千奇百怪的原因之一。
到这时,我们就可以看到Activity之所以会不被称为Window的原因,它也是单个界面或是MVC里的Controller实现部分那么简单,Activity这个名字代表的是某种单一交互功能上的实现。
这种功能的实现将在系统里通过Intent串接起来,构成了一个在功能上具备极大可拓展性的系统。
基于这样的特点,Android也就被称作是“无边界”系统,因为它在功能上延展不再受限于系统的能力,而只受限于智商与创意。
这就是Android世界里的功能共享。
在这种功能共享模型之下,可能还是会有一些微调的需求:
1.
我们有一些情况下不宜使用这种栈式Activity管理,比如我们写一个需要注册的应用程序,注册完开始使用,然后再按退出,我们又会一步步退回到注册填个人信息的界面,而不合理地完全退出。
这样可能不合适。
这时,我们可以使用Intent的Flag参数,加上Activity的Affinity属性进行组合控制。
2.
如果不停地跳出对话框让用户选,用户会崩溃掉。
当然,用户可以在选择时点选一个“始终”的默认选择,这时下次就会使用默认的Activity处理某种操作。
但还是有可能会不合理地使用跨.apk文件里使用Activity,造成性能上的开销,这时,我们也可以在执行下次Activity执行操作时进行强制性地指定。
当然,我们通过Activity这种概念还需要另外一个前提,这就是Android会有别于传统操作系统的前提,那就是单窗口。
想像一下,在多窗口环境下,我们的栈式管理Activity在进行跳转和返回时将会构成多大的灾难啊。
好在使用电容屏的设备,单窗口是天生的需求。
由于手指触摸的精度非常低,无法点准过小的按钮,比如窗口上的关闭按钮,如果将这些按钮放大,又造成了屏幕显示空间上的浪费。
iPhone带来的“后PC时代”革命,最重要的一点就是使用“返祖”式的单窗口显示。
这种怪异的操作方式,实际上在我们生活中也有类似的例子,就比如说我们的动态网页。
动态网页,特别是HTML5构建的网络应用程序,其操作模式,就是可以在不同的链接里不断地点击下去,如果不是弹出新窗口,我们始终还可以退回到发起这一连串点击的起始页面。
Android应用程序,XML构成的UI语言的作用跟Html页面类似,而Java构建的Activity就相当与网页交互中使用的JavaScript,有了这样的相似性,Android编程环境可以说是最接近HTML5的一种编程环境了,但可惜不能像HTML5那样可以跨平台。
我们解析了能完成单一功能的Activty,这时还需要了解Intent,就像是我们了解过了函数实现原理,我们还需要掌握函数之间的参数传递。
当然,一般在介绍编程的思路里,会结合起来说明,或是先说明参数传递。
但Android环境里有点特殊性,一是Intent是一种能够实现跨进程调用的信息传递机制,二是Intent在消息传递上又很灵活,有一定的动态性。
Intent不光服务于Activity之间的调用,还会用于一些不直接与界面打交道的逻辑实现部分,比如我们后面将提到的Service,BroadcastReceiver,以及Notification。
1.3
Intent与IntentFilter
Intent,英文原意就是要“干什么”的意思,之所以取这个名字,也是因为在Android系统里,Intent所起到的作用就是用来指明下一步具体是做什么,具体是不是执行,由谁来执行,则会由根据当前的系统状态(能不能解析这个Intent请求)来决定。
这不只是简简单单地发个消息而已,而是一种更安全的、更加松散的消息机制。
在一个Intent消息对象里,共有六个成员(并不都是必须赋值的,只要一个Intent对象能够被解析,就会得以执行,否则就会会被舍弃):
成员
类型
说明
示例
ComponentName
String
用于定义谁将处理这一Intent。
它由一个Activity的具体实现的全名(加上包名)来指定
org.lianlab.hello.HelloActivity
Action
用于定义这一动作是做什么,可以被拓展自定义类型
ACTION_CALL
开始通话.
ACTION_EDIT
进行编辑.
Data
用一个URI来指定Intent的操作对象,因为URI一般会包含种类信息,于是这个值也可能被用作MIME设别。
“content:
//contacts/people/1”
指定联系列表中的第一个
Category
用来进一步明确什么样的可执行实体将处理这一Intent。
是可选项,也可多选。
CATEGORY_HOME
主界面应用程序
CATEGORY_LAUNCHER
可在主界面里被点击
Type
用来指定特定的MIME类型
"
video/*"
视频
Extra
Bundle
用来传递额外的数据传递,前面我们也介绍了Bundle是一种key:
value配对的字典类型,于是Extra里可以转递复杂的数据
putExtra("
sms_body"
"
sometext"
);
发短信时指定内容
Flags
int
预定义一系列用来控制Intent行为的属性值
在这个成员变量里,最能体现灵活性的就是Component,如果指定了这个值,则我们在通过startActivity()方法来发送Intent时,就会自动启动Component指定的Activity。
如果没有指定,则会由系统来选择一个能够处理这一Intent的Activity来执行,这时就引入了IntentFilter的概念。
IntentFilter在Android里是一种类似于Windows里的注册表一样的东西,虽然我们也可以通过编程来进行IntentFilter的控制,但一般情况下,我们只在AndroidManifest.xml文件里进行定义,对它一个<
的标签进行指定。
应用程序在安装过程中,它的AndroidManifest.xml会被系统扫描并汇总到系统环境里,这时<
也会被导入。
当Activity发送出来的Intent,没有指定Component时,系统就会通过<
找到合适的处理对象,如果只有一个或是用户设置了默认项,则启动这个功能部件来完成任务;
如果有多个<
匹配同时用户又没有指定默认项,则会弹出对话框让用户选择。
当然,默认项也会随着系统里新增了同一Intent匹配项而失效,用户也可以通过“设置”à
“应用程序”来取消默认值。
在AndroidManifest.xml里面定义<
很简单,就是通过指定Intent对象的Action,Data,Type,和Category这四个成员变量来指定。
比如:
.PlayerActivity"
configChanges="
orientation"
actionandroid:
categoryandroid:
android.intent.action.VIEW"
android.intent.category.DEFAULT"
dataandroid:
scheme="
file"
...
当我们的某个Activity,发送了一个Intent,其Action是”android.intent.action.VIEW”,data又是以file:
///开始的URI指定的内容(也就是文件类型),这时上面例子里的PlayerActivity就会成为播放时的候选项。
我们可以继续修改我们前面的HelloWorld的例子,我们新建一个Intent,将Action设成”android.intent.action.VIEW”(可以通过Intent.ACTION_VIEW这个预变量来转义),data使用某个文件“file:
///sd-ext/Movies/test.mp4”,这时就会匹配到我们上面的<
定义:
public
void
onClick(Viewv){
Intentrequest=
new
Intent(Intent.ACTION_VIEW);
request.putData(“file:
///sd-ext/Movies/test.mp4”);
startActivity(request);
finish();
}
当然,我们并不一定需要代码来进行这样的测试,我们也可以使用设备上的am命令来完成。
要完成与上面的点击操作一样的功能,也可以通过adb来执行这条命令:
$adbshellamstart–aandroid.intent.action.VIEW–dfile:
///sd-ext/Movies/test.mp4
在我们具体写代码过程中,我们可以根据需求来定义我们所需要的<
,可以将过滤规则写得很细,也可以写得很粗,让我们的Activity有更多地被执行到的机会。
在这些规则里,可能最重要的规则,就是我们前面也示范过的:
name=
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Android 应用 开发 以及 设计 思想 深度 剖析