<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_Venus神庙</title><subtitle type="text">The flying fly is flying in the high and big sky...</subtitle><id>http://feed.cnblogs.com/blog/u/10512/rss</id><updated>2011-12-25T15:45:13Z</updated><author><name>duguguiyu</name><uri>http://www.cnblogs.com/duguguiyu/</uri></author><generator>CNBlogs BlogServer</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/duguguiyu/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/10512/rss"/><entry><id>http://www.cnblogs.com/duguguiyu/archive/2010/05/29/1747244.html</id><title type="text">深入Android【八】 —— Activity间数据传输</title><summary type="text">Activity间数据传输当对Android有一些了解后，不难发现，Android程序UI框架接近于Web页面的概念。每一个用于呈现页面的组件，Activity，都是彼此独立的，它们通过系统核心来调度整合，彼此之间的通过Intent机制来串联。每一种架构都会有其利弊，Android当然也不能超然脱俗。由于Activity之间的松耦合关系，使得其复用能力特别的出色，Mash-Up方式可以有效的提高开...</summary><published>2010-05-29T15:23:00Z</published><updated>2010-05-29T15:23:00Z</updated><author><name>duguguiyu</name><uri>http://www.cnblogs.com/duguguiyu/</uri></author><link rel="alternate" href="http://www.cnblogs.com/duguguiyu/archive/2010/05/29/1747244.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/duguguiyu/archive/2010/05/29/1747244.html"/><content type="html">&lt;h1 style="font-size: 18pt; "&gt;&lt;font  size="6"&gt;&lt;font  face="Georgia"&gt;Activity间数据传输&lt;/font&gt;&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;&#xD;
&#xD;
当对Android有一些了解后，不难发现，Android程序UI框架接近于Web页面的概念。每一个用于呈现页面的组件，&lt;strong&gt;Activity&lt;/strong&gt;，都是彼此独立的，它们通过系统核心来调度整合，彼此之间的通过&lt;strong&gt;Intent&lt;/strong&gt;机制来串联。&lt;br /&gt;&#xD;
每一种架构都会有其利弊，Android当然也不能超然脱俗。由于Activity之间的松耦合关系，使得其&lt;strong&gt;复用&lt;/strong&gt;能力特别的出色，Mash-Up方式可以有效的提高开发效率。但另一方面，由于Activity过于的独立，它们之间的数据共享，成为一个麻烦的事情。&lt;br /&gt;&#xD;
&lt;h2 style="font-size: 14pt; "&gt;基于消息的传输&lt;/strong&gt;&lt;/p&gt;&#xD;
最标准的Activity之间的数据传输，就是通过Intent的&lt;strong&gt;Extra&lt;/strong&gt;对象。比如，你在A这个Activity上拿到一坨用户输入的文本信息，兴高采烈的想把它放到B这个Activity上展示并发送，一个很可行的方式，是通过Intent的&lt;strong&gt;putExtra&lt;/strong&gt;接口，把用户输入的那些字符信息，按照key/value的形式放进Intent，传输到B这个Activity上。&lt;br /&gt;&#xD;
&lt;br /&gt;&#xD;
&lt;div style="margin-top: 0px; margin-bottom: 0px; direction: inherit; "&gt;&lt;img src="http://docs.google.com/Drawing?w=400&amp;amp;h=400&amp;amp;ac=1&amp;amp;drawingId=sf8-K6eeTB3nY5AgSof6Wcg&amp;amp;drawingRev=34&amp;amp;docid=0AUAFRVp9nQgOZGR3Z3h3OXJfOTc2ZDZrMnQ3ZGc" alt="" /&gt;&lt;br /&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;br /&gt;&#xD;
如上图示，从A到B的传输，看上去是一个直连，但其实，Intent都是要经由系统核心层去分析调度的，这个操作，跨越了进程边界，自然而然，其中的数据，就是需要序列化和反序列化的，而不可以仅通过一个指针就倒腾过去了。&#xD;
&lt;div style="margin-top: 0px; margin-bottom: 0px; direction: inherit; "&gt;基于这样类消息的传输模式，好处不多说，直接谈问题：&lt;/div&gt;&#xD;
&lt;ul style="margin-top: 0px; margin-bottom: 0px; "&gt;&#xD;
     &lt;li style="margin-top: 0px; margin-bottom: 0px; "&gt;首先，对于&lt;strong&gt;大数据&lt;/strong&gt;，就是一场杯具，不可能一坨上M的数据，也来来回回的传来传去，慢死了谁来负责；&lt;/li&gt;&#xD;
     &lt;li style="margin-top: 0px; margin-bottom: 0px; "&gt;再则，Activity之间，维系的是一种&lt;strong&gt;线性关系&lt;/strong&gt;，当我想把一份数据，从队尾一级级传到队头的话，自己历经磨难不提，会把中间所有的Activity都搭上，他们明明自己可能不需要这份数据，也得拿着搁着，为他人做嫁衣裳，不惆怅都不行；&lt;/li&gt;&#xD;
     &lt;li style="margin-top: 0px; margin-bottom: 0px; "&gt;此外，基于消息的传输，会把同一份数据生成若干个副本，有时候，这样很好，没有副作用，大家自己玩自己的不需要看别人脸色，但还有些时候，你就上杆子需要把这些数据都修改一下，同步起来那就太惨烈了；&lt;/li&gt;&#xD;
     &lt;li style="margin-top: 0px; margin-bottom: 0px; "&gt;最后，写序列化代码实在是太无聊了，稍微复杂点的代码，就要自己写个序列化接口，整个吃力不讨好的活计。&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;h2 style="font-size: 14pt; "&gt;基于外部存储的传输&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;div style="margin-top: 0px; margin-bottom: 0px; direction: inherit; "&gt;既然&lt;strike&gt;兽兽&lt;/strike&gt;手手相传太幸苦，自然而然的想法就是找个地方，A把数据搁在那里，把地址信息告诉B，B需要的话，按图索骥，自取就好。这个搁东西的地方，可以考虑选择&lt;strong&gt;外部存储&lt;/strong&gt;。&lt;/div&gt;&#xD;
&lt;div style="margin-top: 0px; margin-bottom: 0px; direction: inherit; "&gt;在Android中，预设了一些快捷便利类和模块，更好的支持不同类别数据的存取。如果，需要存储的是一些小数据量的配置信息，可以选择&lt;strong&gt;&lt;a href="http://androidappdocs.appspot.com/reference/android/preference/Preference.html" id="abnm" title="Preference" target="_blank"&gt;Preference&lt;/a&gt;&lt;/strong&gt;，它等同于传统意义上的设置文件。Preference提供了一些基于key/value的存取接口，可以放置一些简单的基本数据或者派生了&lt;strong&gt;&lt;a href="http://androidappdocs.appspot.com/reference/android/os/Parcelable.html" id="zu.8" title="Parcelable" target="_blank"&gt;Parcelable&lt;/a&gt;&lt;/strong&gt;接口的对象。一个很好的应用场景是&lt;strong&gt;Cookie的存放&lt;/strong&gt;。你在登录界面获得了一份Cookie，你可以把它扔进Preference，谁想要谁去拿，再也不要来来回回的折腾了。&lt;/div&gt;&#xD;
&lt;div style="margin-top: 0px; margin-bottom: 0px; direction: inherit; "&gt;Preference适合于小数据、设置信息，如果大数据，你可以考虑使用&lt;strong&gt;数据库&lt;/strong&gt;。在Android中，使用的是&lt;strong&gt;Sqlite&lt;/strong&gt;，相关的类，堆放在&lt;strong&gt;&lt;a href="http://androidappdocs.appspot.com/reference/android/database/package-summary.html" id="gwmx" title="android.database" target="_blank"&gt;android.database&lt;/a&gt;&lt;/strong&gt;名字空间下，自查，无需赘述。&lt;/div&gt;&#xD;
在Android里，数据库是私有的，如果想分享&lt;strong&gt;给第三方组件使用&lt;/strong&gt;，就需要用&lt;strong&gt;&lt;a href="http://androidappdocs.appspot.com/reference/android/content/ContentProvider.html" id="wd:y" title="ContentProvider" target="_blank"&gt;ContentProvider&lt;/a&gt;&lt;/strong&gt;来封装了。比如你用系统的录音机组件即时搞一段音频信息，它不是返回可能大到恐怖的录音数据，而是会返回给你一个&lt;strong&gt;Uri&lt;/strong&gt;，它标明了这份数据在ContentProvider的地址信息，拿着这个Uri，领取数据就好。&#xD;
&lt;div style="margin-top: 0px; margin-bottom: 0px; direction: inherit; "&gt;当然当然，如果你足够淡定，也可以用赤果果的&lt;strong&gt;&lt;a href="http://androidappdocs.appspot.com/reference/java/io/File.html" id="m.8j" title="File" target="_blank"&gt;File&lt;/a&gt;&lt;/strong&gt;来存储。如果这个文件存在手机私有目录下，那就内部使用，放在SD卡上，那就可以所有应用，一切分享。&lt;/div&gt;&#xD;
&lt;br /&gt;&#xD;
&lt;div style="margin-top: 0px; margin-bottom: 0px; direction: inherit; "&gt;&lt;img src="http://docs.google.com/Drawing?w=400&amp;amp;h=400&amp;amp;ac=1&amp;amp;drawingId=stT_hYb-j0KIQoAffm3FmCQ&amp;amp;drawingRev=45&amp;amp;docid=0AUAFRVp9nQgOZGR3Z3h3OXJfOTc2ZDZrMnQ3ZGc" alt="" /&gt;&lt;br /&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;br /&gt;&#xD;
&lt;div style="margin-top: 0px; margin-bottom: 0px; direction: inherit; "&gt;基于这样外部存储的数据传输，优缺点显而易见，它解决了困扰Intent的传输路径复杂，不利于传输大批量数据的问题，但同时，它有留下了&lt;strong&gt;效率隐患&lt;/strong&gt;，复杂了&lt;strong&gt;编程模型&lt;/strong&gt;。因为面对外部存储，开发者必须要考虑效率问题，很多时候，多线程就会被提上议程，这样，想不麻烦，都不行鸟。&lt;/div&gt;&#xD;
&lt;h2 style="font-size: 14pt; "&gt;基于Service的传输&lt;/strong&gt;&lt;/p&gt;&#xD;
既然存在外部太慢，那么还是在内存级别解决问题好了，这时候，你可能就需要请出Android四大组件之一的&lt;strong&gt;&lt;a href="http://androidappdocs.appspot.com/reference/android/app/Service.html" id="cc6j" title="Service" target="_blank"&gt;Service&lt;/a&gt;&lt;/strong&gt;了。Service设计的本意，就是提供一些后台的服务，数据存取，也可以归于其职责的一部分。&#xD;
&lt;div style="margin-top: 0px; margin-bottom: 0px; direction: inherit; "&gt;Service是提供了直连机制，调用的Activity，可以通过&lt;strong&gt;bindService&lt;/strong&gt;方法，与目标Service建立一条数据通路，拿到&lt;strong&gt;&lt;a href="http://androidappdocs.appspot.com/reference/android/os/IBinder.html" id="k2gm" title="IBinder" target="_blank"&gt;IBinder&lt;/a&gt;&lt;/strong&gt;。这样，通过Android提供的IPC模型，就可以进行远程方法的调用和数据的传输了。&amp;nbsp;&lt;/div&gt;&#xD;
&lt;br /&gt;&#xD;
&lt;img src="http://docs.google.com/Drawing?w=267&amp;amp;h=267&amp;amp;ac=1&amp;amp;drawingId=sPh5odvUAo3rYVUoDSlV7aw&amp;amp;drawingRev=36&amp;amp;docid=0AUAFRVp9nQgOZGR3Z3h3OXJfOTc2ZDZrMnQ3ZGc" alt="" /&gt;&lt;br /&gt;&#xD;
&lt;br /&gt;&#xD;
如上，通过这种模式，可以解决一定问题，但是对于Service来说，实在是太大才小用了，Service的专长，不是在数据，还是在逻辑。对于传数据而言，Service还是重量了一点，不但是有连接耗精力，传输经由IPC，写起来也够费劲。而且作为组件，Service随时可能死掉，你还是要费劲心机的处理数据的持久化，得不偿失。&#xD;
&lt;h2 style="font-size: 14pt; "&gt;利用Application传输&lt;/strong&gt;&lt;/p&gt;&#xD;
好吧，如果你需要在不同页面之间共有某个&lt;strong&gt;内存对象&lt;/strong&gt;，很合适的一种方式是把它们扔到&lt;strong&gt;&lt;a href="http://androidappdocs.appspot.com/reference/android/app/Application.html" id="dylk" title="Application" target="_blank"&gt;Application&lt;/a&gt;&lt;/strong&gt;里面。Application是Context的一个子类，它会在整个应用任何一个组件起来之前，先起来嘘嘘。它的生命周期会贯穿整个应用所有组件的生命旅途，因此，放在其中的对象，不会被处理掉。&#xD;
&lt;div style="margin-top: 0px; margin-bottom: 0px; direction: inherit; "&gt;在Activity中，可以通过&lt;strong&gt;getApplication&lt;/strong&gt;接口，随时获得Application对象的引用，用于实现一些全局对象的存储，和处理，真是最合适不过的地方了。&lt;/div&gt;&#xD;
&lt;br /&gt;&#xD;
&lt;img src="http://docs.google.com/Drawing?w=400&amp;amp;h=400&amp;amp;ac=1&amp;amp;drawingId=soPfW2197WPWFht2V3lhvJQ&amp;amp;drawingRev=35&amp;amp;docid=0AUAFRVp9nQgOZGR3Z3h3OXJfOTc2ZDZrMnQ3ZGc" alt="" /&gt;&lt;br /&gt;&#xD;
&lt;br /&gt;&#xD;
&lt;div style="margin-top: 0px; margin-bottom: 0px; direction: inherit; "&gt;当然，好东西也不要使用过度，可以想象，由于Application存活周期长，其上引用的对象一直缺少被释放的机会，如果你把它当成垃圾场，什么东西都往里扔，污染环境，混乱逻辑不提，单就是滥用内存资源这一项，就够罪孽深重一把了。&lt;/div&gt;&#xD;
&lt;div style="margin-top: 0px; margin-bottom: 0px; direction: inherit; "&gt;因此，如果数据不是真的需要全局使用，不要搁在其中，如果数据太大，不要全部load出来，合理使用数据库等外存储设备，还是必须要的。&lt;br /&gt;&#xD;
&lt;h2 style="font-size: 14pt; "&gt;结语&lt;/strong&gt;&lt;/p&gt;&#xD;
还有一些特殊情况，可以考虑用一些特殊的方式。比如子Activity之间，可以通过调用getParent获得父Activity的引用，来访问期间的对象，云云。小众情况，姑且不提。&lt;br /&gt;&#xD;
以上这些概念，我相信所有的coder都了如指掌，如何处理这样的数据，都心如明镜。我只是给它们套上了一件Android的外衣，让初入Android的coder们，能迅速找到心仪的兵器，劈山砍石，攻城拔寨。&#xD;
 &lt;/div&gt;&lt;img src="http://www.cnblogs.com/duguguiyu/aggbug/1747244.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/duguguiyu/archive/2010/05/29/1747244.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/duguguiyu/archive/2010/05/02/1726069.html</id><title type="text">深入Android【七】 —— 资源文件</title><summary type="text">资源文件作为一枚coder，做界面，很多时候都是一场梦魇。很多时候，我们会感觉对于底层逻辑实现的很有把握性，哪怕需求一直在变，也可以通过不断的重构一直跟进，一切尽在掌握。但遭遇界面，往往就不再如此，它的好坏总是和审美、体验之类的词汇扯在一起，在凤姐芙蓉出没的年头，谈审美成为一件恐怖的事情。你可能会被要求不停的改代码，就为了移动一个像素，调整一枚按钮，琐碎而无聊。为了改变这样的状况，挽救coder们...</summary><published>2010-05-02T11:58:00Z</published><updated>2010-05-02T11:58:00Z</updated><author><name>duguguiyu</name><uri>http://www.cnblogs.com/duguguiyu/</uri></author><link rel="alternate" href="http://www.cnblogs.com/duguguiyu/archive/2010/05/02/1726069.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/duguguiyu/archive/2010/05/02/1726069.html"/><content type="html">&lt;span  style="font-family: Verdana; line-height: normal; font-size: 13px; "&gt;&lt;h1 style="font-size: 18pt; "&gt;&lt;font  face="Georgia"&gt;&lt;font  size="6"&gt;资源文件&lt;/font&gt;&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;作为一枚coder，做界面，很多时候都是一场梦魇。很多时候，我们会感觉对于底层逻辑实现的很有把握性，哪怕需求一直在变，也可以通过不断的重构一直跟进，一切尽在掌握。但遭遇界面，往往就不再如此，它的好坏总是和审美、体验之类的词汇扯在一起，在凤姐芙蓉出没的年头，谈审美成为一件恐怖的事情。你可能会被要求不停的改代码，就为了移动一个像素，调整一枚按钮，琐碎而无聊。&lt;br /&gt;为了改变这样的状况，挽救coder们于水生活热之中，很多开发平台，都采用了类似于资源文件的解决方案。此类方案的基本思想是，将界面的实现与底层逻辑的实现完全剥离开来，用资源文件这样的东西来描述界面。资源文件的描述语言，往往是结构化很强，比如Html，Xml（及其变形体）之类的。于开发语言相比，此类语言逻辑性较弱但结构更好可读性更强更容易理解，并对自动化工具非常友好，可以于界面的拖拽配置结合的更加完美。这样的剥离，可以是的底层逻辑和上层界面独立变化，甚至不同的人员开发（这一点在web开发上表现的应该很明显...），两者之间的耦合性非常的小，coder们的负担，陡然减少（好吧，一个很挫的资源架构也会额外增加开发人员的负担，Symbian同学，请不要对号入座...）。&lt;br /&gt;&lt;br /&gt;&lt;h2 style="font-size: 14pt; "&gt;结构和格式&lt;/strong&gt;&lt;/p&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;Android的资源文件，是由&lt;strong&gt;目录结构&lt;/strong&gt;，&lt;strong&gt;Xml格式的文件&lt;/strong&gt;，和&lt;strong&gt;纯数据文件&lt;/strong&gt;构成。从格式上来看，无疑，学习门槛非常低。Xml作为coder们的瑞士军刀，哪怕使不习惯，弄得清楚并会用至少是没有问题。从配套的工具来看，Android的ADT，提供了一套可视化的配置工具，说不上特别好用，但至少是差强人意能凑合着用，比不上iPhone的，调戏Symbian还是没有问题的［强档广告首播：有道词典 for iPhone新版火热上线，增加了超强单词本功能，特有的触电式颤抖单词切换功能，让你欲罢不能，持有相关设备的童鞋不要犹豫，一拥而上吧...］。&lt;br /&gt;Android的资源文件，&lt;strong&gt;覆盖面超级广&lt;/strong&gt;，只要是和界面相关的，都可以用资源文件表示，比如：UI的样式，菜单，配置文件，各种描述性字符串，图片，音频视频文件，动画，颜色，尺寸，风格和样式，等等等。所有的资源文件（不考虑asset，它和讨论暂无关联...），都放在&lt;strong&gt;res&lt;/strong&gt;目录下，不同类别的资源，需要放置在不同的&lt;strong&gt;特定名称的子文件夹&lt;/strong&gt;中，或者是写在特定文件名的文件中（或者ms不是必须的，但，不用在这里特立独行，寻章办事也挺好...）。比如，所有作为UI背景之类的图片，都需要扔在&lt;strong&gt;drawable&lt;/strong&gt;这类的文件夹中，所有字符串相关的，都会放到&lt;strong&gt;values&lt;/strong&gt;目录下形如&lt;strong&gt;strings.xml&lt;/strong&gt;这样的文件中（如下图所示，是一个资源文件目录结构的截图...）。&lt;/div&gt;&lt;div id="h5rd" style="margin-top: 0px; margin-bottom: 0px; text-align: left; "&gt;&lt;img src="http://docs.google.com/File?id=ddwgxw9r_1019g8tqs8g4_b" style="height: 361px; width: 270px; " alt="" /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;每个xml文件，都有一定的约定。比如一个字符串，会放在&amp;lt;string&amp;gt;&amp;lt;/string&amp;gt;这样的xml element中（如下图所示...），你可以通过eclipse的ADT插件提供的可是界面去填而不关注具体规范，也可以直接人肉打造，前者对于新手来说更为直观，后者对于老鸟而言更为迅捷。&lt;/div&gt;&lt;div id="nm_d" style="margin-top: 0px; margin-bottom: 0px; text-align: left; "&gt;&lt;img src="http://docs.google.com/File?id=ddwgxw9r_1020db7d45dh_b" style="height: 287.9px; width: 648px; " alt="" /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 style="font-size: 14pt; "&gt;可配置性&lt;/strong&gt;&lt;/p&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;程序逻辑总是不变应万变的，但界面往往是需要能够72变。首先一种变化因素，就是&lt;strong&gt;状态&lt;/strong&gt;。想象一下，我们往往会有这样类似的需求，一个按钮，我们需要没有按下去的时候是一种背景，按的过程中刷的变成另一副模样，当它可用的时候需要鲜鲜亮的一个样子，不可用的时候最好是灰不溜秋没人愿点的怂样，诸如此类。传统编程模型下（Symbian，哥叫你出来当模特...），我们总是需要不厌其烦的用代码控制这样的事情。监听不同的事件，见缝插针的切换背景，并祈祷上天，千万别让哥调整，否则哥和你没完。&lt;/div&gt;&lt;br  /&gt;&lt;img src="http://docs.google.com/File?id=ddwgxw9r_1021dpjfp3cb_b" style="height: 306.278px; width: 648px; " alt="" /&gt;&lt;br /&gt;&lt;br /&gt;在Android中，做这个事情，变得简单许多，通过预设的一些&lt;strong&gt;Xml属性&lt;/strong&gt;，能够轻松的搞定。如上图所示，是Radio Button的背景。通过搭配不同的属性，就可以自动转换背景。比如第一个&amp;lt;item&amp;gt;，说的是当Radio Button被选中，并且具有焦点的时候，显示btn_radio_on这幅图片，而最后一个&amp;lt;item&amp;gt;，说的是前述条件都不满足，并且处于选中状态，那么显示btn_radio_on这幅图片。&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;另外一个更易变的因素，就是&lt;strong&gt;手机硬件／软件环境&lt;/strong&gt;了，毕竟，不是家家都是苹果，一个平台搭一款手机，手机款形多样化，几乎是避免不了的问题。没有人希望自己做的软件在大屏幕手机上闪亮光鲜，换个小屏幕就惨不忍睹，竖屏看像那么回事横屏看就挤做一团。还有就是&lt;strong&gt;语言环境&lt;/strong&gt;了，做为一个有国际眼光的coder，作面向世界的NB软件是咱的梦想，但我们不能因为自己的梦想逼迫大家都去学中文，做一款软件可以根据手机的语言环境选择最合适展示的语言，很多时候，是一个需要具备的功能点。&lt;br /&gt;在Android中，实现这些，都是举手之劳。方法就是将和环境相关的资源，放入特定名称的文件夹中。比如，表示简体中文字符信息的资源，可以放到&lt;strong&gt;values-zh-rCN&lt;/strong&gt;中去，当系统语言环境为简体中文时，就会呈现出中文的字符信息。在Android中，很多相关配置项，都可以按照这样的方式参与到资源自适应的活动中来，包括屏幕大小，屏幕朝向，屏幕分辨率，语言环境，触屏类型，SDK版本等等。系统会给所有配置项一个&lt;strong&gt;优先级&lt;/strong&gt;（或者说权重，次序之类的），当用户提供了多份资源的时候，系统会根据优先级从高到底&lt;strong&gt;淘汰备选资源&lt;/strong&gt;，如果淘汰仅&lt;strong&gt;剩了一个&lt;/strong&gt;，那就是最符合当前系统软硬件语言环境的资源项，如果&lt;strong&gt;一个不剩&lt;/strong&gt;，择启用&lt;strong&gt;默认项&lt;/strong&gt;（最是形如values这样没有任何尾巴目录中的资源...）。因此，默认的资源是非常重要的，它必须是其他所有可选资源项的&lt;strong&gt;超集&lt;/strong&gt;，否则在资源选择失败的情况下，应用会凄凉的崩溃。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;关于资源配置，以及选择的详情，参见SDK中的：&lt;strong&gt;&lt;a href="http://androidappdocs.appspot.com/guide/topics/resources/resources-i18n.html" id="q2sf" title="guide/topics/resources/resources-i18n.html" target="_blank"&gt;guide/topics/resources/resources-i18n.html&lt;/a&gt;&lt;/strong&gt;部分。&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;h2 style="font-size: 14pt; "&gt;&lt;font  size="4"&gt;R类&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;在使用资源后，界面逻辑与底层逻辑的耦合被降低了，但这不意味着，两者没有关联了。比如，需要为某个按钮增加一个点击事件，就需要定位到所需的那个按钮；再比如，你需要使用某个字符串资源，通知用户某件事情，就需要能定位到资源中放置的该字串。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;最显而易见的一种方式，就是通过字符串比较，用&lt;strong&gt;名字信息&lt;/strong&gt;在资源的xml描述文件中定位到所需的内容，加载并使用。这种方式，解决了查找的问题，但反复的字符串比较，势必带来严重的效率隐患。因此，在Android中，类似于Symbian的方法，引入了一个R类。&lt;/div&gt;它的基本思想是，通过增加一个&lt;strong&gt;额外的编译器&lt;/strong&gt;，为所有的&lt;strong&gt;资源项&lt;/strong&gt;，都赋予一个&lt;strong&gt;32位的整形数&lt;/strong&gt;来表示，同一个资源像的不同配置，都&lt;strong&gt;使用同一个&lt;/strong&gt;id。这个整形数，就相当于这个资源项的&lt;strong&gt;门牌号码&lt;/strong&gt;，能够帮助定位到对应的资源项。所有的这些整形数，都以常量的方式，整合到一个Java类中，这个类就是&lt;strong&gt;R类&lt;/strong&gt;。这样，在程序中，就可以通过使用这个R类，来查找所需的资源，这就将字符串比较，简化成了一个整形数的比较，大大的节约了开销。&lt;br /&gt;不得不说，这整套逻辑和Symbian中的资源文件预编译一致。但两者很不同的点在于Symbian中的整形数，代表的是一个二进制流的&lt;strong&gt;偏移量&lt;/strong&gt;，资源中的内容在编译时决定了。而Android中的整形数，是一个有&lt;strong&gt;逻辑意义的数值&lt;/strong&gt;，它表达了这个资源所处的资源包，类别，和脚标，它的具体内容在运行时才确定，这使得它的&lt;strong&gt;灵活性大大增强&lt;/strong&gt;，付出的则是一定的&lt;strong&gt;效率代价&lt;/strong&gt;。&lt;h2 style="font-size: 14pt; "&gt;&lt;font  size="4"&gt;实现&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;按照惯例，还是要说实现的，以一个查找流程为示例。当在&lt;strong&gt;Activity&lt;/strong&gt;中需要使用字符串的，会调用它的&lt;strong&gt;getString&lt;/strong&gt;方法，传入&lt;strong&gt;R.stirng.xxx&lt;/strong&gt;的一个整形数，换取一个符合当前机器环境配置的字符串。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;getString，追根溯源，来到&lt;strong&gt;AssetManager&lt;/strong&gt;类中。Asset类，其实是一个空壳，它仅仅是提供了一些便利的接口，而将请求，通过&lt;strong&gt;JNI的接口&lt;/strong&gt;，传入到了&lt;strong&gt;底层C++&lt;/strong&gt;实现的类库中。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;在底层的实现，主要是在C++实现的，AssetManager，ResourceTypes等等之中。其中：&lt;/div&gt;&lt;ul style="margin-top: 0px; margin-bottom: 0px; "&gt;&lt;li style="margin-top: 0px; margin-bottom: 0px; "&gt;JNI文件在：&lt;strong&gt;framework/base/core/jni&lt;/strong&gt;&lt;/li&gt;&lt;li style="margin-top: 0px; margin-bottom: 0px; "&gt;头文件在：&lt;strong&gt;framework/base/include/utils&lt;/strong&gt;&lt;/li&gt;&lt;li style="margin-top: 0px; margin-bottom: 0px; "&gt;CPP文件在：&lt;strong&gt;framework/base/libs/utils&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;&lt;br /&gt;具体实现，和前述的算法逻辑是一致的。每一个资源的id，32位，&lt;strong&gt;高8位&lt;/strong&gt;表示资源包，&lt;strong&gt;低16位&lt;/strong&gt;用于描述脚标，&lt;strong&gt;中间8位&lt;/strong&gt;，用来说明类别。所有资源中的文件，都被预处理了，放入到了一系列的队列和表中，通过id，可以查到具体的位置。然后根据缓存的环境设置对象，跑一次淘汰算法，获得匹配的资源对象的对应文件和偏移量。然后将值读取出来，通过JNI接口，拷贝回去。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;以上这些描述，并不能帮助了解真实的实现细节，主要是为了促使大家对读取资源的效率有一个比较直观的认知。整个资源读取的流程比较长，但是实现在C++中，可以预想，效率比Java高一些，开发人员，应该能够根据自己的需求，决定是否将内容写入资源文件中（还是写在代码中...），是不是需要自己稍微缓存一下，诸如此类。&amp;nbsp;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;========================================&lt;/p&gt;&lt;p&gt;申请了自己的空间和域名，总算有了家的感觉，有兴趣的可以移步&lt;a href="http://flyvenus.net/" target="_blank"&gt;flyvenus.net&lt;/a&gt;，会同步更新相关内容，并提供更好的阅读体验。&lt;/p&gt;&lt;p&gt;========================================&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;/span&gt;&lt;img src="http://www.cnblogs.com/duguguiyu/aggbug/1726069.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/duguguiyu/archive/2010/05/02/1726069.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/duguguiyu/archive/2010/03/27/1698515.html</id><title type="text">深入Android 【六】 —— 界面构造</title><summary type="text">界面构造UI界面，对于每个应用而言，是它与用户进行交互的门脸。好的门脸，不只是是要亮丽可人，最好还能秀色可餐过目不忘，甚至还应该有涵养有气质，彬彬有理温柔耐心。对于开发者来说，锻造这样的面容，不但需要高超的技艺，也需要有称手的工具和对得起党的料子。俗话说，朽木不可雕也，芙蓉不是一日炼成的，不是什么平台都能叫特能书。有套好用的UI框架，对于开发者而言，真有如沙漠中的甘露，而要是撞见了杯具的UI套件，...</summary><published>2010-03-27T11:45:00Z</published><updated>2010-03-27T11:45:00Z</updated><author><name>duguguiyu</name><uri>http://www.cnblogs.com/duguguiyu/</uri></author><link rel="alternate" href="http://www.cnblogs.com/duguguiyu/archive/2010/03/27/1698515.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/duguguiyu/archive/2010/03/27/1698515.html"/><content type="html">&lt;span  style="font-family: Verdana; line-height: normal; font-size: 13px; "&gt;&lt;h1 style="font-size: 18pt; "&gt;&lt;font  size="6"&gt;&lt;font  face="Georgia"&gt;界面构造&lt;/font&gt;&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;UI界面，对于每个应用而言，是它与用户进行交互的门脸。好的门脸，不只是是要亮丽可人，最好还能秀色可餐过目不忘，甚至还应该有涵养有气质，彬彬有理温柔耐心。&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;对于开发者来说，锻造这样的面容，不但需要高超的技艺，也需要有称手的工具和对得起党的料子。俗话说，朽木不可雕也，芙蓉不是一日炼成的，不是什么平台都能叫特能书。有套好用的UI框架，对于开发者而言，真有如沙漠中的甘露，而要是撞见了杯具的UI套件，整个界面开发就有如梦魇了。&lt;/div&gt;Android的UI框架，最核心的，是&lt;strong&gt;资源&lt;/strong&gt;和&lt;strong&gt;Layout&lt;/strong&gt;体系，然后，通过完善的&lt;strong&gt;控件库&lt;/strong&gt;，简明的接口设计，进一步帮助开发者，能够最快的搭建自己需要界面（听到这里，Symbian同学开始钻土...）。&lt;br /&gt;&lt;br /&gt;&lt;h2 style="font-size: 14pt; "&gt;UI控件&lt;/strong&gt;&lt;/p&gt;做UI，有时候就像搭积木，在Android中，这个最原子的积木块，就是&lt;strong&gt;&lt;a href="http://androidappdocs.appspot.com/reference/android/view/View.html" id="g45p" title="View" style="color: #551a8b; " target="_blank"&gt;View&lt;/a&gt;&lt;/strong&gt;。所有其他的UI元素，都是派生于此类的子孙类们。&lt;br /&gt;&lt;br /&gt;&lt;div id="sirl" style="margin-top: 0px; margin-bottom: 0px; text-align: left; "&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/duguguiyu/ddwgxw9r_1008gxrqmxfz_b.png" width="312" height="211" alt="" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;又从SDK中偷来张图，用来描述Android的UI控件结构，在每一个window下，这都是一个标准而完整的树结构。View有一个子类&lt;strong&gt;&lt;a href="http://androidappdocs.appspot.com/reference/android/view/ViewGroup.html" id="z84k" title="ViewGroup" style="color: #551a8b; " target="_blank"&gt;ViewGroup&lt;/a&gt;&lt;/strong&gt;，它相当于一个容器类或者是复合控件，所有派生与ViewGroup的子类在这颗UI树中都可以承担着父节点的职责，而另一些绕过ViewGroup从View直通下来的，就只能蜷局在叶节点的范畴内了。&lt;br /&gt;之所有说这是一个很标准的&lt;strong&gt;控件树&lt;/strong&gt;，是因为父控件对子控件有绝对的掌控权，每个子控件的占地面积和位置，都是基于父控件来分配的，它能够接受和处理的事件，也是父控件派发下去的。这样的结构，被很多平台和框架广泛的认可，和传统的win开发和杯具的Symbian相比，虽然因为事件传播途径变长了，很多操作的效率变低了，但整个结构更有层次性，每个控件只需要多其父控件负责指挥子控件就好，职责明确，逻辑简单，利于开发和设计。&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;谈及任何平台的控件，都有一些不可避免的主题，比如，每个控件如何标识，如何设定大小和位置，如何接受和处理事件，如何绘制，诸如此类。&lt;/div&gt;&lt;h4 style="font-size: 10pt; "&gt;标识&lt;/strong&gt;&lt;/p&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;在Android中，你可以为每个控件选择设定一个&lt;strong&gt;id&lt;/strong&gt;，这个id的全局的唯一性不需要保证，但在某个局部的范围内具有可识别性，这样就可以通过这个id找到这个控件（如果不需要查找，就别设置了...）。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;但是，在父控件中逐级的find比较，找到id匹配的控件，然后再做转型，是一个比较重量的操作，于是Android又为控件憋出另一个属性，&lt;strong&gt;tag&lt;/strong&gt;。它接受任意object类型的数据，你可以把和这个控件对象相关的内容堆在里面。比如，在list中，我们常常将和每个list item相关的所有控件元素封装成一个object，扔到tag中，就不需要每次都去比较id进行寻找，更加高效快捷。&lt;/div&gt;&lt;h4 style="font-size: 10pt; "&gt;尺寸&lt;/strong&gt;&lt;/p&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;在Android中，控件最重要的大小属性，就是&lt;strong&gt;width/height&lt;/strong&gt;，开发者可以明确的指明控件的大小，可以设定成为&lt;strong&gt;fill_parent&lt;/strong&gt;和&lt;strong&gt;wrap_content&lt;/strong&gt;，这样的概念性的大小。丈量并设定控件的位置，是通过两步来进行的。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;第一步是&lt;strong&gt;measure&lt;/strong&gt;。它传入此控件的width/height信息，控件会根据自己的参数，计算出真实需要的width/height，然后调用&lt;strong&gt;setMeasuredDimension&lt;/strong&gt;方法，缓存成成员变量，留作后用。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;在计算出大小之后，会进行另一个步骤，&lt;strong&gt;layout&lt;/strong&gt;。在这个过程中，父控件会计算其上各个子控件的位置，从而完成整个大小和位置的确定流程。整个measure和layout的流程，都是自上到下，从树顶往叶子来推进的。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;当开发人员需要自定义控件的时候，可能需要关注这些内容，通过重载&lt;strong&gt;onMeasure&lt;/strong&gt;和&lt;strong&gt;onLayout&lt;/strong&gt;方法，可以定义自己控件的丈量方式。&lt;/div&gt;&lt;h4 style="font-size: 10pt; "&gt;事件&lt;/strong&gt;&lt;/p&gt;在Android中，所有的按键，触屏等事件，都是从顶至下进行分发的。每个ViewGroup的对象，会维系一个&lt;strong&gt;focused&lt;/strong&gt;变量，它表示在这个父控件中具备focus的控件，当有按键时间发生的时候，会找到这个focused子控件，并传递给它。同理，触屏事件的分发也是类似，只不过和focus无关，父控件会遍历所有子控件，看看谁处于触碰位置，从而传递给谁。&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;另外还有一些事件，逻辑上并不是从顶至下发起的。比如，当你修改某个子控件的内容，使得该子控件的大小和内容都发生了变化，就需要进行控件的重排和重绘，这些操作不仅是子控件自己的事情，需要整个控件树上的所有控件都需要配合。在Android中，处理这类事情的实现策略是子控件维系一个&lt;strong&gt;&lt;a href="http://developer.android.com/reference/android/view/ViewParent.html" id="u8ld" title="ViewParent" target="_blank"&gt;ViewParent&lt;/a&gt;&lt;/strong&gt;对象，该对象象征着整个控件树的管理者，子控件产生影响整个控件树的事件时，会通知到ViewParent，ViewParent会将其转换成一个自顶向下的事件，分发下去。&lt;/div&gt;Android的事件处理逻辑，采用的是观察者模式。Android的控件提供了一些列的&lt;strong&gt;add/set Listener&lt;/strong&gt;的接口，使得外部观察者，有机会处理控件事件。比如，你需要在某个button被点击时做一些事情，你就需要派生一个&lt;strong&gt;View.OnClickListener&lt;/strong&gt;对象作为观察者，调用该控件的&lt;strong&gt;setOnClickListener&lt;/strong&gt;接口注册进去，当button被点击，就可以获得处理点击事件的机会了。当然，有的时候，你需要处理的逻辑更为复杂，光是站在外面围观叫好不能解决问题，可能就需要派生某个控件，去重载&lt;strong&gt;onXXXX&lt;/strong&gt;之类的事件处理函数，进行更完整的控制。&lt;h4 style="font-size: 10pt; "&gt;焦点&lt;/strong&gt;&lt;/p&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;对于一个非触屏的机器，焦点的维系是一个极其重要的事情，而在有触屏的年代，焦点的地位虽有所下降，但依然还是需要妥善保护的。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;Android中，是以控件树为单位，来管理焦点的。每个控件，可以设置&lt;strong&gt;上下左右四向&lt;/strong&gt;的focus转移对象。当在一个控件上发生焦点转移事件，Android会如前述，自顶向下根据设定好的焦点转移逻辑，跳转到正确的控件上。和Symbian相比，真是，真是。。。&lt;/div&gt;&lt;h4 style="font-size: 10pt; "&gt;Layout&lt;/strong&gt;&lt;/p&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;Layout是一类特殊的ViewGroup控件，它们本身没有任何可显示内容，形如透明的玻璃盒子，存活的唯一理由，就是其中的内部结构，能够更好的摆放它的子控件们。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;比如线性的Layout，&lt;strong&gt;&lt;a href="http://androidappdocs.appspot.com/reference/android/widget/LinearLayout.html" id="z1_d" title="LinearLayout" style="color: #551a8b; " target="_blank"&gt;LinearLayout&lt;/a&gt;&lt;/strong&gt;。放入这个Layout的子控件，会按水平或垂直方向，排排坐，一个挨着一个按顺序排列下去。&lt;strong&gt;&lt;a href="http://androidappdocs.appspot.com/reference/android/widget/LinearLayout.html" id="m.m1" title="TableLayout" style="color: #551a8b; " target="_blank"&gt;TableLayout&lt;/a&gt;&lt;/strong&gt;，可以将子控件按照表格的形式，一枚枚放置好。而&lt;strong&gt;&lt;a href="http://androidappdocs.appspot.com/reference/android/widget/RelativeLayout.html" id="pn_c" title="RelativeLayout" style="color: #551a8b; " target="_blank"&gt;RelativeLayout&lt;/a&gt;&lt;/strong&gt;则更灵活，可以设定各个控件之间的对齐和排列关系，适合定制复杂的界面。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;有了Layout的存在，控件和控件之间不再割裂的存在，而是更有机的结合在了一起，设定起来也更为方便。比Symbian那样人肉维系各个控件的关系，轻松自在多了。&lt;/div&gt;&lt;h4 style="font-size: 10pt; "&gt;更多&lt;/strong&gt;&lt;/p&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;这些问题的完整答案，参见SDK中View的页面：&lt;a href="http://androidappdocs.appspot.com/reference/android/view/View.html" id="f8j5" title="/reference/android/view/View.html" style="color: #551a8b; " target="_blank"&gt;/reference/android/view/View.html&lt;/a&gt;。&lt;br /&gt;&lt;br /&gt;&lt;h2 style="font-size: 14pt; "&gt;实现&lt;/strong&gt;&lt;/p&gt;有了这些对Android的UI控件的认知，可以看更整体性的实现细节，那就是Activity的UI实现。&lt;/div&gt;&lt;br /&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/duguguiyu/sIVImeFxoNuobDB_V7TQmMg.png" width="600" height="407" alt="" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;如上图所示，假设你做了个如同虚线框中结构的一个界面，通过Activity的&lt;strong&gt;setContentView&lt;/strong&gt;方法，塞进了Activity中，就会形成图示的一个逻辑关系。每一个Activity，都包含一个&lt;a href="http://androidappdocs.appspot.com/reference/android/view/Window.html" id="nxs-" title="Window" style="color: #551a8b; " target="_blank"&gt;&lt;strong&gt;Window&lt;/strong&gt;&lt;/a&gt;对象，它表示的是一个顶级的一整屏幕上面的界面逻辑。在Android源码中，其实现是&lt;strong&gt;MidWindow&lt;/strong&gt;，它包含了一个&lt;strong&gt;&lt;a href="http://androidappdocs.appspot.com/reference/android/widget/FrameLayout.html" id="kmzd" title="FrameLayout" style="color: #551a8b; " target="_blank"&gt;FrameLayout&lt;/a&gt;&lt;/strong&gt;对象，呈现出来就是那种带着一个title的界面样子。自定义的一堆控件，会插进Window的界面部分，在Activity中，所有事件的处理逻辑，是Window先享用，没消费掉在交由这堆控件吃剩的。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;在整个控件树的最顶端，是一个逻辑的树顶，&lt;strong&gt;&lt;a href="http://androidappdocs.appspot.com/reference/android/view/ViewParent.html" id="yb1o" title="ViewParent" style="color: #551a8b; " target="_blank"&gt;ViewParent&lt;/a&gt;&lt;/strong&gt;，在源码中的实现是&lt;strong&gt;ViewRoot&lt;/strong&gt;。它是整个控件树和&lt;strong&gt;&lt;a href="http://androidappdocs.appspot.com/reference/android/view/WindowManager.html" id="kulm" title="WindowManager" style="color: #551a8b; " target="_blank"&gt;WindowManager&lt;/a&gt;&lt;/strong&gt;之间的事件信息的翻译者。WindowManager是Android中一个重要的服务。它将用户的操作，翻译成为指令，发送给呈现在界面上的各个Window。Activity，会将顶级的控件注册到WindowManager中，当用户真是触碰屏幕或键盘的时候，WindowManager就会通知到，而当控件有一些请求产生，也会经由ViewParent送回到WindowManager中。从而完成整个通信流程。&lt;/div&gt;&lt;/span&gt;&lt;img src="http://www.cnblogs.com/duguguiyu/aggbug/1698515.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/duguguiyu/archive/2010/03/27/1698515.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/duguguiyu/archive/2010/02/22/1671547.html</id><title type="text">深入Android 【五】 —— 任务和进程</title><summary type="text">任务、进程和线程关于Android中的组件和应用，之前涉及，大都是静态的概念。而当一个应用运行起来，就难免会需要关心进程、线程这样的概念。在Android中，组件的动态运行，有一个最与众不同的概念，就是Task，翻译成任务，应该还是比较顺理成章的。Task的介入，最主要的作用，是将组件之间的连接，从进程概念的细节中剥离出来，可以以一种不同模型的东西进行配置，在很多时候，能够简化上层开发人员的理解难...</summary><published>2010-02-22T14:25:00Z</published><updated>2010-02-22T14:25:00Z</updated><author><name>duguguiyu</name><uri>http://www.cnblogs.com/duguguiyu/</uri></author><link rel="alternate" href="http://www.cnblogs.com/duguguiyu/archive/2010/02/22/1671547.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/duguguiyu/archive/2010/02/22/1671547.html"/><content type="html">&lt;span  style="font-family: Verdana; line-height: normal; font-size: 13px; "&gt;&lt;h1 style="font-size: 18pt; "&gt;&lt;font  face="Georgia"&gt;&lt;font  size="6"&gt;任务、进程和线程&lt;/font&gt;&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;关于Android中的组件和应用，之前涉及，大都是静态的概念。而当一个应用运行起来，就难免会需要关心进程、线程这样的概念。在Android中，组件的动态运行，有一个最与众不同的概念，就是Task，翻译成任务，应该还是比较顺理成章的。&lt;br /&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;Task的介入，最主要的作用，是将组件之间的连接，从进程概念的细节中剥离出来，可以以一种不同模型的东西进行配置，在很多时候，能够简化上层开发人员的理解难度，帮助大家更好的进行开发和配置。&lt;/div&gt;&lt;br /&gt;&lt;h2 style="font-size: 14pt; "&gt;任务&lt;/strong&gt;&lt;/p&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;在SDK中关于&lt;strong&gt;&lt;a href="http://androidappdocs.appspot.com/guide/topics/fundamentals.html#acttask" id="tfuk" title="Task" style="color: #551a8b; " target="_blank"&gt;Task&lt;/a&gt;&lt;/strong&gt;（&lt;strong&gt;guide/topics/fundamentals.html#acttask&lt;/strong&gt;），有一个很好的比方，说，Task就相当于应用（&lt;strong&gt;application&lt;/strong&gt;）的概念。在开发人员眼中，开发一个Android程序，是做一个个独门独户的组件，但对于一般用户而言，它们感知到的，只是一个运行起来的整体应用，这个整体背后，就是Task。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;Task，简单的说，就是&lt;strong&gt;一组以栈的模式聚集在一起的Activity组件集合&lt;/strong&gt;。它们有潜在的前后驱关联，新加入的Activity组件，位于栈顶，并仅有在栈顶的Activity，才会有机会与用户进行交互。而当栈顶的Activity完成使命退出的时候，Task会将其退栈，并让下一个将跑到栈顶的Activity来于用户面对面，直至栈中再无更多Activity，Task结束。&lt;/div&gt;&lt;br /&gt;&lt;div align="center" style="margin-top: 0px; margin-bottom: 0px; "&gt;&lt;table border="1" bordercolor="#000000" cellpadding="5" cellspacing="0" id="fl1q" width="100%" style="font-size: 1em; line-height: inherit; border-collapse: collapse; "&gt;&lt;tbody&gt;&lt;tr style="text-align: left; "&gt;&lt;td width="50%" style="text-align: center; "&gt;&lt;strong&gt;事件&lt;/strong&gt;&lt;/td&gt;&lt;td width="50%" style="text-align: center; "&gt;&lt;strong&gt;Task栈（粗体为栈顶组件）&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style="text-align: left; "&gt;&lt;td width="50%"&gt;点开Email应用，进入收件箱（Activity A）&lt;/td&gt;&lt;td width="50%"&gt;&lt;strong&gt;A&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style="text-align: left; "&gt;&lt;td width="50%"&gt;选中一封邮件，点击查看详情（Activity B）&lt;/td&gt;&lt;td width="50%"&gt;A&lt;strong&gt;B&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style="text-align: left; "&gt;&lt;td width="50%"&gt;点击回复，开始写新邮件（Activity C）&lt;/td&gt;&lt;td width="50%"&gt;AB&lt;strong&gt;C&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style="text-align: left; "&gt;&lt;td width="50%"&gt;写了几行字，点击选择联系人，进入选择联系人界面（Activity D）&lt;/td&gt;&lt;td width="50%"&gt;ABC&lt;strong&gt;D&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style="text-align: left; "&gt;&lt;td width="50%"&gt;选择好了联系人，继续写邮件&lt;/td&gt;&lt;td width="50%"&gt;AB&lt;strong&gt;C&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style="text-align: left; "&gt;&lt;td width="50%"&gt;写好邮件，发送完成，回到原始邮件&lt;/td&gt;&lt;td width="50%"&gt;A&lt;strong&gt;B&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style="text-align: left; "&gt;&lt;td width="50%"&gt;点击返回，回到收件箱&lt;/td&gt;&lt;td width="50%"&gt;&lt;strong&gt;A&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style="text-align: left; "&gt;&lt;td width="50%"&gt;退出Email程序&lt;/td&gt;&lt;td width="50%"&gt;null&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;如上表所示，是一个实例。从用户从进入邮箱开始，到回复完成，退出应用整个过程的Task栈变化。这是一个标准的栈模式，对于大部分的状况，这样的Task模型，足以应付，但是，涉及到实际的性能、开销等问题，就会变得残酷许多。比如，启动一个浏览器，在Android中是一个比较沉重的过程，它需要做很多初始化的工作，并且会有不小的内存开销。但与此同时，用浏览器打开一些内容，又是一般应用都会有的一个需求。设想一下，如果同时有十个运行着的应用（就会对应着是多个Task），都需要启动浏览器，这将是一个多么残酷的场面，十个Task栈都堆积着很雷同的浏览器Activity，是多么华丽的一种浪费啊。于是你会有这样一种设想，浏览器Activity，可不可以作为一个单独的Task而存在，不管是来自那个Task的请求，浏览器的Task，都不会归并过去。这样，虽然浏览器Activity本身需要维系的状态更多了，但整体的开销将大大的减少，这种舍小家为大家的行为，还是很值得歌颂的。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;如此值得歌颂的行为，Android当然会举双手支持的。在Android中，每一个Activity的Task模式，都是可以由&lt;strong&gt;Activity提供方&lt;/strong&gt;（通过配置文件...）和&lt;strong&gt;Activity使用方&lt;/strong&gt;（通过Intent中的flag信息...）进行配置和选择。当然，使用方对Activity的控制力，是限定在提供方允许的范畴内进行，提供方明令禁止的模式，使用方是不能够越界使用的。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;在SDK中（&lt;strong&gt;&lt;a href="http://androidappdocs.appspot.com/guide/topics/fundamentals.html#acttask" id="tx4q" title="guide/topics/fundamentals.html#acttask" style="color: #551a8b; " target="_blank"&gt;guide/topics/fundamentals.html#acttask&lt;/a&gt;&lt;/strong&gt;），将两者实现Task模式配置的方式，写的非常清晰了，我再很絮叨挑选一些来解释一下（完整可配置项，一定要看SDK，下面只是其中常用的若干项...）。提供方对组件的配置，是通过&lt;strong&gt;配置文件&lt;/strong&gt;（Manifest）&lt;strong&gt;&amp;lt;activity&amp;gt;&lt;/strong&gt;项来进行的，而调用方，则是通过&lt;strong&gt;Intent对象的flag&lt;/strong&gt;进行抉择的。相对于标准的Task栈的模式，配置的主要方向有两个：一则是破坏已有栈的进出规则，或样式；另一则是开辟新Task栈完成本应在同一Task栈中完成的任务。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;对于应用开发人员而言，&amp;lt;activity&amp;gt;中的&lt;strong&gt;launchMode&lt;/strong&gt;属性，是需要经常打交道的。它有四种模式："&lt;strong&gt;standard&lt;/strong&gt;", "&lt;strong&gt;singleTop&lt;/strong&gt;", "&lt;strong&gt;singleTask&lt;/strong&gt;", "&lt;strong&gt;singleInstance&lt;/strong&gt;"。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;&lt;strong&gt;standard模式&lt;/strong&gt;， 是默认的也是标准的Task模式，在没有其他因素的影响下，使用此模式的Activity，会构造一个Activity的实例，加入到调用者的Task栈中去，对于使用频度一般开销一般什么都一般的Activity而言，standard模式无疑是最合适的，因为它逻辑简单条理清晰，所以是默认的选择。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;而&lt;strong&gt;singleTop模式&lt;/strong&gt;，基本上于standard一致，仅在请求的Activity&lt;strong&gt;正好位于栈顶&lt;/strong&gt;时，有所区别。此时，配置成singleTop的Activity，不再会构造新的实例加入到Task栈中，而是将新来的Intent发送到栈顶Activity中，栈顶的Activity可以通过重载&lt;strong&gt;onNewIntent&lt;/strong&gt;来处理新的Intent（当然，也可以无视...）。这个模式，降低了位于栈顶时的一些重复开销，更避免了一些奇异的行为（想象一下，如果在栈顶连续几个都是同样的Activity，再一级级退出的时候，这是怎么样的用户体验...），很适合一些会有更新的列表Activity展示。一个活生生的实例是，在Android默认提供的应用中，浏览器（Browser）的书签Activity（&lt;strong&gt;BrowserBookmarkPage&lt;/strong&gt;），就用的是singleTop。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;singleTop模式，虽然破坏了原有栈的逻辑（复用了栈顶，而没有构造新元素进栈...），但并未开辟专属的Task。而singleTask，和singleInstance，则都采取的另辟Task的蹊径。&lt;strong&gt;标志为singleTask的Activity&lt;/strong&gt;，最多仅有一个实例存在，并且，位于&lt;strong&gt;以它为根的Task&lt;/strong&gt;中。所有对该Activity的请求，都会跳到该Activity的Task中展开进行。singleTask，很象概念中的单件模式，所有的修改都是基于一个实例，这通常用在构造成本很大，但切换成本较小的Activity中。在Android源码提供的应用中，该模式被广泛的采用，最典型的例子，还是浏览器应用的主Activity（名为Browser...），它是展示当前tab，当前页面内容的窗口。它的构造成本大，但页面的切换还是较快的，于singleTask相配，还是挺天作之合的。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;相比之下，&lt;strong&gt;singleInstance&lt;/strong&gt;显得更为极端一些。在大部分时候singleInstance与singleTask完全一致，唯一的不同在于，singleInstance的Activity，是它所在栈中&lt;strong&gt;仅有的一个Activity&lt;/strong&gt;，如果涉及到的其他Activity，都移交到其他Task中进行。这使得singleInstance的Activity，像一座孤岛，彻底的黑盒，它不关注请求来自何方，也不计较后续由谁执行。在Android默认的各个应用中，很少有这样的Activity，在我个人的工程实践中，曾尝试在&lt;strong&gt;&lt;a href="http://m.youdao.com/help/cidian" id="dh6:" title="有道词典" style="color: #551a8b; " target="_blank"&gt;有道词典&lt;/a&gt;&lt;/strong&gt;的&lt;strong&gt;快速取词Activity&lt;/strong&gt;中采用过，是因为我觉得快速取词入口足够方便（从notification中点选进入），并且会在各个场合使用，应该做得完全独立。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;除了launchMode可以用来调配Task，&amp;lt;activity&amp;gt;的另一属性&lt;strong&gt;taskAffinity&lt;/strong&gt;，也是常常被使用。taskAffinity，是一种物以类聚的思想，它倾向于将taskAffinity属性相同的Activity，扔进同一个Task中。不过，它的约束力，较之launchMode而言，弱了许多。只有当&amp;lt;activity&amp;gt;中的&lt;strong&gt;allowTaskReparen ting&lt;/strong&gt;设置为true，抑或是调用方将Intent的flag添加&lt;strong&gt;FLAG_ACTIVITY_NEW_TASK&lt;/strong&gt;属性时才会生效。如果有机会用到Android的Notification机制就能够知道，每一个由notification进行触发的Activity，都必须是一个设成FLAG_ACTIVITY_NEW_TASK的Intent来调用。这时候，开发者很可能需要妥善配置taskAffinity属性，使得调用起来的Activity，能够找到组织，在同一taskAffinity的Task中进行运行。&lt;/div&gt;&lt;br /&gt;&lt;h2 style="font-size: 14pt; "&gt;进程&lt;/strong&gt;&lt;/p&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;在大多数其他平台的开发中，每个开发人员对自己应用的进程模型都有非常清晰的了解。比如，一个控制台程序，你可以想见它从main函数开始启动一个进程，到main函数结束，进程执行完成退出；在UI程序中，往往是有一个消息循环在跑，当接受到Exit消息后，退出消息循环结束进程。在该程序运行过程中，启动了什么进程，和第三方进程进行通信等等操作，每个开发者都是心如明镜一本帐算得清清楚楚。进程边界，在这里，犹如国界一般，每一次穿越都会留下深深的印迹。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;在Android程序中，开发人员可以直接感知的，往往是Task而已。倍感清晰的，是组件边界，而进程边界变得难以琢磨，甚至有了进程托管一说。Android中不但剥夺了手工锻造内存权力，连手工处置进程的权责，也毫不犹豫的独占了。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;当然，Android隐藏进程细节，并不是刻意为之，而是自然而然水到渠成的。如果，我们把传统的应用称为&lt;strong&gt;面向进程的开发&lt;/strong&gt;，那么，在Android中，我们做得就是&lt;strong&gt;面向组件的开发&lt;/strong&gt;。从前面的内容可以知道，Android组件间的跳转和通信，都是在&lt;strong&gt;第三方介入&lt;/strong&gt;的前提下进行，正由于这种介入，使得两个组件一般不会直接发生联系（于Service的通信，是不需要第三方介入的，因此Android把它全部假设成为穿越进程边界，统一基于RPC来通信，这样，也是为了掩盖进程细节...），其中是否穿越进程边界也就变得不重要。因此，如果这时候，还需要开发者关注进程，就会变得很奇怪，很费解，干脆，Android将所有的进程一并托管去了，上层无须知道进程的生死和通信细节。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;在Android的底层，进程构造了底部的一个&lt;strong&gt;运行池&lt;/strong&gt;，不仅仅是Task中的各个Activity组件，其他三大组件Service、Content Provider、Broadcast Receiver，都是&lt;strong&gt;寄宿&lt;/strong&gt;在底层某个进程中，进行运转。在这里，进程更像一个&lt;strong&gt;资源池&lt;/strong&gt;（概念形如线程池，上层要用的时候取一个出来就好，而不关注具体取了哪一个...），只是为了承载各个组件的运行，而各个组件直接的逻辑关系，它们并不关心。但我们可以想象，为了保证整体性，在默认情况下，Android肯定倾向于&lt;strong&gt;将同一Task、同一应用的各个组件扔进同一个进程内&lt;/strong&gt;，但是当然，出于效率考虑，Android也是允许开发者进行配置。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;在Android中，整体的&lt;strong&gt;&amp;lt;application&amp;gt;&lt;/strong&gt;（将影响其中各个组件...）和底下各个组件，都可以设置&lt;strong&gt;&amp;lt;process&amp;gt;&lt;/strong&gt;属性，相同&amp;lt;process&amp;gt;属性的组件将扔到&lt;strong&gt;同一个进程&lt;/strong&gt;中运行。最常见的使用场景，是通过配置&amp;lt;application&amp;gt;的process属性，将不同的相关应用，塞进一个进程，使得它们可以同生共死。还有就是将经常和某个&lt;strong&gt;Service组件&lt;/strong&gt;进行通信的组件，放入同一个进程，因为与Service通信是个密集操作，走的是RPC，开销不小，通过配置，可以变成进程内的直接引用，消耗颇小。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;除了通过&amp;lt;process&amp;gt;属性，不同的组件还有一些特殊的配置项，以&lt;strong&gt;Content Provider&lt;/strong&gt;为例（通过&lt;strong&gt;&amp;lt;provider&amp;gt;&lt;/strong&gt;项进行配置...）。&amp;lt;provider&amp;gt;项有一个&lt;strong&gt;mutiprocess&lt;/strong&gt;的属性，默认值为false，这意味着Content Provider，仅会在提供该组件的应用&lt;strong&gt;所在进程构造一个实例&lt;/strong&gt;，第三方想使用就需要经由RPC传输数据。这种模式，对于构造开销大，数据传输开销小的场合是非常适用的，并且可能提高缓存的效果。但是，如果是数据传输很大，抑或是希望在此提高传输的效率，就需要将mutiprocess设置成true，这样，Content Provider就会在每一个调用它的进程中构造一个实例，&lt;strong&gt;避免进程通信的开销&lt;/strong&gt;。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;既然，是Android系统帮助开发人员托管了进程，那么就需要有一整套纷繁的算法去执行回收逻辑。Android中各个进程的生死，和运行在其中的各个组件有着密切的联系，进程们依照其上组件的特点，被排入一个&lt;strong&gt;优先级体系&lt;/strong&gt;，在需要回收时，从低优先级到高优先级回收。Android进程共分为五类优先级，分别是：&lt;strong&gt;Foreground Process&lt;/strong&gt;,&amp;nbsp;&lt;strong&gt;Visible Process&lt;/strong&gt;,&amp;nbsp;&lt;strong&gt;Service Process&lt;/strong&gt;,&amp;nbsp;&lt;strong&gt;Background Process&lt;/strong&gt;,&amp;nbsp;&lt;strong&gt;Empty Process&lt;/strong&gt;。顾名思义不难看出，这说明，&lt;strong&gt;越和用户操作紧密相连的，越是正与用户交互的，优先级越高，越难被回收&lt;/strong&gt;。具体详情，参见：&lt;strong&gt;&lt;a href="http://androidappdocs.appspot.com/guide/topics/fundamentals.html#proclife" id="tttj" title="guide/topics/fundamentals.html#proclife" style="color: #551a8b; " target="_blank"&gt;guide/topics/fundamentals.html#proclife&lt;/a&gt;&lt;/strong&gt;。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;有了优先级，还需要有良好的&lt;strong&gt;回收时机&lt;/strong&gt;。回收太早，缓存命中概率低可能引起不断的创造进程销毁进程，池的优势荡然无存；回收的太晚，整体开销大，系统运行效率降低，好端端的法拉利可能被糟蹋成一枚QQ老爷车。Android的进程回收，最重要的是考量&lt;strong&gt;内存开销&lt;/strong&gt;，以及电量等其他资源状况，此外每个进程承载的组件数量、单个应用开辟的进程数量等&lt;strong&gt;数量指标&lt;/strong&gt;，也是作为衡量的一个重要标识。另外，一些运行时的&lt;strong&gt;时间开销&lt;/strong&gt;，也被严格监控，启动慢的进程会很被强行kill掉。Android会&lt;strong&gt;定时检查&lt;/strong&gt;上述参数，也会在一些很&lt;strong&gt;可能发生进程回收的时间点&lt;/strong&gt;，比如某个组件执行完成后，来做回收的尝试。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;从用户体验角度来看，Android的进程机制，会有很可喜的一面，有的程序启动速度很慢，但是在资源充沛的前提下，你反复的退出再使用，则启动变得极其快速（进程没死，只是从后台弄到了前台），这就是拜进程托管所赐的。当然，可喜的另一面就是可悲了，Android的托管算法，还时不时的展现其幼稚的一面，明明用户已经明显感觉到操作系统运行速度下降了，打开任务管理器一看，一票应用还生龙活虎的跳跃着，必须要手动帮助它们终结生命找到坟墓，这使得任务管理器基本成为Android的装机必备软件。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;从开发角度上来看，Android这套进程机制，解放了开发者的手脚。开发人员不需要处心积虑的构造一个后台进程偷偷默默监听某个时间，并尝试用各种各样的守护手段，把自己的进程锻造的犹如不死鸟一辉一般，进程生死的问题，已经原理了普通开发人员需要管理的范畴内。但同时，于GC和人肉内存管理的争议一样，所有开发人员都不相信算法能比自己做得效率更高更出色。但我一直坚信一点，&lt;strong&gt;所有效率的优势都会随着算法的不断改良硬件的不断提升而消失殆尽，只有开发模式的简洁不会随时间而有任何变化&lt;/strong&gt;。&lt;/div&gt;&lt;br /&gt;&lt;h2 style="font-size: 14pt; "&gt;组件生命周期&lt;/strong&gt;&lt;/p&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;任何架构上的变化，都会引起上层开发模式的变化，Android的进程模型，虽然使开发者不再需要密切关注进程的创建和销毁的时机，但仍然需要关注这些时间点对组件的影响。比如，你可能需要在进程销毁之前，将写到内存上的内容，持久化到硬盘上，这就需要关注进程退出前发生的一些事件。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;在Android中，把握这些时间点，就必须了解&lt;strong&gt;组件生命周期&lt;/strong&gt;（&lt;strong&gt;Components Lifecycles&lt;/strong&gt;）。所谓组件的生命在周期，就是在组件在前后台切换、被用户创建退出、被系统回收等等事件发生的时候，会有一些事件通知到对应组件上，开发人员可以选择性的处理这些事件在对应的时间点上来完成一些附加工作。&lt;/div&gt;除Content Provider，其他组件都会有生命周期的概念，都需要依照这个模型定时定点处理一些状况，全部内容参见：&lt;strong&gt;&lt;a href="http://androidappdocs.appspot.com/guide/topics/fundamentals.html#lcycles" id="ioud" title="guide/topics/fundamentals.html#lcycles" style="color: #551a8b; " target="_blank"&gt;guide/topics/fundamentals.html#lcycles&lt;/a&gt;&lt;/strong&gt;。在这里，擒贼先擒王，还是拿Activity出来作楷模。&lt;br /&gt;&lt;br /&gt;&lt;div id="eq5w" style="margin-top: 0px; margin-bottom: 0px; text-align: left; "&gt;&lt;img src="http://androidappdocs.appspot.com/images/activity_lifecycle.png" alt="" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;继续偷图，来自SDK。一个自然的Activity生命旅途，从&lt;strong&gt;onCreate&lt;/strong&gt;开始，到&lt;strong&gt;onDestroy&lt;/strong&gt;消亡。但月有阴晴圆缺组件有祸福旦夕，在系统需要的时候且组件位于后台时，所在的进程随时可能为国捐躯被回收，这就使得知道切入后台这个事情也变得很重要。&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;当组件进入栈顶，与用户开始交互，会调用&lt;strong&gt;onResume&lt;/strong&gt;函数，类似，当退出栈顶，会有&lt;strong&gt;onPause&lt;/strong&gt;函数被呼唤。onResume和onPause可以处理很多事情，最常规的，就是做一些文件或设置项的读写工作。因为，在该组件不再前台运行的时候，可能别的组件会需要读写同样一份文件和设置，如果不再onResume做刷新工作，用的可能就是一份脏数据了（当然，具体情况，还需要具体分析，如果文件不会被多头读写，可以放到onCreate里面去做读工作）。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;除了前述切入后台会被其他组件骚扰的问题，另外，死无定因也是件很可怕的事情。在Android中，组件都有两种常见的死法，一种是&lt;strong&gt;自然消亡&lt;/strong&gt;，比如，栈元素ABC，变成AB了，C组件就自然消亡了。这种死发轻如鸿毛，不需要额外关心。但另一种情况，就是被&lt;strong&gt;系统回收&lt;/strong&gt;，那是死的重如泰山，为国捐躯嘛。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;但这种捐躯的死法，对用户来说，比较费解。想象一下，一款游戏，不能存盘，你一直玩啊玩，三天三夜没合眼，这时候你mm打来电话鼓励一下，你精神抖擞的准备再接再厉，却发现你的游戏进程，在切入后台之后，被系统回收了，一夜回到解放前三天努力成为一场泡影，你会不会想杀做游戏的人，会不会会不会会不会，一定会嘛。这时候，如果没有Activity生命周期这码事，游戏程序员一定是被冤死的，成了Android的替罪羊。但是，Android的组件是有生命周期的，如果真的发生这样情况，不要犹豫，去杀开发的程序员吧。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;为了逃生，程序员们有一块免死金牌，那就是Android的&lt;strong&gt;state机制&lt;/strong&gt;。所谓state，就是开发人员将一些当前运行的状态信息存放在一个&lt;strong&gt;&lt;a href="http://androidappdocs.appspot.com/reference/android/os/Bundle.html" id="lnp6" title="Bundle" style="color: #551a8b; " target="_blank"&gt;Bundle&lt;/a&gt;&lt;/strong&gt;对象里面，这是一个&lt;strong&gt;可序列化键值对集合&lt;/strong&gt;。如果该Activity组件所处的进程需要回收，Android核心会将其上Activity组件的Bundle对象&lt;strong&gt;持久化到磁盘&lt;/strong&gt;上，当用户回到该Activity时候，系统会重新构造该组件，并将持久化到磁盘上的Bundle对象恢复。有了这样的持久化的状态信息，开发人员可以很好的区分具体死法，并有机会的使得死而复生的Activity恢复到死前状态。开发者应该做的，是通过&lt;strong&gt;onSaveInstanceState&lt;/strong&gt;函数把需要维系的状态信息（在默认的状态下，系统控件都会自己保存相关的状态信息，比如TextView，会保存当前的Text信息，这都不需要开发人员担心...），写入到Bundle对象，然后在&lt;strong&gt;onRestoreInstanceState&lt;/strong&gt;函数中读取并恢复相关信息（&lt;strong&gt;onCreate&lt;/strong&gt;，&lt;strong&gt;onStart&lt;/strong&gt;，也都可以处理...）。&lt;/div&gt;&lt;br /&gt;&lt;h2 style="font-size: 14pt; "&gt;线程&lt;/strong&gt;&lt;/p&gt;读取数据，后台处理，这些猥琐的伙计，自然少不了线程的参与。在Android核心的调度层面，是不屑于考量线程的，它关注的只有进程，每一个组件的构造和处理，都是在&lt;strong&gt;进程的主线程&lt;/strong&gt;上做的，这样可以保证逻辑的足够简单。多线程，往往都是开发人员需要做的。&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;Android的线程，也是通过派生Java的&lt;strong&gt;Thread&lt;/strong&gt;对象，实现&lt;strong&gt;Run&lt;/strong&gt;方法来实现的。但当用户需要跑一个具有消息循环的线程的时候，Android有更好的支持，来自于&lt;strong&gt;&lt;a href="http://androidappdocs.appspot.com/reference/android/os/Handler.html" id="h9ds" title="Handler" style="color: #551a8b; " target="_blank"&gt;Handler&lt;/a&gt;&lt;/strong&gt;和&lt;strong&gt;&lt;a href="http://androidappdocs.appspot.com/reference/android/os/Looper.html" id="s2r2" title="Looper" style="color: #551a8b; " target="_blank"&gt;Looper&lt;/a&gt;&lt;/strong&gt;。Handler做的是消息的传送和分发，派生其&lt;strong&gt;handleMessage&lt;/strong&gt;函数，可以处理各种收到的消息，和win开发无异。Looper的任务，则是构造循环，等候退出或其他消息的来临。在Looper的&lt;a href="http://androidappdocs.appspot.com/reference/android/os/Looper.html" id="gpme" title="SDK页面" style="color: #551a8b; " target="_blank"&gt;SDK页面&lt;/a&gt;，有一个消息循环线程实现的标准范例，当然，更为标准的方式也许是构造一个&lt;strong&gt;&lt;a href="http://androidappdocs.appspot.com/reference/android/os/HandlerThread.html" id="dsk." title="HandlerThread" style="color: #551a8b; " target="_blank"&gt;HandlerThread&lt;/a&gt;&lt;/strong&gt;线程，将它的Looper传递给Handler。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;在Android中，&lt;strong&gt;Content Provider&lt;/strong&gt;的使用，往往和线程挂钩，谁让它和数据相关呢。在&lt;a href="http://www.cnblogs.com/duguguiyu/archive/2010/01/30/1659980.html" id="a2eu" title="前面" style="color: #551a8b; " target="_blank"&gt;前面&lt;/a&gt;提到过，Content Provider为了保持更多的灵活性，本身只提供了同步调用的接口，而由于异步对Content Provider进行增删改查是一个常做操作，Android通过&lt;strong&gt;&lt;a href="http://androidappdocs.appspot.com/reference/android/content/AsyncQueryHandler.html" id="r_qm" title="AsyncQueryHandler" style="color: #551a8b; " target="_blank"&gt;AsyncQueryHandler&lt;/a&gt;&lt;/strong&gt;对象，提供了异步接口。这是一个Handler的子类，开发人员可以调用&lt;strong&gt;startXXX&lt;/strong&gt;方法发起操作，通过派生&lt;strong&gt;onXXXComplete&lt;/strong&gt;方法，等待执行完毕后的回调，从而完成整个异步调用的流程，十分的简约明了。&lt;br /&gt;&lt;br /&gt;&lt;h2 style="font-size: 14pt; "&gt;实现&lt;/strong&gt;&lt;/p&gt;整个任务、进程管理的核心实现，尽在&lt;strong&gt;ActivityManagerService&lt;/strong&gt;中。&lt;a href="http://www.cnblogs.com/duguguiyu/archive/2010/02/07/1665544.html" id="u4_x" title="上一篇" style="color: #551a8b; " target="_blank"&gt;上一篇&lt;/a&gt;说到，Intent解析，就是这个ActivityManagerService来负责的，其实，它是一个很名不副实的类，因为虽然名为Activity的Manager Service，但它管辖的范围，不只是Activity，还有其他三类组件，和它们所在的进程。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;在ActivityManagerService中，有两类数据结构最为醒目，一个是&lt;strong&gt;ArrayList&lt;/strong&gt;，另一个是&lt;strong&gt;HashMap&lt;/strong&gt;。ActivityManagerService有大量的ArrayList，每一个组件，会有多个ArrayList来分状态存放。调度工作，往往就是从一个ArrayList里面拿出来，找个方法调一调，然后扔到另一个ArrayList里面去，当这个组件没对应的ArrayList放着的时候，说明它离死不远了。HashMap，是因为有组件是需要用名字或Intent信息做定位的，比如Content Provider，它的查找，都是依据Uri，有了HashMap，一切都顺理成章了。&lt;/div&gt;ActivityManagerService用一些名曰&lt;strong&gt;xxxRecord&lt;/strong&gt;的数据结构，来表达各个存活的组件。于是就有了，&lt;strong&gt;HistoryRecord&lt;/strong&gt;（保存Activity信息的，之所以叫History，是相对Task栈而言的...），&lt;strong&gt;ServiceRecord&lt;/strong&gt;，&lt;strong&gt;BroadcastRecord&lt;/strong&gt;，&lt;strong&gt;ContentProviderRecord&lt;/strong&gt;，&lt;strong&gt;TaskRecord&lt;/strong&gt;，&lt;strong&gt;ProcessRecord&lt;/strong&gt;，等等。&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;值得注意的，是TaskRecord，我们一直再说，Task栈这样的概念，其实，真实的底层，并不会在TaskRecord中，维系一个Activity的栈。在ActivityManagerService中，各个任务的Activity，都以HistoryRecord的形式，集中存放在一个ArrayList中，每个HistoryRecord，会存放它所在TaskRecord的引用。当有一个Activity，执行完成，从概念上的Task栈中退出，Android是通过从当前HistoryRecord位置往前扫描同一个TaskRecord的HistoryRecord来完成的。这个设计，使得上层很多看上去逻辑很复杂的Task体系，在实现变得很统一而简明，值得称道。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;ProcessRecord，是整个进程托管实现的核心，它存放有运行在这个进程上，所有组件的信息，根据这些信息，系统有一整套的算法来决议如何处置这个进程，如果对回收算法感兴趣，可以从ActivityManagerService的&lt;strong&gt;trimApplications&lt;/strong&gt;函数入手来看。&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;对于开发者来说，去了解这部分实现，主要是可以帮助理解整个进程和任务的概念，如果觉得这块理解的清晰了，就不用去碰ActivityManagerService这个庞然大物了。&lt;/div&gt;&lt;/span&gt;&lt;img src="http://www.cnblogs.com/duguguiyu/aggbug/1671547.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/duguguiyu/archive/2010/02/22/1671547.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/duguguiyu/archive/2010/02/07/1665544.html</id><title type="text">深入Android 【四】 —— 组件调用</title><summary type="text">Intent解析基于组件的架构体系，除了有定义良好的组件，如何把这些组件组装在一起，也是一门艺术。在Android中，Intent（貌似通常译作：意图...），就是连接各组件的桥梁。前段时间看同事们做Symbian平台的网易掌上邮（真的是做的用心，NB的一米，热情欢迎所有163邮箱的S60v3用户，猛点击之...），有个功能是为邮件添加附件，比如你想要通过邮件发送一副图片泡mm，可能需要有个很直观...</summary><published>2010-02-07T14:09:00Z</published><updated>2010-02-07T14:09:00Z</updated><author><name>duguguiyu</name><uri>http://www.cnblogs.com/duguguiyu/</uri></author><link rel="alternate" href="http://www.cnblogs.com/duguguiyu/archive/2010/02/07/1665544.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/duguguiyu/archive/2010/02/07/1665544.html"/></entry><entry><id>http://www.cnblogs.com/duguguiyu/archive/2010/01/30/1659980.html</id><title type="text">深入Android 【三】 —— 组件入门</title><summary type="text">Android组件横看成岭侧成峰，远近高低各不同。 -- 《题西林壁》组件（Component），在谈及所谓架构和重用的时候，是一个重要的事情。很多时候都会说基于组件的软件架构，指的是期望把程序做乐高似的，有一堆接口标准封装完整的组件放在哪里，想用的时候取上几个一搭配，整个程序就构建完成了。在开篇的时候就在说，Android是一个为组件化而搭建的平台，它引入所谓Mash-Up的概念，这使得你在应用...</summary><published>2010-01-30T05:09:00Z</published><updated>2010-01-30T05:09:00Z</updated><author><name>duguguiyu</name><uri>http://www.cnblogs.com/duguguiyu/</uri></author><link rel="alternate" href="http://www.cnblogs.com/duguguiyu/archive/2010/01/30/1659980.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/duguguiyu/archive/2010/01/30/1659980.html"/></entry><entry><id>http://www.cnblogs.com/duguguiyu/archive/2010/01/23/1654559.html</id><title type="text">深入Android 【二】 —— 架构和学习</title><summary type="text">Android架构和特征千呼万唤始出来，犹抱琵琶半遮。 -- 《琵琶行》虽贵为富二代，但Android要是没任何可圈点的地方，开不过70迈，在玲琅满目的手机平台竞争中，充其量也就做几个俯卧撑打一桶酱油，然后被落的远远的。说到底，出来混，靠的还是技术。架构从SDK文档中，偷来一幅Android平台的架构图，如上。在整个架构最底层红彤彤的部分，是Linux Kernel在移动平台的一个移植，它隐藏了硬...</summary><published>2010-01-22T18:26:00Z</published><updated>2010-01-22T18:26:00Z</updated><author><name>duguguiyu</name><uri>http://www.cnblogs.com/duguguiyu/</uri></author><link rel="alternate" href="http://www.cnblogs.com/duguguiyu/archive/2010/01/23/1654559.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/duguguiyu/archive/2010/01/23/1654559.html"/></entry><entry><id>http://www.cnblogs.com/duguguiyu/archive/2010/01/21/1652868.html</id><title type="text">深入Android 【一】 —— 序及开篇</title><summary type="text">序携来百侣曾游，忆往昔峥嵘岁月稠。 -- 《沁园春&amp;#183;长沙》对于Android，我也算是老人了，所谓，有文有真想。正由于这段玩票经历，使得我在毕业后，鬼使神差的成为移动平台的一名码工，再次有机会放肆的拥抱Android。2010开年，手上突然有了一把闲散时间，有机会进一步总结和学习Android。于是想再一次为Android写一系列的东西，这些东西来自于一些开发经验，对源码的学习和对And...</summary><published>2010-01-20T16:56:00Z</published><updated>2010-01-20T16:56:00Z</updated><author><name>duguguiyu</name><uri>http://www.cnblogs.com/duguguiyu/</uri></author><link rel="alternate" href="http://www.cnblogs.com/duguguiyu/archive/2010/01/21/1652868.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/duguguiyu/archive/2010/01/21/1652868.html"/></entry><entry><id>http://www.cnblogs.com/duguguiyu/archive/2009/06/17/1504701.html</id><title type="text">Symbian手记【五】 —— Symbian的异步框架</title><summary type="text">永远活在同步的流程里，无疑是我等码工最大的奢望之一。为了不阻塞UI，为了读写一陀陀数据，为了含辛茹苦的演算复杂的逻辑，为了大家和睦相处共同劳动，总是需要异步处理，你一下我一下共同完成任务。在Symbian中，做了一套机制来做这件事情，这就是Active Objects。Active ObjectsActive Object是一套事件驱动的多任务模型。在Symbian的标准线程中（除掉一些Java构...</summary><published>2009-06-16T17:13:00Z</published><updated>2009-06-16T17:13:00Z</updated><author><name>duguguiyu</name><uri>http://www.cnblogs.com/duguguiyu/</uri></author><link rel="alternate" href="http://www.cnblogs.com/duguguiyu/archive/2009/06/17/1504701.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/duguguiyu/archive/2009/06/17/1504701.html"/></entry><entry><id>http://www.cnblogs.com/duguguiyu/archive/2009/06/13/1502416.html</id><title type="text">Symbian手记【四】 —— Symbian的容器</title><summary type="text">【四】 Symbian的容器Symbian在设计之初，没有拥抱STL，这就要求，它需要重新制作一些轮子，容器便是其中的一个。CArray系列容器Symbian的设计者，非常喜欢复杂的继承结构和保罗万象的类，CArray系列的容器，就是在这种理念下的产物。CArray是顺序容器，相当于STL的vector + list，以及更多。CArray系列容器，在继承的最底端，也就是可实例化使用的类，都采用C...</summary><published>2009-06-12T16:55:00Z</published><updated>2009-06-12T16:55:00Z</updated><author><name>duguguiyu</name><uri>http://www.cnblogs.com/duguguiyu/</uri></author><link rel="alternate" href="http://www.cnblogs.com/duguguiyu/archive/2009/06/13/1502416.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/duguguiyu/archive/2009/06/13/1502416.html"/></entry></feed>
