﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-Calvin's Tech Space-随笔分类-Android</title><link>http://www.blogjava.net/lihao336/category/41508.html</link><description>成于坚忍，毁于浮躁</description><language>zh-cn</language><lastBuildDate>Fri, 03 Feb 2012 02:13:07 GMT</lastBuildDate><pubDate>Fri, 03 Feb 2012 02:13:07 GMT</pubDate><ttl>60</ttl><item><title>[转]不同格式证书导入keystore方法 </title><link>http://www.blogjava.net/lihao336/archive/2012/02/03/369303.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Fri, 03 Feb 2012 02:06:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2012/02/03/369303.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/369303.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2012/02/03/369303.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/369303.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/369303.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Java																																				自带的																																																		keytool																																														工具								...&nbsp;&nbsp;<a href='http://www.blogjava.net/lihao336/archive/2012/02/03/369303.html'>阅读全文</a><img src ="http://www.blogjava.net/lihao336/aggbug/369303.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2012-02-03 10:06 <a href="http://www.blogjava.net/lihao336/archive/2012/02/03/369303.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Android exchange 账户设置</title><link>http://www.blogjava.net/lihao336/archive/2012/01/30/369036.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Mon, 30 Jan 2012 09:13:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2012/01/30/369036.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/369036.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2012/01/30/369036.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/369036.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/369036.html</trackback:ping><description><![CDATA[输入邮箱，邮箱要Gmail邮箱，就是后缀@gmail.com  输入密码后下一步,<br />关键点： “服务器”一栏，默认为gmail.com，应该改为“<font color="#FF0000">m.google.com</font>”，然后继续即可。<img src ="http://www.blogjava.net/lihao336/aggbug/369036.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2012-01-30 17:13 <a href="http://www.blogjava.net/lihao336/archive/2012/01/30/369036.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>setComponentEnabledSetting doesn't work on widget</title><link>http://www.blogjava.net/lihao336/archive/2011/12/27/367332.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Tue, 27 Dec 2011 06:14:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2011/12/27/367332.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/367332.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2011/12/27/367332.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/367332.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/367332.html</trackback:ping><description><![CDATA[PackageManager.setComponentEnabledSetting 可以用来禁用某个组件，包括activity，receiver等等。被禁用的组件会被持久化到/data/system/packages.xml中，如：<br /><br />&lt;package name="com.android.setupwizard" codePath="/system/app/SetupWizard.apk" nativeLibraryPath="/data/data/com.android.setupwizard/lib" flags="1" ft="13349457a90" it="13349457a90" ut="13349457a90" version="130" userId="10016"&gt;<br />&lt;sigs count="1"&gt;<br />&lt;cert index="0" /&gt;<br />&lt;/sigs&gt;<br />&lt;disabled-components&gt;<br />&lt;item name="com.android.setupwizard.SetupWizardActivity" /&gt;<br />&lt;/disabled-components&gt;<br />&lt;/package&gt;<br /><br />现在需要在运行时禁用某个widget，同时有一个system property用来标识是否需要禁用。<br />因为widget实际上就是个reveiver，它接收android.appwidget.action.APPWIDGET_UPDATE的action，所以开始的思路是：<br />创建一个BroadcastReceiver，接收Intent.ACTION_BOOT_COMPLETED这个动作，从而在启动完成后调用SystemProperties.get("disable_widget")，如果需要禁用这个widget，那么调用：<br />PackageManager.setComponentEnabledSetting(widgetComponentName，PackageManager.COMPONENT_ENABLED_STATE_ENABLED,<br />                PackageManager.DONT_KILL_APP);<br /><br />但是问题是，调用这个方法disable掉这个widget后，发现必须把设备重启之后才能生效...<br />经过google，发现问题出在com.android.server.AppWidgetService.java。<br />原来开机后，SystemServer会调用AppWidgetService的systemReady()方法，这个方法通过PackageManager查询所有的widget receiver组件，保存到mInstalledProviders变量列表中，并持久化widget信息到/data/system/appwidgets.xml中。<br />而在Launcher上长按添加widget时的那个widget列表信息也是通过AppWidgetService取得mInstalledProviders列表。<br />问题在于我们通过PackageManager.setComponentEnabledSetting（）禁用掉某个widget后，packagemanager确实将这个组件disable了，但是AppWidgetService却没有去从packagemanager reload widget信息，这就导致了mInstalledProviders中保存的widget信息还是开机时load进来的那些信息，并没有与pm进行同步。直到下一次开机调用systemReady重新加载widget信息才会刷新这个列表。<br /><br />参考：<br />Dynamically enabling or disabling a widget with PackageManager.setComponentEnabledSetting does not work<br />http://code.google.com/p/android/issues/detail?id=6533<br /><br />http://blog.csdn.net/yinlijun2004/article/details/6136108<br /><br /><img src ="http://www.blogjava.net/lihao336/aggbug/367332.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2011-12-27 14:14 <a href="http://www.blogjava.net/lihao336/archive/2011/12/27/367332.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Activity的onSaveInstanceState调用时机</title><link>http://www.blogjava.net/lihao336/archive/2011/11/22/364585.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Tue, 22 Nov 2011 09:56:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2011/11/22/364585.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/364585.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2011/11/22/364585.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/364585.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/364585.html</trackback:ping><description><![CDATA[http://ice-k.iteye.com/blog/1018956<br /><br />Activity的生命周期里并没有提到onSaveInstanceState的触发，这个函数提供了为我们在某些情况下保存Activity信息的机会，但需要注意的是这个函数不是什么时候都会被调用的，官方文档解释的比较清楚，特此
<br />翻译一下。
<br />原文出处：android-sdk-windows-1.5_r3/docs/reference/android/app/Activity.html#onSaveInstanceState(android.os.Bundle)
<br />protected void onSaveInstanceState (Bundle outState)
<br />       Called to retrieve per-instance state from an activity before
 being killed so that the state can be restored in onCreate(Bundle) or 
onRestoreInstanceState(Bundle) (the Bundle populated by this method will
 be passed to both). This method is called before an activity may be 
killed so that when it comes back some time in the future it can restore
 its state. For example, if activity B is launched in front of activity 
A, and at some point activity A is killed to reclaim resources, activity
 A will have a chance to save the current state of its user interface 
via this method so that when the user returns to activity A, the state 
of the user interface can be restored via onCreate(Bundle) or 
onRestoreInstanceState(Bundle).
<br /><br />    
在activity被杀掉之前调用保存每个实例的状态,以保证该状态可以在onCreate(Bundle)或者
onRestoreInstanceState(Bundle) 
(传入的Bundle参数是由onSaveInstanceState封装好的)中恢复。这个方法在一个activity被杀死前调用，当该
activity在将来某个时刻回来时可以恢复其先前状态。例如，如果activity B启用后位于activity 
A的前端，在某个时刻activity 
A因为系统回收资源的问题要被杀掉，A通过onSaveInstanceState将有机会保存其用户界面状态，使得将来用户返回到activity 
A时能通过onCreate(Bundle)或者onRestoreInstanceState(Bundle)恢复界面的状态。
<br /><br />    Do not confuse this method with activity lifecycle callbacks 
such as onPause(), which is always called when an activity is being 
placed in the background or on its way to destruction, or onStop() which
 is called before destruction. One example of when onPause() and 
onStop() is called and not this method is when a user navigates back 
from activity B to activity A: there is no need to call 
onSaveInstanceState(Bundle) on B because that particular instance will 
never be restored, so the system avoids calling it. An example when 
onPause() is called and not onSaveInstanceState(Bundle) is when activity
 B is launched in front of activity A: the system may avoid calling 
onSaveInstanceState(Bundle) on activity A if it isn't killed during the 
lifetime of B since the state of the user interface of A will stay 
intact. 
<br />   
<br />    
不要将这个方法和activity生命周期回调如onPause()或onStop()搞混淆了，onPause()在activtiy被放置到背景或者
自行销毁时总会被调用，onStop()在activity被销毁时被调用。一个会调用onPause()和onStop()，但不触发
onSaveInstanceState的例子是当用户从activity B返回到activity 
A时：没有必要调用B的onSaveInstanceState(Bundle)，此时的B实例永远不会被恢复，因此系统会避免调用它。一个调用
onPause()但不调用onSaveInstanceState的例子是当activity B启动并处在activity 
A的前端：如果在B的整个生命周期里A的用户界面状态都没有被破坏的话，系统是不会调用activity 
A的onSaveInstanceState(Bundle)的。
<br /><br />    The default implementation takes care of most of the UI 
per-instance state for you by calling onSaveInstanceState() on each view
 in the hierarchy that has an id, and by saving the id of the currently 
focused view (all of which is restored by the default implementation of 
onRestoreInstanceState(Bundle)). If you override this method to save 
additional information not captured by each individual view, you will 
likely want to call through to the default implementation, otherwise be 
prepared to save all of the state of each view yourself. If called, this
 method will occur before onStop(). There are no guarantees about 
whether it will occur before or after onPause().
<br /><br />      
默认的实现负责了大部分UI实例状态(的保存)，采用的方式是调用UI层上每个拥有id的view的onSaveInstanceState() 
，并且保存当前获得焦点的view的id(所有保存的状态信息都会在默认的onRestoreInstanceState(Bundle)实现中恢复)。
如果你覆写这个方法来保存额外的没有被各个view保存的信息，你可能想要在默认实现过程中调用或者自己保存每个视图的所有状态。如果被调用，这个方法会
在onStop()前被触发，但系统并不保证是否在onPause()之前或者之后触发。
<br /><br />很多不明白Activity类中包含的onSaveInstanceState和onRestoreInstanceState有什么用，首先声
明下使用这两个方法时一定要注意情况和了解Activity的生命周期，否则有的时候  
onSaveInstanceState和onRestoreInstanceState 
可能不会被触发，虽然他们都是Activity的重写方法。（文/Android开发网）
<br /><br />他们比较常用到的地方是 
Sensor、Land和Port布局的自动切换，过去Android开发网曾经说过解决横屏和竖屏切换带来的数据被置空或者说onCreate被重复调
用问题，其实Android提供的onSaveInstanceState方法可以保存当前的窗口状态在即将布局切换前或当前Activity被推入历史
栈，其实布局切换也调用过onPause所以被推入Activity的history 
stack，如果我们的Activity在后台没有因为运行内存吃紧被清理，则切换回时会触发onRestoreInstanceState方法。
<br /><br />这两个方法中参数均为Bundle，可以存放类似 SharedPreferences 的数据，所以使用它们作为当前窗口的状态保存是比较合适的。实际使用代码
<br />@Override
<br />  protected void onSaveInstanceState(Bundle outState){
<br />            outState.putString("lastPath", "/sdcard/android123/cwj/test");
<br />  }
<br /><br /><br />@Override
<br />public void onRestoreInstanceState(Bundle savedInstanceState) {
<br />super.onRestoreInstanceState(savedInstanceState);
<br /><br />String cwjString = savedInstanceState.getString("lastPath");
<br />}
<br /><br />onSaveInstanceState和onRestoreInstanceState触发的时机
<br />已有 199 次阅读 2011-3-10 10:32 |个人分类:Android|关键词:onSaveInstanceState onRestoreInstanceState
<br />先看Application Fundamentals上的一段话：
<br /> Android calls onSaveInstanceState() before the activity becomes 
vulnerable to being destroyed by the system, but does not bother calling
 it when the instance is actually being destroyed by a user action (such
 as pressing the BACK key)
<br />从这句话可以知道，当某个activity变得“容易”被系统销毁时，该activity的onSaveInstanceState就会被执行，除非该activity是被用户主动销毁的，例如当用户按BACK键的时候。
<br />注意上面的双引号，何为“容易”？言下之意就是该activity还没有被销毁，而仅仅是一种可能性。这种可能性有哪些？通过重写一个 
activity的所有生命周期的onXXX方法，包括onSaveInstanceState和onRestoreInstanceState方法，我
 们可以清楚地知道当某个activity（假定为activity 
A）显示在当前task的最上层时，其onSaveInstanceState方法会在什么时候被执行，有这么几种情况：
<br />1、当用户按下HOME键时。这是显而易见的，系统不知道你按下HOME后要运行多少其他的程序，自然也不知道activity A是否会被销毁，故系统会调用onSaveInstanceState，让用户有机会保存某些非永久性的数据。以下几种情况的分析都遵循该原则
<br />2、长按HOME键，选择运行其他的程序时。
<br />3、按下电源按键（关闭屏幕显示）时。
<br />4、从activity A中启动一个新的activity时。
<br />5、屏幕方向切换时，例如从竖屏切换到横屏时。在屏幕切换之前，系统会销毁activity A，在屏幕切换之后系统又会自动地创建activity A，所以onSaveInstanceState一定会被执行
<br />总而言之，onSaveInstanceState的调用遵循一个重要原则，即当系统“未经你许可”时销毁了你的activity，则 
onSaveInstanceState会被系统调用，这是系统的责任，因为它必须要提供一个机会让你保存你的数据（当然你不保存那就随便你了）。
<br />至于onRestoreInstanceState方法，需要注意的是，onSaveInstanceState方法和 
onRestoreInstanceState方法“不一定”是成对的被调用的，onRestoreInstanceState被调用的前提 
是，activity A“确实”被系统销毁了，而如果仅仅是停留在有这种可能性的情况下，则该方法不会被调用，例如，当正在显示activity 
A的时候，用户按下HOME键回到主界面，然后用户紧接着又返回到activity A，这种情况下activity 
A一般不会因为内存的原因被系统销毁，故activity A的onRestoreInstanceState方法不会被执行
<br />另外，onRestoreInstanceState的bundle参数也会传递到onCreate方法中，你也可以选择在onCreate方法中做数据还原
  <img src ="http://www.blogjava.net/lihao336/aggbug/364585.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2011-11-22 17:56 <a href="http://www.blogjava.net/lihao336/archive/2011/11/22/364585.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>利用javap生成方法签名</title><link>http://www.blogjava.net/lihao336/archive/2011/10/24/361901.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Mon, 24 Oct 2011 08:04:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2011/10/24/361901.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/361901.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2011/10/24/361901.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/361901.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/361901.html</trackback:ping><description><![CDATA[使用JNI在native内调用java方法时，需要知道java方法的方法签名，利用javap工具可以方便的生成签名。由于java方法签名在jni层的表示方法的复杂性，利用这个工具生成签名信息可以避免人工分析带来的错误。<br />如：<br /><div style="background-color:#eeeeee;font-size:13px;BORDER:1px solid #CCCCCC;PADDING-RIGHT: 5px;PADDING-BOTTOM: 4px;PADDING-left: 4px;PADDING-TOP: 4px;WIDTH: 98%;word-break:break-all"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #008080; "> 1</span> <span style="color: #0000FF; ">package</span><span style="color: #000000; "> com.demo;<br /></span><span style="color: #008080; "> 2</span> <span style="color: #000000; "><br /></span><span style="color: #008080; "> 3</span> <span style="color: #000000; "></span><span style="color: #0000FF; ">public</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">class</span><span style="color: #000000; "> SigTest {<br /></span><span style="color: #008080; "> 4</span> <span style="color: #000000; "><br /></span><span style="color: #008080; "> 5</span> <span style="color: #000000; ">    </span><span style="color: #0000FF; ">public</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">static</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">final</span><span style="color: #000000; "> String name </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">;<br /></span><span style="color: #008080; "> 6</span> <span style="color: #000000; "><br /></span><span style="color: #008080; "> 7</span> <span style="color: #000000; ">    </span><span style="color: #0000FF; ">public</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">int</span><span style="color: #000000; "> getName(</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">[] data,</span><span style="color: #0000FF; ">long</span><span style="color: #000000; "> index) {<br /></span><span style="color: #008080; "> 8</span> <span style="color: #000000; ">        </span><span style="color: #0000FF; ">return</span><span style="color: #000000; "> </span><span style="color: #000000; ">0</span><span style="color: #000000; ">;<br /></span><span style="color: #008080; "> 9</span> <span style="color: #000000; ">    }<br /></span><span style="color: #008080; ">10</span> <span style="color: #000000; ">}<br /></span><span style="color: #008080; ">11</span> <span style="color: #000000; "></span></div><br />[calvin@calvin-desktop /tmp 15:59:50 ] <br />$ javac SigTest.java <br />[calvin@calvin-desktop /tmp 15:59:57 ] <br />$ javap -s -p -classpath . <b>SigTest</b><br />Compiled from "SigTest.java"<br />public class com.demo.SigTest extends java.lang.Object{<br />public static final java.lang.String name;<br />  Signature: Ljava/lang/String;<br />public com.demo.SigTest();<br />  Signature: ()V<br />public int getName(int[], long);<br />  Signature: ([IJ)I<br />static {};<br />  Signature: ()V<br />}<br /><br /><br />-s表示打印签名信息<br />-p表示打印所有函数和成员的签名信息，默认只打印public的签名信息。<br /><br />注意：<br />粗体部分是.class文件的文件名，不要.class后缀，否则提示<br />ERROR:Could not find SigTest.class.<br /><br /><img src ="http://www.blogjava.net/lihao336/aggbug/361901.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2011-10-24 16:04 <a href="http://www.blogjava.net/lihao336/archive/2011/10/24/361901.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]The Android boot process from power on</title><link>http://www.blogjava.net/lihao336/archive/2011/09/07/358158.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Wed, 07 Sep 2011 02:53:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2011/09/07/358158.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/358158.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2011/09/07/358158.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/358158.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/358158.html</trackback:ping><description><![CDATA[[First written by Steve Guo, please keep the mark if forwarding.].<br /><br /><br />init is the first process after kernel started. The corresponding source code lies in: device/system/init. It does the following tasks step by step:<br /><br />1.       Initialize log system.<br /><br />2.       Parse /init.rc and /init.%hardware%.rc.<br /><br />3.       Execute early-init action in the two files parsed in step 2.<br /><br />4.       Device specific initialize. For example, make all device node in /dev and download firmwares.<br /><br />5.       Initialize property system. Actually the property system is working as a share memory. Logically it looks like a registry under Windows system.<br /><br />6.       Execute init action in the two files parsed in step 2.<br /><br />7.       Start property service.<br /><br />8.       Execute early-boot and boot actions in the two files parsed in step 2.<br /><br />9.       Execute property action in the two files parsed in step 2.<br /><br />10.   Enter into an indefinite loop to wait for device/property set/child process exit events. For example, if an SD card is plugined, init will receive a device add event, so it can make node for the device. Most of the important process is forked in init, so if any of them crashed, init will receive a SIGCHLD then translate it into a child process exit event, so in the loop init can handle the process exit event and execute the commands defined in *.rc(it will run command onrestart).<br /><br /> <br /><br />The .rc file is a script file defined by Android. The default is device/system/rootdir/init.rc. We can take a loot at the file format(device/system/init/readme.txt is a good overall introduction of the script). Basically the script file contains actions and services.<br /><br /> <br /><br />Actions<br /><br />-------<br /><br />Actions are named sequences of commands. Actions have a trigger which is used to determine when the action should occur.  When an event occurs which matches an action's trigger, that action is added to the tail of a to-be-executed queue (unless it is already on the queue).<br /><br />Each action in the queue is dequeued in sequence and each command in that action is executed in sequence.  Init handles other activities (device creation/destruction, property setting, process restarting) "between" the execution of the commands in activities.<br /><br />Actions take the form of:<br /><br />on &lt;trigger&gt;<br /><br />   &lt;command&gt;<br /><br />   &lt;command&gt;<br /><br />   &lt;command&gt;<br /><br />...<br /><br /> <br /><br />Services<br /><br />--------<br /><br />Services are programs which init launches and (optionally) restarts when they exit.  Services take the form of:<br /><br />service &lt;name&gt; &lt;pathname&gt; [ &lt;argument&gt; ]*<br /><br />   &lt;option&gt;<br /><br />   &lt;option&gt;<br /><br />   ...<br /><br /> <br /><br />Options<br /><br />-------<br /><br />Options are modifiers to services.  They affect how and when init runs the service.<br /><br /> <br /><br />Triggers<br /><br />--------<br /><br />Triggers are strings which can be used to match certain kinds of events and used to cause an action to occur.<br /><br /> <br /><br />The builtin supported commands are defined in device/system/init/keywords.h. Commands are implementd in device/system/init/bultins.c.<br /><br /> <br /><br />The init program only executes five kinds of triggers: “early-init”, “init”, “early-boot”, “boot”, “property:*”. Take a look at the following line in default init.rc.<br /><br />class_start default<br /><br />This line is a command for the action corresponding to “boot” trigger. It will start all services whose class name equals to “default”. By default, if no class option is defined for a service, the service’s class name is “default”. So this line will start all the services in the order of position in the file by default. (BTW, you can start any service using start commands, if you like.) Any service is run as a forked process of init, take a look at the source code of service_start in device/system/init.c.<br /><br /> <br /><br />So according to the default init.rc, the following services will be executed step by step:<br /><br />console: star a shell. The source is in device/system/bin/ash.<br /><br />adbd: start adb daemon. The source is in device/tools/adbd. By default is disabled.<br /><br />servicemanager: start binder system. The source is in device/commands/binder.<br /><br />mountd: mount all fs defined in /system/etc/mountd.conf if started, receive commands through local socket to mount any fs. The source is in device/system/bin/mountd.<br /><br />debuggerd: start debug system. The source is in device/system/bin/debuggerd.<br /><br />rild: start radio interface layer daemon. The source is in device/commands/rind.<br /><br />zygote: start Android Java Runtime and start system server. It’s the most important service. The source is in device/servers/app.<br /><br />media: start AudioFlinger, MediaPlayerService and CameraService. The source is in device/commands/mediaserver.<br /><br />bootsound: play the default boot sound /system/media/audio/ui/boot.mp3. The source is in device/commands/playmp3.<br /><br />dbus: start dbus daemon, it’s only used by BlueZ. The source is in device/system/Bluetooth/dbus-daemon.<br /><br />hcid: redirect hcid’s stdout and stderr to the Android logging system. The source is in device/system/bin/logwrapper. By default is disabled.<br /><br />hfag: start Bluetooth handsfree audio gateway, it’s only used by BlueZ. The source is in device/system/Bluetooth/bluez-utils. By default is disabled.<br /><br />hsag: start Bluetooth headset audio gateway, it’s only used by BlueZ. The source is in device/system/Bluetooth/bluez-utils. By default is disabled.<br /><br />installd: start install package daemon. The source is in device/servers/installd.<br /><br />flash_recovery: load /system/recovery.img. The source is in device/commands/recovery/mtdutils.<br /><br /> <br /><br />Zygote service does the following tasks step by step:<br /><br />1.       Create JAVA VM.<br /><br />2.       Register android native function for JAVA VM.<br /><br />3.       Call the main function in the JAVA class named com.android.internal.os.ZygoteInit whose source is device/java/android/com/android/internal/os/ZygoteInit.java.<br /><br />a)         Load ZygoteInit class<br /><br />b)        Register zygote socket<br /><br />c)        Load preload classes(the default file is device/java/android/preloaded-classes)<br /><br />d)        Load preload resources<br /><br />e)         Call Zygote::forkSystemServer (implemented in device/dalvik/vm/InternalNative.c) to fork a new process. In the new process, call the main function in the JAVA class named com.android.server.SystemServer, whose source is in device/java/services/com/android/server.<br /><br />                         i.              Load libandroid_servers.so<br /><br />                       ii.              Call JNI native init1 function implemented in device/libs/android_servers/com_android_server_SystemServers. It only calls system_init implemented in device/servers/system/library/system_init.cpp.<br /><br />l         If running on simulator, instantiate AudioFlinger, MediaPlayerService and CameraService here.<br /><br />l         Call init2 function in JAVA class named com.android.server.SystemServer, whose source is in device/java/services/com/android/server. This function is very critical for Android because it start all of Android JAVA services.<br /><br />l         If not running on simulator, call IPCThreadState::self()-&gt;joinThreadPool() to enter into service dispatcher.<br /><br /> <br /><br />SystemServer::init2 will start a new thread to start all JAVA services as follows:<br /><br />Core Services:<br /><br />1.       Starting Power Manager<br /><br />2.       Creating Activity Manager<br /><br />3.       Starting Telephony Registry<br /><br />4.       Starting Package Manager<br /><br />5.       Set Activity Manager Service as System Process<br /><br />6.       Starting Context Manager<br /><br />7.       Starting System Context Providers<br /><br />8.       Starting Battery Service<br /><br />9.       Starting Alarm Manager<br /><br />10.   Starting Sensor Service<br /><br />11.   Starting Window Manager<br /><br />12.   Starting Bluetooth Service<br /><br />13.   Starting Mount Service<br /><br />Other services<br /><br />1.       Starting Status Bar Service<br /><br />2.       Starting Hardware Service<br /><br />3.       Starting NetStat Service<br /><br />4.       Starting Connectivity Service<br /><br />5.       Starting Notification Manager<br /><br />6.       Starting DeviceStorageMonitor Service<br /><br />7.       Starting Location Manager<br /><br />8.       Starting Search Service<br /><br />9.       Starting Clipboard Service<br /><br />10.   Starting Checkin Service<br /><br />11.   Starting Wallpaper Service<br /><br />12.   Starting Audio Service<br /><br />13.   Starting HeadsetObserver<br /><br />14.   Starting AdbSettingsObserver<br /><br />Finally SystemServer::init2 will call ActivityManagerService.systemReady to launch the first activity by senting Intent.CATEGORY_HOME intent.<br /><br /> <br /><br />There is another way to start system server, which is through a program named system_server whose source is device/servers/system/system_main.cpp. It also calls system_init to start system services. So there is a question: why does Android have two methods to start system services? My guess is that directly start system_server may have synchronous problem with zygote because system_server will call JNI to start SystemServer::init2, while at that time zygote may not start JAVA VM yet. So Android uses another method. After zynote is initialized, fork a new process to start system services. <br /><img src ="http://www.blogjava.net/lihao336/aggbug/358158.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2011-09-07 10:53 <a href="http://www.blogjava.net/lihao336/archive/2011/09/07/358158.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Compile CyanogenMod (Linux) for HTC Desire</title><link>http://www.blogjava.net/lihao336/archive/2011/09/06/358137.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Tue, 06 Sep 2011 10:12:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2011/09/06/358137.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/358137.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2011/09/06/358137.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/358137.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/358137.html</trackback:ping><description><![CDATA[
		<br />参照guide：<br /><a href="http://wiki.cyanogenmod.com/wiki/HTC_Desire_%28GSM%29:_Compile_CyanogenMod_%28Linux%29">http://wiki.cyanogenmod.com/wiki/HTC_Desire_(GSM):_Compile_CyanogenMod_(Linux)</a><br /><br />出现如下问题：<br /><br />1.repo init时报错：<br />......<br />object 30d452905f166b316152f236422f85c8aa75a2d0<br />type commit<br />tag v1.7.5<br />tagger Shawn O. Pearce &lt;sop@google.com&gt; 1307663540 -0700<br /><br />repo 1.7.5<br /><br />gpg: Signature made Fri 10 Jun 2011 07:52:20 AM CST using DSA key ID 920F5C65<br />gpg: Can't check signature: public key not found<br />error: could not verify the tag 'v1.7.5'<br /><br />出错原因是曾使用repo sync从其它库sync过代码，删掉~/.repoconfig即可：<br />$ rm -rf ~/.repoconfig<br />$ ./repo init -u git://github.com/CyanogenMod/android.git -b gingerbread<br />gpg: keyring `/home/calvin/.repoconfig/gnupg/secring.gpg' created<br />gpg: keyring `/home/calvin/.repoconfig/gnupg/pubring.gpg' created<br />gpg: /home/calvin/.repoconfig/gnupg/trustdb.gpg: trustdb created<br />gpg: key 920F5C65: public key "Repo Maintainer &lt;repo@android.kernel.org&gt;" imported<br />gpg: Total number processed: 1<br />gpg:               imported: 1<br /><br />Getting repo ...<br />   from http://android.git.kernel.org/tools/repo.git<br />。。。。<br /><br /><br />2.repo sync时报错：<br />。。。。。<br />Fetching projects:   1% (3/285)  <br />Initializing project platform/bootable/bootloader/legacy ...<br />android.git.kernel.org[0: 130.239.17.13]: errno=Connection refused<br />android.git.kernel.org[0: 149.20.4.77]: errno=Connection timed out<br />android.git.kernel.org[0: 199.6.1.173]: errno=Connection refused<br />android.git.kernel.org[0: 2001:4f8:8:10:1972:112:1:0]: errno=Network is unreachable<br />android.git.kernel.org[0: 2001:500:60:10:1972:112:1:0]: errno=Network is unreachable<br />android.git.kernel.org[0: 2001:6b0:e:4017:1972:112:1:0]: errno=Network is unreachable<br />android.git.kernel.org[0: 2001:4f8:1:10:1972:112:1:0]: errno=Network is unreachable<br />fatal: unable to connect a socket (Network is unreachable)<br />error: Cannot fetch platform/bootable/bootloader/legacy<br /><br />连接服务器时的问题，解决：<br />修改.repo/manifest.xml中<br />  &lt;remote  name="korg"<br />           fetch="git://android.git.kernel.org/"<br />           review="review.source.android.com" /&gt;<br />为<br />  &lt;remote  name="korg"<br />           fetch="http://android.git.kernel.org/"<br />           review="review.source.android.com" /&gt;<br /><br /><img src ="http://www.blogjava.net/lihao336/aggbug/358137.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2011-09-06 18:12 <a href="http://www.blogjava.net/lihao336/archive/2011/09/06/358137.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>android.uid.system没有读写sdcard的权限</title><link>http://www.blogjava.net/lihao336/archive/2011/08/29/357497.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Mon, 29 Aug 2011 06:16:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2011/08/29/357497.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/357497.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2011/08/29/357497.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/357497.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/357497.html</trackback:ping><description><![CDATA[在AndroidManifest.xml中声明<br />android:sharedUserId="android.uid.system"<br />后，该应用程序将没有权限读写SD卡。<br /><br />Processes that continue holding open fds on the sdcard a little after it is 
<br />requested to be unmounted will be killed so that it can unmount. 
<br /><br />We don't want the system process to  be able to access the sdcard to avoid 
<br />these kinds of issues (and just general security cleanliness), so that it 
<br />does not have permission to access it. 
  <br /><br /><a href="http://groups.google.com/group/android-porting/browse_thread/thread/c6af65d7ddd5eff3">http://groups.google.com/group/android-porting/browse_thread/thread/c6af65d7ddd5eff3</a><br /><a href="http://stackoverflow.com/questions/5617797/android-shared-user-id-and-reading-writing-a-file">http://stackoverflow.com/questions/5617797/android-shared-user-id-and-reading-writing-a-file</a><br /><a href="http://stackoverflow.com/questions/6679011/it-cant-access-the-sdcard-after-setting-android-uid-system-in-my-application">http://stackoverflow.com/questions/6679011/it-cant-access-the-sdcard-after-setting-android-uid-system-in-my-application</a><br /><a href="http://www.eoeandroid.com/forum.php?mod=viewthread&amp;tid=63314&amp;page=1#pid636737">http://www.eoeandroid.com/forum.php?mod=viewthread&amp;tid=63314&amp;page=1#pid636737</a><br /><img src ="http://www.blogjava.net/lihao336/aggbug/357497.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2011-08-29 14:16 <a href="http://www.blogjava.net/lihao336/archive/2011/08/29/357497.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Android monkey &amp; jni相关</title><link>http://www.blogjava.net/lihao336/archive/2011/05/27/351178.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Fri, 27 May 2011 07:08:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2011/05/27/351178.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/351178.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2011/05/27/351178.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/351178.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/351178.html</trackback:ping><description><![CDATA[首先，android平台应用程序可能产生以下四种crash：<br />App层：<br />Force close crash<br />ANR crash<br />Native层：<br />Tombstone crash<br />Kernel层：<br />Kernel panic<br />比较难定位，可以查看/proc/last_kmsg来辅助定位。<br /><br />最近需要通过monkey工具测试Tombstone类型的crash，抓取log并分析。通过monkey测试，如果要抓取native类型的crash，需要加上--monitor-native-crash参数：<br /><br />seed=$(date +%Y%m%d%H%m%S)<br />monkey -s $seed --pkg-whitelist-file ${your-package-list} --monitor-native-crashes --kill-process-after-error -v -v -v 2000000000<br /><br />这样，monkey在跑出crash后，在/data/system/dropbox 和 /data/tombstones目录下会生成相关日志，moneky会停止发送事件流并退出测试.值得注意的是，/data/tombstones文件夹下只会保存10个日志，超过10个后，最早创建的会被替换。而monkey是通过监视这个文件夹下的文件数量变化来判断是否有tombtone类型的crash产生的。因此，当/data/tombstones文件夹下超过10个文件后，如果再有tombstone crash产生的话，monkey是不能检测到的，它会继续发送事件流。为了避免这个问题，可以在每次运行monkey之前先清空一下这个文件夹。<br /><br />另外，在settings.db中的secure表中有三个字段：dropbox:data_app_wtf,dropbox:data_app_anr,dropbox:data_app_crash。如果设置为enabled，每当有app crash之后，在/data/system/dropbox这个文件夹下都会产生相关的日志信息，这对于分析调试问题都是第一手的信息。<br /><br />如何制造tombstone类型的crash？<br />这需要通过jni调用一个native的so文件，在本地代码中抛出异常即可。<br />可以编写如下代码tombstone_gen.cpp:<br />int main(int argc, char **argv) {<br />  int *p=0;<br />  *p=1;    //will seg fault<br />  return 0;<br />}<br />参照development/samples/SimpleJNI的示例，运行build出的apk即可。<br /><br />关于jni调用，也有几个问题：<br />1.FindClass,RegisterNatives等找不到：<br />target thumb C: libtombstonec &lt;= development/samples/AndroidDemos/jni/tombstone_gen.c<br />development/samples/AndroidDemos/jni/tombstone_gen.c: In function 'registerNativeMethods':<br />development/samples/AndroidDemos/jni/tombstone_gen.c:48: error: request for member 'FindClass' in something not a structure or union<br />development/samples/AndroidDemos/jni/tombstone_gen.c:53: error: request for member 'RegisterNatives' in something not a structure or union<br />development/samples/AndroidDemos/jni/tombstone_gen.c: In function 'JNI_OnLoad':<br />development/samples/AndroidDemos/jni/tombstone_gen.c:97: error: request for member 'GetEnv' in something not a structure or union<br />make: *** [out/target/product/generic/obj/SHARED_LIBRARIES/libtombstonec_intermediates/tombstone_gen.o] Error 1<br /><br />问题原因在于：<br />如果是C程序，要用 (*env)-&gt;<br />如果是C++要用 env-&gt;<br />因此有两种解决方法：<br />1、将 (*env)-&gt; 改为 env-&gt;<br />2、将c文件改为cpp文件，改为c++的方式编译。<br /><br />2、运行时异常java.lang.UnsatisfiedLinkError<br />tombstone_gen.cpp中<br />static const char *classPathName = "com/android/demo/AndroidDemos";<br />类名有误，导致类链接错误。<br /><br />最后，关于jni中JNINativeMethod相关解释：<br />http://hi.baidu.com/zhlg_hzh/blog/item/f0d782081f2f45d963d986f5.html<br /><br /><img src ="http://www.blogjava.net/lihao336/aggbug/351178.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2011-05-27 15:08 <a href="http://www.blogjava.net/lihao336/archive/2011/05/27/351178.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在android工程中导入layoutlib.jar使用internal api</title><link>http://www.blogjava.net/lihao336/archive/2011/04/28/349172.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Thu, 28 Apr 2011 03:39:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2011/04/28/349172.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/349172.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2011/04/28/349172.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/349172.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/349172.html</trackback:ping><description><![CDATA[在android-sdk-linux_x86/platforms/android-10/data/layoutlib.jar中包含了source中internal的api，在eclipse中导入这个jar包就可以使用internal的api了。<br />
导入方法：<br />
1. Right-click the project in Eclipse and select "Build Path -&gt; Add Libraries...".<br />
2. Select User Library from the list and click Next.<br />
3. Click the "User Libraries..." button.<br />
4. Click "New..." in the User Libraries dialog.<br />
5. Give the user library a name and select the System library checkbox and click OK.<br />
6. Highlight the newly added user library in the list and click the "Add JARs..." button and add the desired jar files.<br />
7. Click OK on the User Libraries dialog.<br />
8. Make sure the new user library is checked in the Add Library dialog and<br />
<br />
不以这种方式添加会出现DEX error，切记<br />
<br />
<img src ="http://www.blogjava.net/lihao336/aggbug/349172.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2011-04-28 11:39 <a href="http://www.blogjava.net/lihao336/archive/2011/04/28/349172.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Eclipse 导入gingerbread源代码build path错误</title><link>http://www.blogjava.net/lihao336/archive/2011/04/21/348715.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Thu, 21 Apr 2011 08:29:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2011/04/21/348715.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/348715.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2011/04/21/348715.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/348715.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/348715.html</trackback:ping><description><![CDATA[<br />
在eclipse中导入gingerbread源代码后出现如下build path错误：<br />
<br />
Project 'gingerbread' is missing required library: 'out/target/common/obj/JAVA_LIBRARIES/google-common_intermediates/javalib.jar'<br />
Project 'gingerbread' is missing required library: 'out/target/common/obj/JAVA_LIBRARIES/gsf-client_intermediates/javalib.jar'<br />
<br />
解决：<br />
删除.classpath中的这两行路径<br />
<span class="Apple-style-span" style="border-collapse: separate; color: #000000; font-family: 'WenQuanYi Micro Hei'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: -webkit-auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; font-size: medium; "><span class="Apple-style-span" style="font-family: simsun; font-size: 14px; line-height: 23px; text-align: left; ">&lt;classpathentry kind="lib" path="out/target/common/obj/JAVA_LIBRARIES/google-common_intermediates/javalib.jar"/&gt;<br />
&lt;classpathentry kind="lib" path="out/target/common/obj/JAVA_LIBRARIES/gsf-client_intermediates/javalib.jar"/&gt;<br />
添加<br />
&lt;classpathentry kind="lib" path="out/target/common/obj/JAVA_LIBRARIES/android-common_intermediates/javalib.jar"/&gt;</span></span><br />
<br />
或者<br />
<a href="https://groups.google.com/group/android-platform/browse_thread/thread/5c86d1f1929eed3c?pli=1">https://groups.google.com/group/android-platform/browse_thread/thread/5c86d1f1929eed3c?pli=1</a><br />
<a href="http://topic.csdn.net/u/20110406/19/5cc32204-b45e-4427-a3ea-eacd83fede13.html">http://topic.csdn.net/u/20110406/19/5cc32204-b45e-4427-a3ea-eacd83fede13.html</a><br />
<br />
<img src ="http://www.blogjava.net/lihao336/aggbug/348715.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2011-04-21 16:29 <a href="http://www.blogjava.net/lihao336/archive/2011/04/21/348715.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用git下载android源码</title><link>http://www.blogjava.net/lihao336/archive/2011/03/03/345551.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Wed, 02 Mar 2011 17:39:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2011/03/03/345551.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/345551.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2011/03/03/345551.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/345551.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/345551.html</trackback:ping><description><![CDATA[<span style="color: #000000;"><span style="border-collapse: separate; color: #000000; font-family: 文泉驿等宽微米黑; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: center; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium;"><span style="font-family: verdana,sans-serif; font-size: 12px; line-height: 18px; text-align: left;">
<h1 style="line-height: 24px; margin: 0px; padding: 0px 0px 0.5em 1.5em; font-size: 15px; font-family: 'Microsoft yahei',verdana,sans-serif; border-bottom: 2px solid #dcdcdc;"><span style="line-height: 21px; font-family: verdana,sans-serif; font-weight: normal; font-size: 14px;">
<p style="line-height: 22px; margin: 1em 0px 0.5em; padding: 0px;"><strong style="line-height: 22px;">1、Git的安装</strong>&nbsp;<br style="line-height: 22px;" />
&nbsp;&nbsp;<br style="line-height: 22px;" />
<strong style="line-height: 22px;">sudo apt-get install git-core&nbsp;<br style="line-height: 22px;" />
</strong></p>
<p style="line-height: 22px; margin: 1em 0px 0.5em; padding: 0px;"><strong style="line-height: 22px;">2、安装Repo</strong>&nbsp;<br style="line-height: 22px;" />
2.1首先确保在当前用户的主目录下创建一个~/bin目录（如果没有的话），</p>
<p style="line-height: 22px; margin: 1em 0px 0.5em; padding: 0px;">2.2然后把它(~/bin)加到PATH环境变量中;</p>
<p style="line-height: 22px; margin: 1em 0px 0.5em; padding: 0px;">echo &#8220;export PATH=$PATH:~/bin&#8221; &gt; ~/.bashrc</p>
<p style="line-height: 22px; margin: 1em 0px 0.5em; padding: 0px;">source ~/.bashrc<br style="line-height: 22px;" />
<strong style="line-height: 22px; font-weight: normal;">2.3下载repo</strong></p>
<p style="line-height: 22px; margin: 1em 0px 0.5em; padding: 0px;"><strong style="line-height: 22px;">打开http://android.git.kernel.org/repo，把该网页保存为 ~/bin/repo</strong></p>
<p style="line-height: 22px; margin: 1em 0px 0.5em; padding: 0px;">给repo可执行权限<br style="line-height: 22px;" />
<strong style="line-height: 22px;">chmod a+x ~/bin/repo</strong></p>
<p style="line-height: 22px; margin: 1em 0px 0.5em; padding: 0px;"><strong style="line-height: 22px;">3，设置git代理参考，见我的一篇文章</strong></p>
<p style="line-height: 22px; margin: 1em 0px 0.5em; padding: 0px;"><strong style="line-height: 22px;">http://blog.chinaunix.net/u3/93670/showart_2084139.html</strong></p>
<p style="line-height: 22px; margin: 1em 0px 0.5em; padding: 0px;"><strong style="line-height: 22px;">4、初始化版本库</strong></p>
<p style="line-height: 22px; margin: 1em 0px 0.5em; padding: 0px;"><strong style="line-height: 22px;">4.1修改repo内容</strong></p>
<p style="line-height: 22px; margin: 1em 0px 0.5em; padding: 0px;"><strong style="line-height: 22px;"><span style="line-height: 21px; font-weight: normal;">把&#8220;git:&#8221;改成&#8220;http:&#8221;</span>&nbsp;<br style="line-height: 22px;" />
</strong></p>
<p style="line-height: 22px; margin: 1em 0px 0.5em; padding: 0px;">4.2新建~/android目录，进去以后用repo init命令即可。只初始化2.0版（eclair）</p>
<p style="line-height: 22px; margin: 1em 0px 0.5em; padding: 0px;"><strong style="line-height: 22px;">repo init -u&nbsp;<span style="line-height: 21px; color: #ff0102;">http:</span>&nbsp;//android.git.kernel.org/platform/manifest.git</strong>&nbsp;-b eclair<br style="line-height: 22px;" />
<br style="line-height: 22px;" />
最后会看到 repo initialized in /android这样的提示，就说明本地的版本库已经初始化完毕，并且包含了当前最新的sourcecode。</p>
<p style="line-height: 22px; margin: 1em 0px 0.5em; padding: 0px;"><span style="line-height: 25px; font-family: Verdana,Arial,Helvetica,sans-serif,宋体; color: #333333;">通常情况下会出现error提示（如果是以前没有创建过repo账户的话），这个不要紧，忽略掉它好了。<br style="line-height: 22px;" />
<br style="line-height: 22px;" />
<a href="http://www.xxlinux.com/linux/article/accidence/install/" target="_blank" style="line-height: 22px; text-decoration: none; color: #07519a;">配置</a>repo账户<br style="line-height: 22px;" />
git config --global user.email "[email=xxxxx@xxxxxxx]xxxxx@xxxxxxx[/email]"<br style="line-height: 22px;" />
git config --global user.name "xxxxxx"</span></p>
<p style="line-height: 22px; margin: 1em 0px 0.5em; padding: 0px;"><strong style="line-height: 22px;">5、同步版本库</strong>&nbsp;<br style="line-height: 22px;" />
5.1修改.repo/manifest.xml<br style="line-height: 22px;" />
<strong style="line-height: 22px;"><span style="line-height: 21px; font-weight: normal;"><br style="line-height: 22px;" />
&nbsp; 把&#8220;git:&#8221;改成&#8220;http:&#8221;</span></strong></p>
<p style="line-height: 22px; margin: 1em 0px 0.5em; padding: 0px;">5.2<strong style="line-height: 22px;">同步（其实是正式下载，前面init只是下载了具体的路径和依赖文件）<br style="line-height: 22px;" />
</strong></p>
<p style="line-height: 22px; margin: 1em 0px 0.5em; padding: 0px;"><strong style="line-height: 22px;">repo sync</strong></p>
<p style="line-height: 22px; margin: 1em 0px 0.5em; padding: 0px;"><strong style="line-height: 22px;"><br style="line-height: 22px;" />
</strong></p>
<p style="line-height: 22px; margin: 1em 0px 0.5em; padding: 0px;"><span style="line-height: 21px; font-weight: bold;">另一种情况是</span>&nbsp;，<span style="line-height: 21px; font-weight: bold;">只下载某一个项目</span>&nbsp;。</p>
<p style="line-height: 22px; margin: 1em 0px 0.5em; padding: 0px;">我们只需要某一个project的代码，比如kernel/common，就不需要repo了，直接用Git即可。<br style="line-height: 22px;" />
<strong style="line-height: 22px;">git clone git://android.git.kernel.org/kernel/common.git</strong>&nbsp;<br style="line-height: 22px;" />
这也需要不少的时间，因为它会把整个Linux Kernel的代码复制下来。</p>
<p style="line-height: 22px; margin: 1em 0px 0.5em; padding: 0px;">如果需要某个branch的代码，用git checkout即可。比如我们刚刚拿了kernel/common.get的代码，那就先进入到common目录，然后用下面的命令：<br style="line-height: 22px;" />
<strong style="line-height: 22px;">git checkout origin/android-goldfish-2.6.27 -b goldfish</strong>&nbsp;<br style="line-height: 22px;" />
这样我们就在本地建立了一个名为goldfish的android-goldfish-2.6.27分支，代码则已经与android-goldgish-2.6.27同步。我们可以通过git branch来列出本地的所有分支。</p>
</span></h1>
</span></span>
</span>
<img src ="http://www.blogjava.net/lihao336/aggbug/345551.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2011-03-03 01:39 <a href="http://www.blogjava.net/lihao336/archive/2011/03/03/345551.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SurfaceView与View</title><link>http://www.blogjava.net/lihao336/archive/2010/12/08/340050.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Wed, 08 Dec 2010 03:20:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/12/08/340050.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/340050.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/12/08/340050.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/340050.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/340050.html</trackback:ping><description><![CDATA[<br />
如果你的游戏不吃CPU，用View就比较好，符合标准Android操作方式，由系统决定刷新surface的时机。<br />
但如果很不幸的，你做不到不让你的程序吃CPU，你就只好使用SurfaceView来强制刷新surface了，不然系统的UI进程很可能抢不过你那些吃CPU的线程。<br />
<br />
当然其实不止这两种方法来刷新Surface的，这两种只是纯java应用比较常见的方法。<br />
<br />
<hr size="2" width="100%" />
<br />
SurfaceView和View最本质的区别在于，surfaceView是在一个新起的单独线程中可以重新绘制画面而View必须在UI的主线程中更新画面。<br />
那么在UI的主线程中更新画面 可能会引发问题，比如你更新画面的时间过长，那么你的主UI线程会被你正在画的函数阻塞。那么将无法响应按键，触屏等消息。<br />
<br />
当使用surfaceView 由于是在新的线程中更新画面所以不会阻塞你的UI主线程。但这也带来了另外一个问题，就是事件同步。比如你触屏了一下，你需要surfaceView中thread处理，一般就需要有一个event queue的设计来保存touch event，这会稍稍复杂一点，因为涉及到线程同步。<br />
<br />
所以基于以上，根据游戏特点，一般分成两类。<br />
<br />
1 被动更新画面的。比如棋类，这种用view就好了。因为画面的更新是依赖于 onTouch 来更新，可以直接使用 invalidate。 因为这种情况下，这一次Touch和下一次的Touch需要的时间比较长些，不会产生影响。<br />
<br />
2 主动更新。比如一个人在一直跑动。这就需要一个单独的thread不停的重绘人的状态，避免阻塞main UI thread。所以显然view不合适，需要surfaceView来控制。<br />
<img src ="http://www.blogjava.net/lihao336/aggbug/340050.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-12-08 11:20 <a href="http://www.blogjava.net/lihao336/archive/2010/12/08/340050.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>android bluetooth</title><link>http://www.blogjava.net/lihao336/archive/2010/12/06/339897.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Mon, 06 Dec 2010 06:48:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/12/06/339897.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/339897.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/12/06/339897.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/339897.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/339897.html</trackback:ping><description><![CDATA[<a href="http://blog.csdn.net/dyufei/archive/2010/08/16/5815719.aspx">http://blog.csdn.net/dyufei/archive/2010/08/16/5815719.aspx</a><br />
<br />
<a href="http://blog.csdn.net/dyufei/archive/2010/08/27/5844353.aspx">http://blog.csdn.net/dyufei/archive/2010/08/27/5844353.aspx</a><br />
<br />
<a href="/Files/lihao336/android/android-Bluetooth.pdf">http://www.blogjava.net/Files/lihao336/android/android-Bluetooth.pdf</a><br />
<img src ="http://www.blogjava.net/lihao336/aggbug/339897.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-12-06 14:48 <a href="http://www.blogjava.net/lihao336/archive/2010/12/06/339897.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Talking about Android process</title><link>http://www.blogjava.net/lihao336/archive/2010/11/29/339327.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Mon, 29 Nov 2010 08:14:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/11/29/339327.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/339327.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/11/29/339327.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/339327.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/339327.html</trackback:ping><description><![CDATA[<span class="Apple-style-span" style="border-collapse: separate; color: #000000; font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium;"><span class="Apple-style-span" style="border-collapse: collapse; font-family: song,Verdana; font-size: 12px;">
<h3 style="margin: 13pt 0cm;"><span lang="EN-US"><font color="#000000" face="Times New Roman" size="5">[First written by Steve Guo, please keep the mark if forwarding.]</font></span></h3>
</span></span><span class="Apple-style-span" style="border-collapse: separate; color: #000000; font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium;"><span class="Apple-style-span" style="border-collapse: collapse; font-family: song,Verdana; font-size: 12px;">
<table style="border-collapse: collapse; word-wrap: break-word;" cellpadding="0" cellspacing="0" width="100%" border="0">
    <tbody>
        <tr style="font: 12px song,Verdana;">
            <td style="font: 12px song,Verdana;" align="center">
            <table style="border-collapse: collapse; word-wrap: break-word;" cellpadding="0" cellspacing="0" width="100%" border="0">
                <tbody>
                    <tr style="font: 12px song,Verdana;">
                        <td style="font: 12px song,Verdana;" width="100%">
                        <div id="art" width="100%" style="margin: 15px;">
                        <div id="msgcns!89AD27DFB5E249BA!459" class="bvMsg">
                        <p style="font: 12px song,Verdana;">In this topic you will learn some information about Android process management. First let&#8217;s take a look at the launched processes during Android booting.</p>
                        <p style="font: 12px song,Verdana;"><em>USER PID PPID VSIZE RSS WCHAN PC NAME</em></p>
                        <p style="font: 12px song,Verdana;"><em>root 1 0 264 176 c00acc6c 0000c36c S /init</em></p>
                        <p style="font: 12px song,Verdana;"><em>root 28 1 724 308 c0051354 afe0c4cc S /system/bin/sh</em></p>
                        <p style="font: 12px song,Verdana;"><em>system 30 1 796 248 c026516c afe0b74c S /system/bin/servicemanager</em></p>
                        <p style="font: 12px song,Verdana;"><em>root 31 1 1824 316 ffffffff afe0b50c S /system/bin/mountd</em></p>
                        <p style="font: 12px song,Verdana;"><em>root 32 1 652 248 c02976e0 afe0c0bc S /system/bin/debuggerd</em></p>
                        <p style="font: 12px song,Verdana;"><em>radio 33 1 5344 664 ffffffff afe0bdbc S /system/bin/rild</em></p>
                        <p style="font: 12px song,Verdana;"><em>root 34 1 71028 18828 c00ad308 afe0b874 S zygote</em></p>
                        <p style="font: 12px song,Verdana;"><em>media 37 1 16812 3456 ffffffff afe0b74c S /system/bin/mediaserver</em></p>
                        <p style="font: 12px song,Verdana;"><em>root 39 1 788 288 c02f9ae4 afe0b50c S /system/bin/installd</em></p>
                        <p style="font: 12px song,Verdana;"><em>system 86 34 187756 21836 ffffffff afe0b74c S system_server</em></p>
                        <p style="font: 12px song,Verdana;"><em>radio 118 34 103476 13896 ffffffff afe0c824 S com.android.phone</em></p>
                        <p style="font: 12px song,Verdana;"><em>app_4 124 34 117848 19248 ffffffff afe0c824 S android.process.acore</em></p>
                        <p style="font: 12px song,Verdana;"><em>app_5 139 34 98672 11516 ffffffff afe0c824 S com.android.mms</em></p>
                        <p style="font: 12px song,Verdana;"><em>app_3 151 34 92096 10976 ffffffff afe0c824 S com.android.alarmclock</em></p>
                        <p style="font: 12px song,Verdana;"><em>app_6 161 34 94436 12616 ffffffff afe0c824 S com.android.calendar</em></p>
                        <p style="font: 12px song,Verdana;"><em>app_9 173 34 93248 11728 ffffffff afe0c824 S android.process.media</em></p>
                        <p style="font: 12px song,Verdana;"><em>app_15 182 34 91848 9764 ffffffff afe0c824 S com.android.voicedialer</em></p>
                        <p style="font: 12px song,Verdana;"><em>app_16 190 34 94524 10812 ffffffff afe0c824 S android.process.im</em></p>
                        <p style="font: 12px song,Verdana;">They can be divided into three kinds.</p>
                        <h4>Root Process</h4>
                        <p style="font: 12px song,Verdana;">init is the first process after kernel booting. The major task it performs:</p>
                        <p style="font: 12px song,Verdana;">l Parser and execute init.rc and init.%hardware%.rc</p>
                        <p style="font: 12px song,Verdana;">l Automatically generate device node under /dev</p>
                        <p style="font: 12px song,Verdana;">l Start log and property service</p>
                        <p style="font: 12px song,Verdana;">l Monitor for device, property set and child process exit events</p>
                        <h4>Native Application Process</h4>
                        <p style="font: 12px song,Verdana;">According to init.rc, init will fork the following native application process.</p>
                        <p style="font: 12px song,Verdana;"><strong>console</strong>: star a shell.</p>
                        <p style="font: 12px song,Verdana;"><strong>servicemanager</strong>: start binder IPC service manager.</p>
                        <p style="font: 12px song,Verdana;"><strong>mountd</strong>: mount all fs defined in /system/etc/mountd.conf if started, receive commands through local socket to mount any fs.</p>
                        <p style="font: 12px song,Verdana;"><strong>debuggerd</strong>: start debug system.</p>
                        <p style="font: 12px song,Verdana;"><strong>rild</strong>: start radio interface layer daemon.</p>
                        <p style="font: 12px song,Verdana;"><strong>zygote</strong>: start Android Java VM Runtime and start system server. It&#8217;s the most important process.</p>
                        <p style="font: 12px song,Verdana;"><strong>mediaserver</strong>: start AudioFlinger, MediaPlayerService and CameraService.</p>
                        <p style="font: 12px song,Verdana;"><strong>installd</strong>: start install package daemon.</p>
                        <h4>JAVA Application Process</h4>
                        <p style="font: 12px song,Verdana;">Every JAVA application process is forked from zygote process. system_server is a special JAVA process, which is directly forked from zygote.. Other JAVA process is created from ActivityManagerService(run in system_server process) like this.</p>
                        <p style="font: 12px song,Verdana;"><em>int pid = Process.start("android.app.ActivityThread",</em></p>
                        <p style="font: 12px song,Verdana;"><em>mSimpleProcessManagement ? app.processName : null, uid, uid,</em></p>
                        <p style="font: 12px song,Verdana;"><em>gids, ((app.info.flags&amp;ApplicationInfo.FLAG_DEBUGGABLE) != 0), null);</em></p>
                        <p style="font: 12px song,Verdana;">While Process.java use UNIX domain socket to communicate with zygote. So the overall picture is shown as following.</p>
                        <p style="font: 12px song,Verdana;"><a href="http://blufiles.storage.msn.com/y1pySHLglI8hr1QG90DfDA8rJPCI543BJ1x0D41pF_ZMLy-f3FxRn5p7mgGuy2WAnph50vRzK2gehM2DmT6KF7mPw?PARTNER=WRITER" style="text-decoration: underline; color: #0044b6;"><img alt="clip_image002" src="http://blufiles.storage.msn.com/y1pokXRB25-2RV1nj7EKcQuKUb13ODpZiNTCZhuaLVcnRiFtv-4A2RxYiScrmSU310uMHeevOYYRyUnO-8Xa6o5jA?PARTNER=WRITER" style="border-width: 0px;" height="313" width="474" border="0" /></a></p>
                        <h5>System Server</h5>
                        <p style="font: 12px song,Verdana;">It&#8217;s the first JAVA application launched by zygote. It starts the core Android services, e.g. ActivityManager, WindowManager, PackageManager etc. It&#8217;s the Android core engine.</p>
                        <h5>Persistent Application</h5>
                        <p style="font: 12px song,Verdana;">During booting, ActivityManagerService.systemReady will start all persistent applications.</p>
                        <p style="font: 12px song,Verdana;"><em>List apps = ActivityThread.getPackageManager().</em></p>
                        <p style="font: 12px song,Verdana;"><em>getPersistentApplications(PackageManager.GET_SHARED_LIBRARY_FILES);</em></p>
                        <p style="font: 12px song,Verdana;"><em>if (apps != null) {</em></p>
                        <p style="font: 12px song,Verdana;"><em>int N = apps.size();</em></p>
                        <p style="font: 12px song,Verdana;"><em>int i;</em></p>
                        <p style="font: 12px song,Verdana;"><em>for (i=0; i&lt;N; i++) {</em></p>
                        <p style="font: 12px song,Verdana;"><em>ApplicationInfo info</em></p>
                        <p style="font: 12px song,Verdana;"><em>= (ApplicationInfo)apps.get(i);</em></p>
                        <p style="font: 12px song,Verdana;"><em>if (info != null &amp;&amp;</em></p>
                        <p style="font: 12px song,Verdana;"><em>!info.packageName.equals("android")) {</em></p>
                        <p style="font: 12px song,Verdana;"><em>addAppLocked(info);</em></p>
                        <p style="font: 12px song,Verdana;"><em>}</em></p>
                        <p style="font: 12px song,Verdana;"><em>}</em></p>
                        <p style="font: 12px song,Verdana;"><em>}</em></p>
                        <p style="font: 12px song,Verdana;">Currently only Phone application is registered as a persistent app in AndroidManifest.xml like this.</p>
                        <p style="font: 12px song,Verdana;"><em>&lt;application android:name="PhoneApp"</em></p>
                        <p style="font: 12px song,Verdana;"><em><font color="#ff0000">android:persistent="true"</font></em></p>
                        <p style="font: 12px song,Verdana;"><em>android:label="@string/dialerIconLabel"</em></p>
                        <p style="font: 12px song,Verdana;"><em>android:icon="@drawable/ic_launcher_phone"&gt;</em></p>
                        <p style="font: 12px song,Verdana;">So during booting, only phone application is automatically launched. It&#8217;s the &#8220;com.android.phone&#8221; process.</p>
                        <h5>The First Activity</h5>
                        <p style="font: 12px song,Verdana;">The first activity is launched by senting Intent.CATEGORY_HOME intent from ActivityManagerService.</p>
                        <p style="font: 12px song,Verdana;"><em>Intent intent = new Intent(</em></p>
                        <p style="font: 12px song,Verdana;"><em>mTopAction,</em></p>
                        <p style="font: 12px song,Verdana;"><em>mTopData != null ? Uri.parse(mTopData) : null);</em></p>
                        <p style="font: 12px song,Verdana;"><em>intent.setComponent(mTopComponent);</em></p>
                        <p style="font: 12px song,Verdana;"><em>if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {</em></p>
                        <p style="font: 12px song,Verdana;"><em>intent.addCategory(<font color="#ff0000">Intent.CATEGORY_HOME</font>);</em></p>
                        <p style="font: 12px song,Verdana;"><em>}</em></p>
                        <p style="font: 12px song,Verdana;"><em>ActivityInfo aInfo =</em></p>
                        <p style="font: 12px song,Verdana;"><em>intent.resolveActivityInfo(mContext.getPackageManager(),</em></p>
                        <p style="font: 12px song,Verdana;"><em>PackageManager.GET_SHARED_LIBRARY_FILES);</em></p>
                        <p style="font: 12px song,Verdana;"><em>if (aInfo != null) {</em></p>
                        <p style="font: 12px song,Verdana;"><em>intent.setComponent(new ComponentName(</em></p>
                        <p style="font: 12px song,Verdana;"><em>aInfo.applicationInfo.packageName, aInfo.name));</em></p>
                        <p style="font: 12px song,Verdana;"><em>// Don't do this if the home app is currently being</em></p>
                        <p style="font: 12px song,Verdana;"><em>// instrumented.</em></p>
                        <p style="font: 12px song,Verdana;"><em>ProcessRecord app = getProcessRecordLocked(aInfo.processName,</em></p>
                        <p style="font: 12px song,Verdana;"><em>aInfo.applicationInfo.uid);</em></p>
                        <p style="font: 12px song,Verdana;"><em>if (app == null || app.instrumentationClass == null) {</em></p>
                        <p style="font: 12px song,Verdana;"><em>intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);</em></p>
                        <p style="font: 12px song,Verdana;"><em>startActivityLocked(null, intent, null, null, 0, aInfo,</em></p>
                        <p style="font: 12px song,Verdana;"><em>null, null, 0, 0, 0, false);</em></p>
                        <p style="font: 12px song,Verdana;"><em>}</em></p>
                        <p style="font: 12px song,Verdana;"><em>}</em></p>
                        <p style="font: 12px song,Verdana;">It&#8217;s the &#8220;android.process.acore&#8221; process. (The process name is defined in AndroidManifest.xml)</p>
                        <h5>Auto-launched Application After Booting</h5>
                        <p style="font: 12px song,Verdana;">When activity idle is detected in ActivityManagerService, it will broadcast ACTION_BOOT_COMPLETED intent at the first time.</p>
                        <p style="font: 12px song,Verdana;"><em>if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {</em></p>
                        <p style="font: 12px song,Verdana;"><em>// Tell anyone interested that we are done booting!</em></p>
                        <p style="font: 12px song,Verdana;"><em>synchronized (this) {</em></p>
                        <p style="font: 12px song,Verdana;"><em>broadcastIntentLocked(null, null,</em></p>
                        <p style="font: 12px song,Verdana;"><em>new Intent(<font color="#ff0000">Intent.ACTION_BOOT_COMPLETED</font>, null),</em></p>
                        <p style="font: 12px song,Verdana;"><em>null, null, 0, null, null,</em></p>
                        <p style="font: 12px song,Verdana;"><em>android.Manifest.permission.RECEIVE_BOOT_COMPLETED,</em></p>
                        <p style="font: 12px song,Verdana;"><em>false, false, MY_PID, Process.SYSTEM_UID);</em></p>
                        <p style="font: 12px song,Verdana;"><em>}</em></p>
                        <p style="font: 12px song,Verdana;"><em>}</em></p>
                        <p style="font: 12px song,Verdana;">Currently, MMS, AlarmClock, Calendar, MediaProvider, VoiceDialer and IM have registered as a receiver for ACTION_BOOT_COMPLETED intent in their AndroidManifest.xml. So they will be automatically launched. (This explains the remained JAVA process.)</p>
                        <p style="font: 12px song,Verdana;">Email also registers as a receiver for ACTION_BOOT_COMPLETED intent in its AndroidManifest.xml, but it defines android:enable=&#8221;false&#8221;. So it won&#8217;t be launched.</p>
                        <p style="font: 12px song,Verdana;"><em>&lt;receiver android:name=".service.BootReceiver"</em></p>
                        <p style="font: 12px song,Verdana;"><em><font color="#ff0000">android:enabled="false"</font></em></p>
                        <p style="font: 12px song,Verdana;"><em>&gt;</em></p>
                        <p style="font: 12px song,Verdana;"><em>&lt;intent-filter&gt;</em></p>
                        <p style="font: 12px song,Verdana;"><em>&lt;action android:name="android.intent.action.BOOT_COMPLETED" /&gt;</em></p>
                        <p style="font: 12px song,Verdana;"><em>&lt;/intent-filter&gt;</em></p>
                        <p style="font: 12px song,Verdana;"><em>&lt;intent-filter&gt;</em></p>
                        <p style="font: 12px song,Verdana;"><em>&lt;action android:name="android.intent.action.DEVICE_STORAGE_LOW" /&gt;</em></p>
                        <p style="font: 12px song,Verdana;"><em>&lt;/intent-filter&gt;</em></p>
                        <p style="font: 12px song,Verdana;"><em>&lt;intent-filter&gt;</em></p>
                        <p style="font: 12px song,Verdana;"><em>&lt;action android:name="android.intent.action.DEVICE_STORAGE_OK" /&gt;</em></p>
                        <p style="font: 12px song,Verdana;"><em>&lt;/intent-filter&gt;</em></p>
                        <p style="font: 12px song,Verdana;"><em>&lt;/receiver&gt;</em></p>
                        <p style="font: 12px song,Verdana;">DownloadProvider also registers as a receiver for ACTION_BOOT_COMPLETED intent in its AndroidManifest.xml, but it defines android:exported=&#8221;false&#8221;. So it won&#8217;t be launched.</p>
                        <p style="font: 12px song,Verdana;"><em>&lt;receiver android:name=".DownloadReceiver"<span class="Apple-converted-space">&nbsp;</span><font color="#ff0000">android:exported="false"</font>&gt;</em></p>
                        <p style="font: 12px song,Verdana;"><em>&lt;intent-filter&gt;</em></p>
                        <p style="font: 12px song,Verdana;"><em>&lt;action android:name="android.intent.action.BOOT_COMPLETED" /&gt;</em></p>
                        <p style="font: 12px song,Verdana;"><em>&lt;action android:name="android.net.conn.CONNECTIVITY_CHANGE" /&gt;</em></p>
                        <p style="font: 12px song,Verdana;"><em>&lt;/intent-filter&gt;</em></p>
                        <p style="font: 12px song,Verdana;"><em>&lt;/receiver&gt;</em></p>
                        <h5>Behind the JAVA process</h5>
                        <p style="font: 12px song,Verdana;">system_server is a special case. It calls ActivityThread.java&#8217;s systemMain static function, which creates an instance of ActivityThread. ActivityThread then creates an instance of ApplicationThread, Application and ApplicationContext.</p>
                        <p style="font: 12px song,Verdana;">Every other JAVA process works in a different way. It&#8217;s controlled by system_server while forked by zygote. When any JAVA process other than system_server is forked from zygote, it automatically calls ActivityThread.java&#8217;s main static function(See Process.java and the following code snippet).</p>
                        <p style="font: 12px song,Verdana;"><em>try {</em></p>
                        <p style="font: 12px song,Verdana;"><em>ZygoteInit.invokeStaticMain(cloader, className, mainArgs);</em></p>
                        <p style="font: 12px song,Verdana;"><em>} catch (RuntimeException ex) {</em></p>
                        <p style="font: 12px song,Verdana;"><em>logAndPrintError (newStderr, "Error starting. ", ex);</em></p>
                        <p style="font: 12px song,Verdana;"><em>}</em></p>
                        <p style="font: 12px song,Verdana;">The ActivityThread.java&#8217;s main function creates an instance of ActivityThread. ActivityThread then creates an instance of ApplicationThread. The ApplicationThread will work as an IBinder object to interact with ActivityManagerService in system_server. The new process does nothting at this time other than waiting IPC call from system_server. The Application and ApplicationContext object won&#8217;t be created at this time. Actually it&#8217;s deferred to when the process really works, eg. start an activity, receive intent or start a service.</p>
                        <p style="font: 12px song,Verdana;">For example, when start an activity, ActivityManagerService know which process the to-be-launched activity should run in, so it will RPC call ApplicationThread&#8217;s scheduleLaunchActivity to launch a new activity in that process. ApplicationThread then post a message to let ActivityThread know it needs to start an activity. ActivityThread then creates Application and ApplicationContext object. After that, it calls Instrumentation, then Instrumentation finally calls JAVA dalvik VM to really create an activity JAVA object.</p>
                        </div>
                        </div>
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
        <tr style="font: 12px song,Verdana;">
            <td style="font: 12px song,Verdana;" height="25">&nbsp;<font color="#000099"><strong>原文地址</strong></font><span class="Apple-converted-space">&nbsp;</span><a href="http://letsgoustc.spaces.live.com/?_c11_BlogPart_BlogPart=blogview&amp;_c=BlogPart&amp;partqs=cat%3DGoogle%2" target="_blank" style="text-decoration: underline; color: #0044b6;">http://letsgoustc.spaces.live.com/?_c11_BlogPart_BlogPart=blogview&amp;_c=BlogPart&amp;partqs=cat%3DGoogle%2</a></td>
        </tr>
    </tbody>
</table>
</span></span><br />
<br />
<br />
<br />
<br />
<br />
<br />
<img src ="http://www.blogjava.net/lihao336/aggbug/339327.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-11-29 16:14 <a href="http://www.blogjava.net/lihao336/archive/2010/11/29/339327.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>handler与多线程消息处理</title><link>http://www.blogjava.net/lihao336/archive/2010/11/29/339316.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Mon, 29 Nov 2010 06:55:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/11/29/339316.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/339316.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/11/29/339316.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/339316.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/339316.html</trackback:ping><description><![CDATA[转载地址：http://blog.csdn.net/jinlking/archive/2009/07/09/4333456.aspx<br />
<br />
在Android下面也有多线程的概念，在C/C++中，子线程可以是一个函数，一般都是一个带有循环的函数，来处理某些数据，优先线程只是一个复杂的运算过程，所以可能不需要while循环，运算完成，函数结束，线程就销毁。对于那些需要控制的线程，一般我们都是和互斥锁相互关联，从而来控制线程 的进度，一般我们创建子线程，一种线程是很常见的，那就是带有消息循环的线程。<br />
<br />
消息循环是一个很有用的线程方式，曾经自己用C在Linux下面实现一个消息循环的机制，往消息队列里添加数据，然后异步的等待消息的返回。当消息队列为空的时候就会挂起线程，等待新的消息的加入。这是一个很通用的机制。<br />
<br />
在Android，这里的线程分为有消息循环的线程和没有消息循环的线程，有消息循环的线程一般都会有一个Looper，这个是android的新概念。我们的主线程（UI线程）就是一个消息循环的线程。针对这种消息循环的机制，我们引入一个新的机制Handler，我们有消息循环，就要往消息循环里面发送相应的消息，自定义消息一般都会有自己对应的处理，消息的发送和清除，消息的的处理，把这些都封装在Handle里面，注意Handle只是针对那 些有Looper的线程，不管是UI线程还是子线程，只要你有Looper，我就可以往你的消息队列里面添加东西，并做相应的处理。<br />
<br />
但是这里还有一点，就是只要是关于UI相关的东西，就不能放在子线程中，因为子线程是不能操作UI的，只能进行数据、系统等其他非UI的操作。<br />
<br />
那么什么情况下面我们的子线程才能看做是一个有Looper的线程呢？<strong>我们如何得到它Looper的句柄呢？</strong><br />
<br />
Looper.myLooper();获得当前的Looper<br />
<br />
Looper.getMainLooper () 获得UI线程的Lopper<br />
<br />
我们看看Handle的初始化函数，如果没有参数，那么他就默认使用的是当前的Looper，如果有Looper参数，就是用对应的线程的Looper。<br />
<br />
如果一个线程中调用Looper.prepare()，那么系统就会自动的为该线程建立一个消息队列，然后调用 Looper.loop();之后就进入了消息循环，这个之后就可以发消息、取消息、和处理消息。这个如何发送消息和如何处理消息可以在其他的线程中通过 Handle来做，但前提是我们的Handle知道这个子线程的Looper，但是你如果不是在子线程运行 Looper.myLooper()，一般是得不到子线程的looper的。<br />
<br />
public void run() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; synchronized (mLock) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Looper.prepare();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //do something<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Looper.loop();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
<br />
所以很多人都是这样做的：我直接在子线程中新建handle，然后在子线程中发送消息，这样的话就失去了我们多线程的意义了。<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008080;">&nbsp;1</span>&nbsp;<span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;myThread&nbsp;</span><span style="color: #0000ff;">extends</span><span style="color: #000000;">&nbsp;Thread{<br />
</span><span style="color: #008080;">&nbsp;2</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;EHandler&nbsp;mHandler&nbsp;;<br />
</span><span style="color: #008080;">&nbsp;4</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;5</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;run()&nbsp;{<br />
</span><span style="color: #008080;">&nbsp;6</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;7</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Looper&nbsp;myLooper,&nbsp;mainLooper;<br />
</span><span style="color: #008080;">&nbsp;8</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;9</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myLooper&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;Looper.myLooper&nbsp;();<br />
</span><span style="color: #008080;">10</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">11</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mainLooper&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;Looper.getMainLooper&nbsp;();<br />
</span><span style="color: #008080;">12</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">13</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;obj;<br />
</span><span style="color: #008080;">14</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">15</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(myLooper&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">&nbsp;){<br />
</span><span style="color: #008080;">16</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">17</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mHandler&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;EHandler(mainLooper);<br />
</span><span style="color: #008080;">18</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">19</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;obj&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">current&nbsp;thread&nbsp;has&nbsp;no&nbsp;looper!</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;;<br />
</span><span style="color: #008080;">20</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">21</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</span><span style="color: #008080;">22</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">23</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;">&nbsp;{<br />
</span><span style="color: #008080;">24</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">25</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mHandler&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;EHandler(myLooper);<br />
</span><span style="color: #008080;">26</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">27</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;obj&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">This&nbsp;is&nbsp;from&nbsp;current&nbsp;thread.</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;;<br />
</span><span style="color: #008080;">28</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">29</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</span><span style="color: #008080;">30</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">31</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mHandler&nbsp;.removeMessages(</span><span style="color: #000000;">0</span><span style="color: #000000;">);<br />
</span><span style="color: #008080;">32</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">33</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Message&nbsp;m&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;mHandler&nbsp;.obtainMessage(</span><span style="color: #000000;">1</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">,&nbsp;obj);<br />
</span><span style="color: #008080;">34</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">35</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mHandler&nbsp;.sendMessage(m);<br />
</span><span style="color: #008080;">36</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">37</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</span><span style="color: #008080;">38</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">39</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;}</span></div>
<br />
可以让其他的线程来控制我们的handle，可以把 private EHandler mHandler ;放在外面，这样我们的发消息和处理消息都可以在外面来定义，这样增加程序代码的美观，结构更加清晰。<br />
<br />
对如任何的Handle，里面必须要重载一个函数<br />
<br />
public void handleMessage(Message msg)<br />
<br />
这个函数就是我们的消息处理，如何处理，这里完全取决于你，然后通过 obtainMessage和 sendMessage等来生成和发送消息， removeMessages(0)来清除消息队列。Google真是太智慧了，这种框架的产生，我们写代码更加轻松了。<br />
<br />
有的时候，我们的子线程想去改变UI了，这个时候千万不要再子线程中去修改，获得UI线程的Looper，然后发送消息即可。<br />
<br />
我们来看看高焕堂的代码：<br />
<br />
// class ac01 extends Activity {<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // &#8230;&#8230;&#8230;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void onClick(View v) {<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; switch (v.getId()){<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 101:<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t = new myThread();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t .start();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break ;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 102:<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; finish();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break ;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
<br />
//------------------------------------------------------&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
<br />
class EHandler extends Handler {<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public EHandler(Looper looper) {<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super (looper);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @Override<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void handleMessage(Message msg) {<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tv .setText((String)msg. obj );<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
<br />
//------------------------------------------------------&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
<br />
class myThread extends Thread{<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private EHandler mHandler ;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void run() {<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Looper myLooper, mainLooper;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; myLooper = Looper.myLooper ();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mainLooper = Looper.getMainLooper ();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String obj;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (myLooper == null ){<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mHandler = new EHandler(mainLooper);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; obj = "current thread has no looper!" ;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else {<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mHandler = new EHandler(myLooper);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; obj = "This is from current thread." ;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mHandler .removeMessages(0);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Message m = mHandler .obtainMessage(1, 1, 1, obj);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mHandler .sendMessage(m);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp; }<br />
<br />
}<br />
<br />
完全是不知所云，一坨狗屎。我们来看，在上面的run里面<br />
<br />
Looper myLooper, mainLooper;<br />
<br />
myLooper = Looper.myLooper (); //很明显这个会返回空，因为你还没有 prepare，不会返回Looper。<br />
<br />
mainLooper = Looper.getMainLooper ();<br />
<br />
建议大家在看Looper的时候不要看高焕堂的书，感觉他也不是很懂，倒还把我搞糊涂了。讲了那么多，完全是他自己的理解，他自己的理解很是复杂，关键的是把简单的问题复杂化，并且复杂之后的东西还是错的。我们看看Goole Music App的源代码。<br />
<br />
在MediaPlaybackActivity.java中，我们可以看一下再OnCreate中的有这样的两句：<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mAlbumArtWorker = new Worker("album art worker");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mAlbumArtHandler = new AlbumArtHandler(mAlbumArtWorker.getLooper());<br />
<br />
很明显这两句，是构建了一个子线程。并且这个子线程还是Looper的子线程，这里很牛逼的使用了 mAlbumArtWorker.getLooper()这个函数，因为我们知道，我们能够得到子线程的Looper的途径只有一个：就是在子线程中调用 Looper.myLooper ()，并且这个函数还要在我们perpare之后调用才能得到正确的Looper，但是他这里用了一个这样的什么东东 getLooper，不知道它是如何实现的？<br />
<br />
这里有一个大概的思路，我们在子线程的的prepare之后调用 myLooper ()这个方法，然后保存在一个成员变量中，这个getLooper就返回这个东西，但是这里会碰到多线程的一个很突出的问题，同步。我们在父线程中调用 mAlbumArtWorker.getLooper()，但是想要这个返回正确的looper就必须要求我们的子线程运行了prepare，但是这个东 西实在子线程运行的，我们如何保证呢？<br />
&nbsp;<br />
我们看Google是如何实现的？<br />
<br />
&nbsp;<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Worker&nbsp;</span><span style="color: #0000ff;">implements</span><span style="color: #000000;">&nbsp;Runnable&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;Object&nbsp;mLock&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Object();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;Looper&nbsp;mLooper;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Creates&nbsp;a&nbsp;worker&nbsp;thread&nbsp;with&nbsp;the&nbsp;given&nbsp;name.&nbsp;The&nbsp;thread<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;then&nbsp;runs&nbsp;a&nbsp;{</span><span style="color: #808080;">@link</span><span style="color: #008000;">&nbsp;android.os.Looper}.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080;">@param</span><span style="color: #008000;">&nbsp;name&nbsp;A&nbsp;name&nbsp;for&nbsp;the&nbsp;new&nbsp;thread<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Worker(String&nbsp;name)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread&nbsp;t&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Thread(</span><span style="color: #0000ff;">null</span><span style="color: #000000;">,&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">,&nbsp;name);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.setPriority(Thread.MIN_PRIORITY);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.start();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">synchronized</span><span style="color: #000000;">&nbsp;(mLock)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;(mLooper&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">try</span><span style="color: #000000;">&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mLock.wait();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000ff;">catch</span><span style="color: #000000;">&nbsp;(InterruptedException&nbsp;ex)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;Looper&nbsp;getLooper()&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;mLooper;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;run()&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">synchronized</span><span style="color: #000000;">&nbsp;(mLock)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Looper.prepare();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mLooper&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;Looper.myLooper();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mLock.notifyAll();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Looper.loop();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;quit()&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mLooper.quit();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
<br />
我们知道，一个线程类的构造函数是在主线程中完成的，所以在我们的 Worker的构造函数中我们创佳一个线程，然后让这个线程运行，这一这个线程的创建是指定一个 Runnabl，这里就是我们的Worker本身，在主线程调用 t.start();，这后，我们子线程已经创建，并且开始执行work的run方法。然后下面的代码很艺术：<br />
<br />
synchronized (mLock) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (mLooper == null) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mLock.wait();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (InterruptedException ex) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
<br />
我们开始等待我们的子线程给mLooper赋值，如果不赋值我们就继续等，然后我们的子线程在运行run方法之后，在给 mLooper赋值之后，通知worker够着函数中的wait，然后我们的构造函数才能完成，所以我们说：<br />
<br />
mAlbumArtWorker = new Worker("album art worker");<br />
<br />
这句本身就是阻塞的，它创建了一个子线程，开启了子线程，并且等待子线程给mLooper赋值，赋值完成之后，这个函数才返回，这样才能保证我们的子线程的Looper的获取绝对是正确的，这个构思很有创意。值得借鉴。<br />
<br />
PS：<br />
1、发送消息并不会阻塞线程，而处理消息时会阻塞线程，这是因为Handler 处理完一个 Message 对象才会接着去取下面一个消息进行处理。<br />
Handler对于Message的处理不是并发的。一个Looper 只有处理完一条Message才会读取下一条，所以消息的处理是阻塞形式的，如果在handler里做耗时的操作，则调用者线程会阻塞。但是如果<strong>用不同的Looper则能达到并发的目的</strong>。（<a href="http://windywindy.javaeye.com/blog/464185">http://windywindy.javaeye.com/blog/464185</a>）<br />
<br />
2、Android提供了一个HandlerThread来实现并发处理message的目的，HandlerThread在实现上与Music应用的Worker类相似。<br />
<br />
参考：<br />
<ul>
    <li><a title="Android中的MessageQueue,Handler,Looper和Thread" href="http://www.limodev.cn/blog/archives/1207">Android中的MessageQueue,Handler,Looper和Thread</a></li>
    <li><a title="android handler 多线程demo" href="http://blog.csdn.net/shaofeiwang/archive/2010/10/17/5947529.aspx">android handler 多线程demo</a></li>
    <li><a title="Handler与线程的关系" href="http://xifangyuhui.javaeye.com/blog/813264">Handler与线程的关系</a></li>
    <li><a title="图解 Android Handler 线程消息机制" href="http://blog.csdn.net/nieweilin/archive/2010/10/30/5976820.aspx">图解 Android Handler 线程消息机制</a></li>
</ul>
<img src ="http://www.blogjava.net/lihao336/aggbug/339316.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-11-29 14:55 <a href="http://www.blogjava.net/lihao336/archive/2010/11/29/339316.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Android 窗口管理</title><link>http://www.blogjava.net/lihao336/archive/2010/11/24/338962.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Wed, 24 Nov 2010 10:28:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/11/24/338962.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/338962.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/11/24/338962.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/338962.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/338962.html</trackback:ping><description><![CDATA[Android 窗口管理<br />
在整个控件树的最顶端，是一个逻辑的树顶，ViewParent，在源码中的实现是ViewRoot（ViewRoot extends Handler implements ViewParent）。它是整个控件树和WindowManager之间的事件信息的翻译者。WindowManager是Android中一个重要的服务。它将用户的操作，翻译成为指令，发送给呈现在界面上的各个Window。Activity会将顶级的控件注册到WindowManager中，当用户真是触碰屏幕或键盘的时候，WindowManager就会通知到，而当控件有一些请求产生，也会经由ViewParent送回到WindowManager中。从而完成整个通信流程。<br />
<br />
事件分发流程<br />
用户在触发一个时间后产生一个消息，消息先被window manager采集到，然后分发给client。<br />
window manager通过IWindow分发给client，我们知道ViewRoot使用IWindowSession与server通讯，使用IWindow接收消息，所以第一步消息到了ViewRoot这里来了<br />
也就是window manager-&gt;IWindow-&gt;ViewRoot<br />
到了ViewRoot后它把消息转发给Looper（楼主可以看ViewRoot.java看它是怎么获取当前线程的Looper的)<br />
Looper-&gt;ViewRoot$RootHandler().dispatch()，有转发会给ViewRoot，然后就通过decor view形成的树状结构依次分发下去。<br />
<br />
window manager proxy中维护了view, ViewRoot, layout param三元组。<br />
每次调用window manager proxy的addView都会新增一个三元组。一般程序中都是调用addView(decor,...)，也就是只对decor view调用addView<br />
<br />
*****************\<br />
在Activity在performLaunchActivity时，会使用Activity.attach（）建立一个PhoneWindow主窗口。这个主窗口的建立并不是一个重点。handleResumeActivity真正要启动一个Activity时候，将主窗口加入到WindowManager，当然并不是将主窗口本身，而是将主窗口的DecorView加入到WindowManager中。<br />
<br />
&#8226; performLaunchActivity@ActivityThread.java<br />
attach()@Activity.javaSession.java<br />
addWindow()@WindowManager<br />
<br />
mWindow = PolicyManager.makeNewWindow(this); --实例化一个activity或者dialog或者widget的地方才会make new window<br />
&#8226; handleResumeActivity()@ActivityThread.java<br />
addView()@WindowManagerImpl.java --添加DecorView到WindowManager中<br />
setView()@ViewRoot.java<br />
add()@IwindowSession.java<br />
| --这里通过AIDL调用<br />
add()@WindowManagerService$Service.java<br />
<br />
关于PhoneWindow：<br />
而PhoneWindow只是做了一个具体跟手机功能相关的公用事件的处理，所以在Android中PhoneWindow并不是一个抽象的纯正概念，而是一个跟手机系统相关的一个特别窗口概念，例如按键的默认动作处理，按键音的发出等等。<br />
<br />
一个View对应一个ViewRoot<br />
<br />
问题：<strong style="background-color: yellow">WindowMangerService如果通过AIDL将事件派发到客户端的？</strong>
<img src ="http://www.blogjava.net/lihao336/aggbug/338962.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-11-24 18:28 <a href="http://www.blogjava.net/lihao336/archive/2010/11/24/338962.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[原]Activity启动过程分析</title><link>http://www.blogjava.net/lihao336/archive/2010/11/23/338802.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Tue, 23 Nov 2010 06:59:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/11/23/338802.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/338802.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/11/23/338802.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/338802.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/338802.html</trackback:ping><description><![CDATA[启动activity：<br />
**android.process.acore进程<br />
1.Acticity.startActivityForResult()<br />
2.Instrumention.execStartActivity();<br />
3.ActivityManagerNative.getDefault()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .startActivity()<br />
&nbsp; 3.1 ActivityManagerNative.getDefault()返回的是ActivityManagerProxy的实例，<br />
&nbsp; 它只是一个代理类，这个代理类实际上代理的是IBinder b = ServiceManager.getService("activity");<br />
&nbsp; 这个Service。<br />
&nbsp; 3.2 这个Service是什么时候添加进来的呢？<br />
&nbsp; 在SystemServer.java的run()中有调用<br />
&nbsp; ActivityManagerService.setSystemProcess();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ServiceManager.addService("activity", m);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这里还会添加许多系统关键服务。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; （TODO：查看在SystemServer的Log输出）<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
**system_process进程 <br />
4 ActivityManagerNative<br />
&nbsp;&nbsp;&nbsp; |--ActivityManagerService<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 在ActivityManagerNative的onTransact方法中最终提供了服务：<br />
&nbsp;&nbsp;&nbsp; case START_ACTIVITY_TRANSACTION：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ActivityManagerService.startActivity（）;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --startActivityLocked(IApplicationThread caller,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Intent intent, String resolvedType,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Uri[] grantedUriPermissions,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int grantedMode, ActivityInfo aInfo, IBinder resultTo,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String resultWho, int requestCode,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int callingPid, int callingUid, boolean onlyIfNeeded,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; boolean componentSpecified) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --startActivityUncheckedLocked(r, sourceRecord,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; grantedUriPermissions, grantedMode, onlyIfNeeded, true)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在这个方法里面检查权限，解析intent中的Flag。。。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --startActivityLocked(HistoryRecord r, boolean newTask)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --resumeTopActivityLocked(HistoryRecord prev)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --startSpecificActivityLocked(HistoryRecord r,boolean andResume, boolean checkConfig) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --startProcessLocked(String processName,ApplicationInfo info, boolean knownToBeDead, int intentFlags,String hostingType, ComponentName hostingName)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --startProcessLocked(ProcessRecord app,String hostingType, String hostingNameStr)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在这里启动一个进程用来host这个应用<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int pid = Process.start("android.app.ActivityThread",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mSimpleProcessManagement ? app.processName : null, uid, uid,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; gids, debugFlags, null);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
ActivityManagerService.java<br />
--startSpecificActivityLocked(HistoryRecord r,boolean andResume, boolean checkConfig)<br />
&nbsp; --realStartActivityLocked(HistoryRecord r,ProcessRecord app, boolean andResume, boolean checkConfig)<br />
&nbsp;&nbsp;&nbsp; --app.thread.scheduleLaunchActivity&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //scheduleLaunchActivity()@IApplicationThread.java<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --scheduleLaunchActivity()@ActivityThread.java&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //这里实际是ApplicationThreadNative提供的服务<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --handleMessage()@H$ActivityThread.java<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --handleLaunchActivity()@ActivityThread.java<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --Activity performLaunchActivity(ActivityRecord r, Intent customIntent)@ActivityThread.java&nbsp; //这时真正的Activity对象被构造出来<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --mInstrumentation.newActivity（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //通过反射构造出Activity对象<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --activity.attach（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //初始化Activity，生成一个window对象，设置各种状态等等<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --mInstrumentation.callActivityOnCreate(activity, r.state);&nbsp; //调用Activity的onCreate()方法<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 到这里，我们自己写的activity的onCreate()方法已经被系统调用了，接下来依次回调生命周期方法：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --activity.performStart();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --mInstrumentation.callActivityOnStart(this);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --mInstrumentation.callActivityOnPostCreate(activity, r.state);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --mActivities.put(r.token, r);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //将这个activity入栈<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 然后就要调用onResume()方法了：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --handleResumeActivity(IBinder token, boolean clearHide, boolean isForward)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --performResumeActivity(token, clearHide);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --r.activity.performResume();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --performRestart()@Activity.java;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --mInstrumentation.callActivityOnRestart(this);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --mInstrumentation.callActivityOnStart(this);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --mInstrumentation.callActivityOnResume(this);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; onResume()已经调用完毕，一个activity的逻辑处理结束了，但是这时候屏幕上还不会显示任何东西，因为View还没有添加进去<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --r.window.getDecorView();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //开始把DecorView添加进Window<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --wm.addView(decor, l);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 至此一个Activity启动结束。<br />
<img src ="http://www.blogjava.net/lihao336/aggbug/338802.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-11-23 14:59 <a href="http://www.blogjava.net/lihao336/archive/2010/11/23/338802.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>PDP context相关</title><link>http://www.blogjava.net/lihao336/archive/2010/11/23/338799.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Tue, 23 Nov 2010 06:50:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/11/23/338799.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/338799.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/11/23/338799.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/338799.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/338799.html</trackback:ping><description><![CDATA[<br />
<br />
<a title="GPRS-PDP上下文的激活过程 (摘选)" href="http://blog.163.com/linxiuming0126@126/blog/static/807398762010326111716749/">GPRS-PDP上下文的激活过程 (摘选)</a><br />
<br />
<a title="about PDP context" href="http://bbs.c114.net/archiver/?tid-364749.html">about PDP context</a><br />
<img src ="http://www.blogjava.net/lihao336/aggbug/338799.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-11-23 14:50 <a href="http://www.blogjava.net/lihao336/archive/2010/11/23/338799.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Apn切换后数据连接过程</title><link>http://www.blogjava.net/lihao336/archive/2010/11/23/338789.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Tue, 23 Nov 2010 06:12:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/11/23/338789.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/338789.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/11/23/338789.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/338789.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/338789.html</trackback:ping><description><![CDATA[<br />
GsmDataConnectionTracker在实例化时，会注册一个观察者，监视apn数据库的变化。<br />
p.getContext().getContentResolver().registerContentObserver(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Telephony.Carriers.CONTENT_URI, true, apnObserver);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
当改变apn后，Settings应用更新apn数据库，ApnChangeObserver的onChange被调用，发送EVENT_APN_CHANGED消息：<br />
sendMessage(obtainMessage(EVENT_APN_CHANGED));<br />
<br />
接着onApnChanged()@GsmDataConnectionTracker.java被调用<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -trySetupData(Phone.REASON_APN_CHANGED)@GsmDataConnectionTracker.java<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --setupData(String reason)@GsmDataConnectionTracker.java<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private boolean setupData(String reason) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ApnSetting apn;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GsmDataConnection pdp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; apn = getNextApn();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (apn == null) return false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //获取一个状态为inactive的pdp连接对象<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pdp = findFreePdp();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (pdp == null) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (DBG) log("setupData: No free GsmDataConnection found!");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mActiveApn = apn;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mActivePdp = pdp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Message msg = obtainMessage();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; msg.what = EVENT_DATA_SETUP_COMPLETE;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; msg.obj = reason;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //开始激活这个pdp<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //在android2.0.1版本时，有一个PdpConnection.java来进行连接，2.2时这个类被删掉了，connect的功能合并到GsmDataConnection里面<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pdp.connect(msg, apn);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //设置这个pdp连接状态为INITING<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setState(State.INITING);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (DBG) log("setupData for reason: "+reason);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //通知上层应用数据连接状态改变<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; phone.notifyDataConnection(reason);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 其中，在这一层，数据连接共七个状态：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IDLE,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INITING,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CONNECTING,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SCANNING,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CONNECTED,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DISCONNECTING,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FAILED<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 对上层应用来说，这七个状态划分为四种状态（getDataConnectionState()@GSMPhone.java）：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CONNECTED, CONNECTING, DISCONNECTED, SUSPENDED;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 分别对应TelephonyManager的四种连接状态。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 开始激活PDP连接时，设置状态为State.INITING，调用phone.notifyDataConnection(reason)发出通知，后续调用过程为：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; notifyDataConnection(String reason)@PhoneBase.java<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --notifyDataConnection(Phone sender, String reason)@DefaultPhoneNotifier.java<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .&nbsp;&nbsp; <strong>这里需要经过IPC调用</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; notifyDataConnection()@TelephonyRegistry.java<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --onDataConnectionStateChanged()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
当连接成功后，onDataSetupComplete（）@GsmDataConnectionTracker.java被调用<br />
通过phone.notifyDataConnection(reason);回调应用层的onDataConnectionStateChanged()方法。<br />
<br />
ps:可以通过adb logcat -b radio查看激活数据连接时，radio层的log输出。<br />
<img src ="http://www.blogjava.net/lihao336/aggbug/338789.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-11-23 14:12 <a href="http://www.blogjava.net/lihao336/archive/2010/11/23/338789.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>利用onUserLeaveHint发送后台运行通知</title><link>http://www.blogjava.net/lihao336/archive/2010/11/22/338677.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Mon, 22 Nov 2010 05:26:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/11/22/338677.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/338677.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/11/22/338677.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/338677.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/338677.html</trackback:ping><description><![CDATA[背景：<br />
用户按下Home键将程序置于后台运行或者应用启动其他activity，比如系统浏览器，短信等，需要向系统发送通知，用户做完别的操作后，点击通知栏，回到应用。<br />
<br />
问题一<br />
在什么时机发送通知？<br />
用户按下Home的事件在应用层时捕捉不到的，因此只能从activity生命周期方法着手。<br />
<br />
方法一：<br />
系统所有activity继承一个BaseActivity，在BaseActivity中维护一个当前可见的activity数组：<br />
protected static ArrayList<activity> sVisibleActivities = new ArrayList<activity>();<br />
<br />
在onResume中，将当前activity保存，同时清除所有通知：<br />
protected void onResume()<br />
{<br />
if (!sVisibleActivities.contains(this))<br />
{<br />
sVisibleActivities.add(this);<br />
}<br />
<br />
// 清除系统消息<br />
mNotificationManager.cancel(R.id.notify);<br />
}<br />
<br />
在onStop中，清除保存的当前activity：<br />
protected void onStop()<br />
{<br />
if (sVisibleActivities.contains(this))<br />
{<br />
sVisibleActivities.remove(this);<br />
}<br />
<br />
// 如果当前没有可见的activity，则发送系统通知<br />
if (sVisibleActivities.isEmpty())<br />
{<br />
sendBackgroundNotify();<br />
}<br />
<br />
super.onStop();<br />
}<br />
<br />
这种方式在大多数情况下工作良好，可以达到需求，但是问题时，当前台的activity被至于后台时，onStop()方法不一定会被调用，因此通知有可能不会被发出！<br />
<br />
方法二：<br />
几经周折，发现activity有一个生命周期方法可以达到目的：<br />
<br />
</activity></activity>
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff;">protected</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;onUserLeaveHint&nbsp;()<br />
<br />
Since:&nbsp;API&nbsp;Level&nbsp;</span><span style="color: #000000;">3</span><span style="color: #000000;"><br />
Called&nbsp;as&nbsp;part&nbsp;of&nbsp;the&nbsp;activity&nbsp;lifecycle&nbsp;when&nbsp;an&nbsp;activity&nbsp;is&nbsp;about&nbsp;to&nbsp;go&nbsp;into&nbsp;the&nbsp;background&nbsp;as&nbsp;the&nbsp;result&nbsp;of&nbsp;user&nbsp;choice. <br />
For&nbsp;example,&nbsp;when&nbsp;the&nbsp;user&nbsp;presses&nbsp;the&nbsp;Home&nbsp;key,&nbsp;onUserLeaveHint()&nbsp;will&nbsp;be&nbsp;called,&nbsp;but&nbsp;when&nbsp;an&nbsp;incoming&nbsp;phone&nbsp;call&nbsp;causes&nbsp;the&nbsp;in</span><span style="color: #000000;">-</span><span style="color: #000000;">call&nbsp;Activity&nbsp;to&nbsp;be&nbsp;automatically&nbsp;brought&nbsp;to&nbsp;the&nbsp;foreground,<br />
&nbsp;onUserLeaveHint()&nbsp;will&nbsp;not&nbsp;be&nbsp;called&nbsp;on&nbsp;the&nbsp;activity&nbsp;being&nbsp;interrupted.&nbsp;In&nbsp;cases&nbsp;when&nbsp;it&nbsp;is&nbsp;invoked,&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">&nbsp;method&nbsp;is&nbsp;called&nbsp;right&nbsp;before&nbsp;the&nbsp;activity</span><span style="color: #000000;">'</span><span style="color: #000000;">s&nbsp;onPause()&nbsp;callback.</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">This&nbsp;callback&nbsp;and&nbsp;onUserInteraction()&nbsp;are&nbsp;intended&nbsp;to&nbsp;help&nbsp;activities&nbsp;manage&nbsp;status&nbsp;bar&nbsp;notifications&nbsp;intelligently;&nbsp;specifically,&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;helping&nbsp;activities&nbsp;determine&nbsp;the&nbsp;proper&nbsp;time&nbsp;to&nbsp;cancel&nbsp;a&nbsp;notfication.</span></div>
<activity><activity><br />
从文档来看，这个方法似乎就是为了按下Home键时这样的场景设计的。<br />
这样，在onUserLeaveHint里发出系统通知即可。<br />
但是问题又来了，如果启动应用，从一个activity依次调用startActivity，finish关闭自己，启动一个新的activity时，onUserLeaveHint也会被调用....<br />
<br />
再次翻阅文档，发现Intent中的一个Flag：<br />
<br />
</activity></activity>
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;FLAG_ACTIVITY_NO_USER_ACTION<br />
<br />
Since:&nbsp;API&nbsp;Level&nbsp;</span><span style="color: #000000;">3</span><span style="color: #000000;"><br />
If&nbsp;set,&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">&nbsp;flag&nbsp;will&nbsp;prevent&nbsp;the&nbsp;normal&nbsp;onUserLeaveHint()&nbsp;callback&nbsp;from&nbsp;occurring&nbsp;on&nbsp;the&nbsp;current&nbsp;frontmost&nbsp;activity&nbsp;before&nbsp;it&nbsp;is&nbsp;paused&nbsp;as&nbsp;the&nbsp;newly</span><span style="color: #000000;">-</span><span style="color: #000000;">started&nbsp;activity&nbsp;is&nbsp;brought&nbsp;to&nbsp;the&nbsp;front.<br />
<br />
Typically,&nbsp;an&nbsp;activity&nbsp;can&nbsp;rely&nbsp;on&nbsp;that&nbsp;callback&nbsp;to&nbsp;indicate&nbsp;that&nbsp;an&nbsp;explicit&nbsp;user&nbsp;action&nbsp;has&nbsp;caused&nbsp;their&nbsp;activity&nbsp;to&nbsp;be&nbsp;moved&nbsp;out&nbsp;of&nbsp;the&nbsp;foreground. <br />
The&nbsp;callback&nbsp;marks&nbsp;an&nbsp;appropriate&nbsp;point&nbsp;in&nbsp;the&nbsp;activity</span><span style="color: #000000;">'</span><span style="color: #000000;">s&nbsp;lifecycle&nbsp;for&nbsp;it&nbsp;to&nbsp;dismiss&nbsp;any&nbsp;notifications&nbsp;that&nbsp;it&nbsp;intends&nbsp;to&nbsp;display&nbsp;"until&nbsp;the&nbsp;user&nbsp;has&nbsp;seen&nbsp;them,"&nbsp;such&nbsp;as&nbsp;a&nbsp;blinking&nbsp;LED.</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">If&nbsp;an&nbsp;activity&nbsp;is&nbsp;ever&nbsp;started&nbsp;via&nbsp;any&nbsp;non</span><span style="color: #000000;">-</span><span style="color: #000000;">user</span><span style="color: #000000;">-</span><span style="color: #000000;">driven&nbsp;events&nbsp;such&nbsp;as&nbsp;phone</span><span style="color: #000000;">-</span><span style="color: #000000;">call&nbsp;receipt&nbsp;or&nbsp;an&nbsp;alarm&nbsp;handler,&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">&nbsp;flag&nbsp;should&nbsp;be&nbsp;passed&nbsp;to&nbsp;Context.startActivity,&nbsp;ensuring&nbsp;that&nbsp;the&nbsp;pausing&nbsp;activity&nbsp;does&nbsp;not&nbsp;think&nbsp;the&nbsp;user&nbsp;has&nbsp;acknowledged&nbsp;its&nbsp;notification.<br />
</span></div>
<br />
<activity><activity>这正是我想要的，这样，在启动activity时，往intent中加上这个flag，onUserLeaveHint就不会再被调用了，hoory...<br />
</activity></activity>
<img src ="http://www.blogjava.net/lihao336/aggbug/338677.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-11-22 13:26 <a href="http://www.blogjava.net/lihao336/archive/2010/11/22/338677.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>android1.6启动pppd的方式</title><link>http://www.blogjava.net/lihao336/archive/2010/11/19/338480.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Fri, 19 Nov 2010 07:25:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/11/19/338480.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/338480.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/11/19/338480.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/338480.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/338480.html</trackback:ping><description><![CDATA[在1.5中，有个PppLink.java文件，封装了启动pppd进程的接口，但是在1.6版本的时候这个文件被删除了，与之相关的代码也全删了，不知其解，网上搜得解答如下：<br />
<br />
因为高通的方案，采用共享内存的方法，不需要pppd拨号了。google这帮人就认为不需要pppd了，也就把PppLink.java删除了。所以1.6之后，还需要pppd拨号的，就需要把1.5拨号这块移植回来.<br />
<br />
参见：<br />
<a href="http://topic.csdn.net/u/20091022/16/6e5b6a99-3af6-421a-b6f1-e0752e239077.html">http://topic.csdn.net/u/20091022/16/6e5b6a99-3af6-421a-b6f1-e0752e239077.html</a><br />
<br />
<img src ="http://www.blogjava.net/lihao336/aggbug/338480.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-11-19 15:25 <a href="http://www.blogjava.net/lihao336/archive/2010/11/19/338480.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]Task和Activity相关</title><link>http://www.blogjava.net/lihao336/archive/2010/11/19/338478.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Fri, 19 Nov 2010 06:32:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/11/19/338478.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/338478.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/11/19/338478.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/338478.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/338478.html</trackback:ping><description><![CDATA[Task和Activity相关<br />
<br />
这段时间在做一个项目，发现对Task和Activity掌握的还是不牢固。把相关知识整理在这里，方便查阅，有几个Flag没看明白啥意思，也没测试出来效果如何。。。<br />
<br />
android:allowTaskReparenting<br />
用来标记Activity能否从启动的Task移动到有着affinity的Task（当这个Task进入到前台时）——&#8220;true&#8221;，表示能移动，&#8220;false&#8221;，表示它必须呆在启动时呆在的那个Task里。<br />
如果这个特性没有被设定，设定到<application>元素上的allowTaskReparenting特性的值会应用到Activity上。默认值为&#8220;false&#8221;。<br />
一般来说，当Activity启动后，它就与启动它的Task关联，并且在那里耗尽它的整个生命周期。当当前的Task不再显示时，你可以使用这个特性来强制Activity移动到有着affinity的Task中。典型用法是：把一个应用程序的Activity移到另一个应用程序的主Task中。<br />
例如，如果e－mail中包含一个web页的链接，点击它就会启动一个Activity来显示这个页面。这个Activity是由Browser应用程序定义的，但是，现在它作为e－mail Task的一部分。如果它重新宿主到Browser Task里，当Browser下一次进入到前台时，它就能被看见，并且，当e－mail Task再次进入前台时，就看不到它了。<br />
Actvity的affinity是由taskAffinity特性定义的。Task的affinity是通过读取根Activity的affinity决定。因此，根据定义，根Activity总是位于相同affinity的Task里。由于启动模式为&#8220;singleTask&#8221;和&#8220;singleInstance&#8221;的Activity只能位于Task的底部，因此，重新宿主只能限于&#8220;standard&#8221;和&#8220;singleTop&#8221;模式。<br />
<br />
android:alwaysRetainTaskState<br />
用来标记Activity所在的Task的状态是否总是由系统来保持——&#8220;true&#8221;，表示总是；&#8220;false&#8221;，表示在某种情形下允许系统恢复Task到它的初始化状态。默认值是&#8220;false&#8221;。这个特性只针对Task的根Activity有意义；对其它Activity来说，忽略之。<br />
一般来说，特定的情形如当用户从主画面重新选择这个Task时，系统会对这个Task进行清理（从stack中删除位于根Activity之上的所有Activivity）。典型的情况，当用户有一段时间没有访问这个Task时也会这么做，例如30分钟。<br />
然而，当这个特性设为&#8220;true&#8221;时，用户总是能回到这个Task的最新状态，无论他们是如何启动的。这非常有用，例如，像Browser应用程序，这里有很多的状态（例如多个打开的Tab），用户不想丢失这些状态。<br />
<br />
android:clearTaskOnLaunch<br />
用来标记是否从Task中清除所有的Activity，除了根Activity外（每当从主画面重新启动时）——&#8220;true&#8221;，表示总是清除至它的根Activity，&#8220;false&#8221;表示不。默认值是&#8220;false&#8221;。这个特性只对启动一个新的Task的Activity（根Activity）有意义；对Task中其它的Activity忽略。<br />
当这个值为&#8220;true&#8221;，每次用户重新启动这个Task时，都会进入到它的根Activity中，不管这个Task最后在做些什么，也不管用户是使用BACK还是HOME离开的。当这个值为&#8220;false&#8221;时，可能会在一些情形下（参考alwaysRetainTaskState特性）清除Task的Activity，但不总是。<br />
假设，某人从主画面启动了Activity P，并从那里迁移至Activity Q。接下来用户按下HOME，然后返回Activity P。一般，用户可能见到的是Activity Q，因为它是P的Task中最后工作的内容。然而，如果P设定这个特性为&#8220;true&#8221;，当用户按下HOME并使这个Task再次进入前台时，其上的所有的Activity(在这里是Q)都将被清除。因此，当返回到这个Task时，用户只能看到P。<br />
如果这个特性和allowTaskReparenting都设定为&#8220;true&#8221;，那些能重新宿主的Activity会移动到共享affinity的Task中；剩下的Activity都将被抛弃，如上所述。<br />
<br />
android:finishOnTaskLaunch<br />
用来标记当用户再次启动它的Task（在主画面选择这个Task）时已经存在的Activity实例是否要关闭（结束）——&#8220;true&#8221;，表示应该关闭，&#8220;false&#8221;表示不关闭。默认值是&#8220;false&#8221;。<br />
如果这个特性和allowTaskReparenting都设定为&#8220;true&#8221;，这个特性胜出。Activity的affinity忽略。这个Activity不会重新宿主，但是会销毁。<br />
<br />
android:launchMode<br />
用于指示Activity如何启动。这里有四种模式，与Intent对象中的Activity Flags（FLAG_ACTIVITY_*变量）共同作用，来决定Activity如何启动来处理Intent。它们是：<br />
<br />
"standard"<br />
"singleTop"<br />
"singleTask"<br />
"singleInstance"<br />
<br />
默认模式是&#8220;standard&#8221;。<br />
<br />
这些模式可以分成两大组别，&#8220;standard&#8221;和&#8220;singleTop&#8221;一组，&#8220;singleTask&#8221;和&#8220;singleInstance&#8221;一组。具有&#8220;standard&#8221;和&#8220;singleTop&#8221;启动模式的Activity可以实例化很多次。这些实例可以属于任何Task并且可以位于Activity stack的任何位置。典型的情况是，它们会进入调用startActivity()的Task（除非Intent对象包含FLAG_ACTIVITY_NEW_TASK标志，在这种情况下会选择一个不同的Task——参考taskAffinity特性）。<br />
相反的，&#8220;singleTask&#8221;和&#8220;singleInstance&#8221;只能启动一个Task。它们总是位于Activity stack的底部。甚至，设备一次只能拥有一个Activity的实例——只有一个这样的Task。<br />
&#8220;standard&#8221;和&#8220;singleTop&#8221;模式只在一种情况下有差别：每次有一个新的启动&#8220;standard&#8221;Activity的Intent，就会创建一个新的实例来响应这个Intent。每个实例处理一个Intent。相似的，一个&#8220;singleTop&#8221;的Activity实例也有可能被创建来处理新的Intent。然而，如果目标Task已经有一个存在的实例并且位于stack的顶部，那么，这个实例就会接收到这个新的Intent（调用onNewIntent()）；不会创建新的实例。在其他情况下——例如，如果存在的&#8220;singleTop&#8221;的Activity实例在目标Task中，但不是在stack的顶部，或者它在一个stack的顶部，但不是在目标Task中——新的实例都会被创建并压入stack中。<br />
&#8220;singleTask&#8221;和&#8220;singleInstance&#8221;模式也只在一种情况下有差别：&#8220;singleTask&#8221;Activity允许其它Activity成为它的Task的部分。它位于Activity stack的底部，其它Activity（必须是&#8220;standard&#8221;和&#8220;singleTop&#8221;Activity）可以启动加入到相同的Task中。&#8220;singleInstance&#8221;Activity，换句话说，不允许其它Activity成为它的Task的部分。它是Task中的唯一Activity。如果它启动其它的Activity，这个Activity会被放置到另一个task中——好像Intent中包含了FLAG_ACTIVITY_NEW_TASK标志。<br />
<br />
android:noHistory<br />
用于标记当用户从Activity上离开并且它在屏幕上不再可见时Activity是否从Activity stack中清除并结束（调用finish()方法）——&#8220;true&#8221;，表示它应该关闭，&#8220;false&#8221;，表示不需要。默认值是&#8220;false&#8221;。<br />
&#8220;true&#8221;值意味着Activity不会留下历史痕迹。因为它不会在Activity stack的Task中保留，因此，用户不能返回它。<br />
<br />
android:taskAffinity<br />
Activity为Task拥有的一个affinity。拥有相同的affinity的Activity理论上属于相同的Task（在用户的角度是相同的&#8220;应用程序&#8221;）。Task的affinity是由它的根Activity决定的。 <br />
affinity决定两件事情——Activity重新宿主的Task（参考allowTaskReparenting特性）和使用FLAG_ACTIVITY_NEW_TASK标志启动的Activity宿主的Task。<br />
默认情况，一个应用程序中的所有Activity都拥有相同的affinity。捏可以设定这个特性来重组它们，甚至可以把不同应用程序中定义的Activity放置到相同的Task中。为了明确Activity不宿主特定的Task，设定该特性为空的字符串。<br />
如果这个特性没有设置，Activity将从应用程序的设定那里继承下来（参考<application>元素的taskAffinity特性）。应用程序默认的affinity的名字是<manifest>元素中设定的package名。<br />
<br />
FLAG_ACTIVITY_BROUGHT_TO_FRONT <br />
这个标志一般不是由程序代码设置的，如在launchMode中设置singleTask模式时系统帮你设定。<br />
<br />
FLAG_ACTIVITY_CLEAR_TOP<br />
如果设置，并且这个Activity已经在当前的Task中运行，因此，不再是重新启动一个这个Activity的实例，而是在这个Activity上方的所有Activity都将关闭，然后这个Intent会作为一个新的Intent投递到老的Activity（现在位于顶端）中。<br />
例如，假设一个Task中包含这些Activity：A，B，C，D。如果D调用了startActivity()，并且包含一个指向Activity B的Intent，那么，C和D都将结束，然后B接收到这个Intent，因此，目前stack的状况是：A，B。<br />
上例中正在运行的Activity B既可以在onNewIntent()中接收到这个新的Intent，也可以把自己关闭然后重新启动来接收这个Intent。如果它的启动模式声明为&#8220;multiple&#8221;(默认值)，并且你没有在这个Intent中设置FLAG_ACTIVITY_SINGLE_TOP标志，那么它将关闭然后重新创建；对于其它的启动模式，或者在这个Intent中设置FLAG_ACTIVITY_SINGLE_TOP标志，都将把这个Intent投递到当前这个实例的onNewIntent()中。<br />
这个启动模式还可以与FLAG_ACTIVITY_NEW_TASK结合起来使用：用于启动一个Task中的根Activity，它会把那个Task中任何运行的实例带入前台，然后清除它直到根Activity。这非常有用，例如，当从Notification Manager处启动一个Activity。<br />
<br />
FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET<br />
如果设置，这将在Task的Activity stack中设置一个还原点，当Task恢复时，需要清理Activity。也就是说，下一次Task带着FLAG_ACTIVITY_RESET_TASK_IF_NEEDED标记进入前台时（典型的操作是用户在主画面重启它），这个Activity和它之上的都将关闭，以至于用户不能再返回到它们，但是可以回到之前的Activity。<br />
这在你的程序有分割点的时候很有用。例如，一个e-mail应用程序可能有一个操作是查看一个附件，需要启动图片浏览Activity来显示。这个Activity应该作为e-mail应用程序Task的一部分，因为这是用户在这个Task中触发的操作。然而，当用户离开这个Task，然后从主画面选择e-mail app，我们可能希望回到查看的会话中，但不是查看图片附件，因为这让人困惑。通过在启动图片浏览时设定这个标志，浏览及其它启动的Activity在下次用户返回到mail程序时都将全部清除。<br />
<br />
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS<br />
如果设置，新的Activity不会在最近启动的Activity的列表中保存。<br />
<br />
FLAG_ACTIVITY_FORWARD_RESULT<br />
如果设置，并且这个Intent用于从一个存在的Activity启动一个新的Activity，那么，这个作为答复目标的Activity将会传到这个新的Activity中。这种方式下，新的Activity可以调用setResult(int)，并且这个结果值将发送给那个作为答复目标的Activity。<br />
<br />
FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY <br />
这个标志一般不由应用程序代码设置，如果这个Activity是从历史记录里启动的（常按HOME键），那么，系统会帮你设定。<br />
<br />
FLAG_ACTIVITY_MULTIPLE_TASK <br />
不要使用这个标志，除非你自己实现了应用程序启动器。与FLAG_ACTIVITY_NEW_TASK结合起来使用，可以禁用把已存的Task送入前台的行为。当设置时，新的Task总是会启动来处理Intent，而不管这是是否已经有一个Task可以处理相同的事情。<br />
由于默认的系统不包含图形Task管理功能，因此，你不应该使用这个标志，除非你提供给用户一种方式可以返回到已经启动的Task。<br />
如果FLAG_ACTIVITY_NEW_TASK标志没有设置，这个标志被忽略。<br />
<br />
FLAG_ACTIVITY_NEW_TASK <br />
如果设置，这个Activity会成为历史stack中一个新Task的开始。一个Task（从启动它的Activity到下一个Task中的Activity）定义了用户可以迁移的Activity原子组。Task可以移动到前台和后台；在某个特定Task中的所有Activity总是保持相同的次序。<br />
这个标志一般用于呈现&#8220;启动&#8221;类型的行为：它们提供用户一系列可以单独完成的事情，与启动它们的Activity完全无关。<br />
使用这个标志，如果正在启动的Activity的Task已经在运行的话，那么，新的Activity将不会启动；代替的，当前Task会简单的移入前台。参考FLAG_ACTIVITY_MULTIPLE_TASK标志，可以禁用这一行为。<br />
这个标志不能用于调用方对已经启动的Activity请求结果。<br />
<br />
FLAG_ACTIVITY_NO_ANIMATION <br />
如果在Intent中设置，并传递给Context.startActivity()的话，这个标志将阻止系统进入下一个Activity时应用Acitivity迁移动画。这并不意味着动画将永不运行——如果另一个Activity在启动显示之前，没有指定这个标志，那么，动画将被应用。这个标志可以很好的用于执行一连串的操作，而动画被看作是更高一级的事件的驱动。<br />
<br />
FLAG_ACTIVITY_NO_HISTORY <br />
如果设置，新的Activity将不再历史stack中保留。用户一离开它，这个Activity就关闭了。这也可以通过设置noHistory特性。<br />
<br />
FLAG_ACTIVITY_NO_USER_ACTION <br />
如果设置，作为新启动的Activity进入前台时，这个标志将在Activity暂停之前阻止从最前方的Activity回调的onUserLeaveHint()。<br />
典型的，一个Activity可以依赖这个回调指明显式的用户动作引起的Activity移出后台。这个回调在Activity的生命周期中标记一个合适的点，并关闭一些Notification。<br />
如果一个Activity通过非用户驱动的事件，如来电或闹钟，启动的，这个标志也应该传递给Context.startActivity，保证暂停的Activity不认为用户已经知晓其Notification。<br />
<br />
FLAG_ACTIVITY_PREVIOUS_IS_TOP <br />
If set and this intent is being used to launch a new activity from an existing one, the current activity will not be counted as the top activity for deciding whether the new intent should be delivered to the top instead of starting a new one. The previous activity will be used as the top, with the assumption being that the current activity will finish itself immediately. <br />
<br />
FLAG_ACTIVITY_REORDER_TO_FRONT<br />
如果在Intent中设置，并传递给Context.startActivity()，这个标志将引发已经运行的Activity移动到历史stack的顶端。<br />
例如，假设一个Task由四个Activity组成：A,B,C,D。如果D调用startActivity()来启动Activity B，那么，B会移动到历史stack的顶端，现在的次序变成A,C,D,B。如果FLAG_ACTIVITY_CLEAR_TOP标志也设置的话，那么这个标志将被忽略。<br />
<br />
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED<br />
<br />
If set, and this activity is either being started in a new task or bringing to the top an existing task, then it will be launched as the front door of the task. This will result in the application of any affinities needed to have that task in the proper state (either moving activities to or from it), or simply resetting that task to its initial state if needed. <br />
<br />
FLAG_ACTIVITY_SINGLE_TOP<br />
如果设置，当这个Activity位于历史stack的顶端运行时，不再启动一个新的。 <br />
<br />
<br />
Activity和Task<br />
<br />
之前提到的，一个Activity可以启动另一个，即便是定义在不同应用程序中的Activity。例如，假设你想让用户显示一些地方的街景。而这里已经有一个Activity可以做到这一点，因此，你的Activity所需要做的只是在Intent对象中添加必要的信息，并传递给startActivity()。地图浏览将会显示你的地图。当用户按下BACK键，你的Activity会再次出现在屏幕上。<br />
<br />
对于用户来说，看起来好像是地图浏览与你的Activity一样，属于相同的应用程序，即便是它定义在其它的应用程序里，并运行在那个应用程序的进程里。Android通过将这两个Activity保存在同一个Task里来体现这一用户体验。简单来说，一个Task就是用户体验上的一个&#8220;应用&#8221;。它将相关的Activity组合在一起，以stack的方式管理。stack中根Activity启动Task——典型的，它就是用户在应用程序启动栏中选择的Activity。位于stack顶端的Activity是当前正在运行的——能够聚焦用户的动作。当一个Activity启动另一个，新的Activity进入stack；它成为正在运行的Activity。之前的Activity仍保留在stack中。当用户按下BACK键，当前的Activity从stack中退出，之前的那个成为正在运行的Activity。<br />
<br />
stack包含对象，因此，如果一个Task中有多个同一个Activity的实例时——多个地图浏览，例如——stack为每个实例拥有一个独立的入口。位于stack中的Activity不会重新调整，只是进入和退出。<br />
<br />
一个Task就是一组Activity，不是一个类或者在manifest中定义的一个元素。因此，没有办法为Task设置独立于它的Activity的属性值。Task的值作为整体在根Activity中设置。例如，下一个章节会讨论Task的&#8220;affinity&#8221;；那个值就是从Task中的根Activity中读取的。<br />
<br />
Task中的所有Activity作为一个单元一起移动。整个Task（整个Activity stack）可以进入前台或者退到后台。例如，假设当前Task中的stack中有4个Activity——3个位于当前Activity下方。用户按下HOME键，进入到应用程序启动栏，然后选择一个新的应用程序（实际上，一个新的Task）。当前Task退到后台，并且新Task中的根Activity会显示出来。然后，经过一段时间后，用户回到Home画面，然后再次选择前一个应用程序（前一个Task）。那个拥有4个Activity的Task会进入前台。当用户按下BACK键，屏幕不会显示用户刚刚离开的Activity（前一个Task的根Activity）。而是，这个stack中的顶端Activity移除，相同Task中的前一个Activity会显示出来。<br />
<br />
刚才描述的行为是Activity和Task的默认行为。但有方法来完全改变它。Task之间的关联，和一个Task中的一个Activity行为，受启动Activity的Intent对象中设置的Flag和manifest文件中Activity的<activity>元素的特性值交互控制。调用者和响应者都有权决定如何发生。<br />
<br />
核心的Intent Flag有：<br />
FLAG_ACTIVITY_NEW_TASK<br />
FLAG_ACTIVITY_CLEAR_TOP<br />
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED<br />
FLAG_ACTIVITY_SINGLE_TOP<br />
<br />
核心的<activity>特性有：<br />
taskAffinity<br />
launchMode<br />
allowTaskReparenting<br />
clearTaskOnLaunch<br />
alwaysRetainTaskState<br />
finishOnTaskLaunch<br />
<br />
接下来的章节将描述一些Flag和特性的用法，如何相互影响，以及在使用时的建议。<br />
<br />
Affinity和新Task<br />
默认情况下，一个应用程序中的所有Activity都有affinity——也就是说，属于同一个Task中所有Activity有一个设定。然而，每个Activity都可以在<activity>元素的taskAffinity特性上设置单独的值。定义在不同应用程序中的Activity可以共享同一个affinity，或者定义在同一个应用程序中的Activity设置不同的affinity。Affinity在两种环境下工作：Intent对象包含FLAG_ACTIVITY_NEW_TASK标志，和Activity的allowTaskReparenting特性设置为&#8220;true&#8221;。<br />
FLAG_ACTIVITY_NEW_TASK:<br />
之前描述的，一个Activity一般通过调用startActivity()启动并加入到Task中。它同调用者一样，进入同一个Task。然而，如果传递给startActivity()的Intent对象中包含FLAG_ACTIVITY_NEW_TASK时，系统会搜索一个新的Task来容纳新的Activity。通常，如标志的名字所示，是一个新的Task。然而，并不是必须是。如果已经存在一个Task与新Activity的affinity相同，这个Activity就会加入到那个Task中。如果不是，启动一个新的Task。<br />
allowTaskReparenting：<br />
如果一个Activity的allowTaskReparenting特性设置为&#8220;true&#8221;，它就能从启动的Task中移到有着相同affinity的Task（这个Task进入到前台的时候）。例如，在一个旅游的程序中定义了一个可以报告选择城市的天气情况的Activity。它和同一个应用程序的其它Activity一样，有着相同的Affinity（默认的Affinity），并且它允许重新宿主。你的Activity中的一个启动了天气预报，因此，它初始化到和你Activity相同的Task中。然而，当旅游应用程序下一次进入到前台时，天气预报那个Activity将会重新编排并在那个Task中显示。<br />
<br />
如果从用户的角度出发，一个.apk文件包含多个&#8220;应用&#8221;的话，你可能希望为关联的Activity设置不同的affinity。<br />
<br />
Launch Mode<br />
<br />
这里4种不同的启动模式可以设置到<activity>元素的launchMode特性上：<br />
standard（默认模式）<br />
singleTop<br />
singleTask<br />
singleInstance<br />
<br />
这些模式有以下四点区别：<br />
l  哪个Task将容纳响应Intent的Activity。对于&#8220;standard&#8221;和&#8220;singleTop&#8221;来说，是产生Intent的那个Task（并调用startActivity()）——除非Intent对象包含FLAG_ACTIVITY_NEW_TASK。在那种情况下，不同的Task将被选择，如&#8220;Affinity和新Task&#8221;中描述的那样。对比而言，&#8220;singleTask&#8221;和&#8220;singleInstance&#8221;指示Activity总是一个Task的根。它们定义一个Task；它们不会加入到另一个Task中。<br />
l  是否有多个Activity的实例。&#8220;standard&#8221;和&#8220;singleTop&#8221;可以实例化多次。它们可以属于多个Task，一个特定的Task可以有相同Activity的多个实例。对比而言，&#8220;singleTask&#8221;和&#8220;singleInstance&#8221;只能有一个实例。因为这些Activity只能位于Task的底部，这一限制意味着在设备的某个时间，不会出现这样Task的多个实例。<br />
l  是否可以在同一个Task中拥有其它的Activity。&#8220;singleInstance&#8221;Activity保持单身，在它的Task中它是仅有的Activity。如果它启动另一个Activity，那个Activity将会放入到不同的Task中，而不管它的启动模式——好像FLAG_ACTIVITY_NEW_TASK在Intent中一样。对于其它方面，，&#8220;singleInstance&#8221;等同于&#8220;singleTask&#8221;。其它三个模式允许多个Activity加入到这个Task中。&#8220;singleTask&#8221;Activity总是位于Task的底部，但它可以启动其它的Activity并放入到它的Task中。&#8220;standard&#8221;和&#8220;singleTop&#8221;的Activity可以出现在stack的任何地方。<br />
l  是否一个新的实例启动来处理新的Intent。对于默认的&#8220;standard&#8221;来说，都是创建一个新的实例来响应新的Intent。每个实例处理一个Intent。对于&#8220;singleTop&#8221;来说，如果它位于目标Task的顶端，那么，已经存在的实例就可以重复使用来处理这个新的Intent。如果它不在顶端，那么它就不能重复使用。替代的，新的实例将创建来响应新的Intent，并进入到stack中。<br />
例如，假设一个Task的Activity stack中包含根Activity A和其它Activity B，C，D，并且D位于顶端，因此，stack是A-B-C-D。有一个Intent来了，它要启动D类型的Activity。如果D有默认的&#8220;standard&#8221;启动模式，那么，一个新的实例将被启动并且stack变成A-B-C-D-D。然而，如果D的启动模式&#8220;singleTop&#8221;，已经存在的实例将去处理新来的Intent（因为它正好处在stack的顶端），并且stack依旧是A-B-C-D。<br />
换句话说，如果来临的Intent是冲着B类型的，那么，B类型的实例将被创建启动而不管B的模式是&#8220;standard&#8221;或&#8220;singleTop&#8221;（因为B不处在stack的顶端），因此，stack将会是A-B-C-D-B。<br />
之前提到的，设备上不会出现超过一个实例的&#8220;singleTask&#8221;或&#8220;singleInstance&#8221;Activity，因此，那个实例都将去处理所有新来的Intent。&#8220;singleInstance&#8221;Activity总是位于stack的顶端（因为它是task中唯一的Activity），因此，它总是处于能处理Intent的位置。然而，&#8220;singleTask&#8221;Activity可能有或没有其它Activity处于它的上方。如果有，它就不处于能处理Intent的位置，那么，这个Intent将被丢弃。（即使Intent被丢弃了，它的到来会引发那个Task进入到前台，在那里，它会继续保留。）<br />
<br />
当一个存在的Activity请求去处理一个新的Intent时，Intent对象将传到该Activity的onNewIntent()的方法中。（原来启动Activity的Intent对象可以通过调用getIntent()得到。）<br />
<br />
注意：当一个新的实例创建来处理新的Intent时，用户可以按下BACK键返回到之前的状态（前一个Activity）。但一个存在的实例来处理新的Intent时，用户不能按下BACK键返回到新Intent到来之前的状态。<br />
<br />
清除stack<br />
如果用户离开Task很长一段时间，系统会清除Task中的所有Activity，除根Activity外。当用户再次返回到这个Task时，和用户离开时一样，仅仅只是初始化Activity呈现。这样做的意图是，经过一些时间后，用户可能已经忘记之前正在做的事情，并且打算回到Task开始些新的时期。<br />
<br />
这是默认情况。这里有一些Activity特性可以用于控制这一行为并且修改它：<br />
alwaysRetainTaskState：<br />
如果Task的根Activity的这个特性设置为&#8220;true&#8221;时，上面描述的默认行为不会发生。Task保留所有的Activity，即便是经过很长一段时间。<br />
clearTaskOnLaunch：<br />
如果Task的根Activity的这个特性设置为&#8220;true&#8221;时，当用户离开Task并返回时，stack会清除直到根Activity。换句话说，它是alwaysRetainTaskState的另一个极端。用户总是回到Task的初始化状态，即便是一个短暂的离开。<br />
finishOnTaskLaunch：<br />
这个特性和clearTaskOnLaunch相似，但它针对单个Activity，不是整个Task。它能使任何Activity消失，包括根Activity。当它设置为&#8220;true&#8221;时，这个Activity仅在当前会话期间保持为Task的部分。如果用户离开并再次返回到这个Task，它就不再显示了。<br />
<br />
这里还有其它的方式可以强制Activity从stack中移除。如果Intent对象中包含FLAG_ACTIVITY_CLEAR_TOP标志，并且目标Task中已经有一个这个类型Activity的实例，而且这个实例应该处理这个Intent，那么，位于其上的Activity都将移除，这样，这个Activity就能在stack的顶端并响应这个Intent。如果这个Activity的启动模式设定为&#8220;standard&#8221;，它也会从stack中清除，然后新的实例启动来响应这个Intent。这是因为当启动模式设定为&#8220;standard&#8220;时，总是会创建一个新的实例来响应新的Intent。<br />
<br />
FLAG_ACTIVITY_CLEAR_TOP经常与FLAG_ACTIVITY_NEW_TASK结合起来使用。当一起使用时，这些标志可以定位其它Task中已经存在的Activity，并且把它置于可以响应Intent的位置。<br />
<br />
启动Task<br />
如果一个Activity的Intent Filter的action为&#8220;android.intent.action.MAIN&#8221;、category为&#8220;android.intent.category.LAUNCHER&#8221;时，它就可以作为一个Task的入口点。有这种类型的Filter会在导致这个Activity在应用程序启动栏显示一个图标和标签，给用户提供一个方式可以启动这个Task和在任何时候可以再次回到这个Task。<br />
<br />
第二个能力很重要：用户一定可以离开一个Task，然后可以再次回到它。基于这个原因，两个启动模式，&#8220;singleTask&#8221;和&#8220;singleInstance&#8221;应该只在有MAIN和LAUNCHER的Activity上使用。例如，假设这个Filter没有的话：一个Intent启动了一个&#8220;singleTask&#8221;Activity，初始化一个新的Task，然后用户花费了一些时间在它上面。然后，用户按下HOME键。现在，这个Task处于后台并且被HOME画面遮盖。由于它不能在应用程序启动栏显示，用户就没有办法可以返回它。<br />
<br />
在面对FLAG_ACTIVITY_NEW_TASK时，也有相似的困难。如果这个标志导致一个Activity启动了一个新的Task，并且用户按下HOME键离开它，这里必须有方法可以再次回到它。一些机能（如Notification Manager）总是在外部的Task中启动Activity，而不是作为自己的一部分，因此，它总是把FLAG_ACTIVITY_NEW_TASK标志放入Intent，然后传递给startActivity()。如果你的Activity可能会被外部的机能（可能使用这个标志）调用，注意用户可以额外的方式可以返回到启动的Task。<br />
<br />
如果你不想用户回到某个Activity，可以把<activity>元素的finishOnTaskLaunch设置为&#8220;true&#8221;。<br />
<br />
</activity></activity></activity></activity></activity></manifest></application></application><a href="http://www.cnblogs.com/xirihanlin/archive/2010/06/03/1750811.html">http://www.cnblogs.com/xirihanlin/archive/2010/06/03/1750811.html</a><br />
<img src ="http://www.blogjava.net/lihao336/aggbug/338478.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-11-19 14:32 <a href="http://www.blogjava.net/lihao336/archive/2010/11/19/338478.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Handler与Android进程管理</title><link>http://www.blogjava.net/lihao336/archive/2010/10/27/336309.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Wed, 27 Oct 2010 11:01:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/10/27/336309.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/336309.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/10/27/336309.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/336309.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/336309.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/lihao336/archive/2010/10/27/336309.html'>阅读全文</a><img src ="http://www.blogjava.net/lihao336/aggbug/336309.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-10-27 19:01 <a href="http://www.blogjava.net/lihao336/archive/2010/10/27/336309.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>调试跟踪Android源代码</title><link>http://www.blogjava.net/lihao336/archive/2010/10/25/336058.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Mon, 25 Oct 2010 02:09:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/10/25/336058.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/336058.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/10/25/336058.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/336058.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/336058.html</trackback:ping><description><![CDATA[1、编译android&nbsp;代码树，编译sdk；<br />
编译注意：<br />
1）gcc的版本过高，由于android源码编译要求为4.3，如果你的gcc版本为4.4，那你的编译可能会失败的！我的系统是ubuntu 10.04,默认的gcc版本为4.4，gcc-4.4太严格，那么怎样从gcc-4.4降到gcc- 4.3呢？<br />
1、安装gcc-4.3<br />
$ sudo apt-get install gcc-4.3 g++-4.3<br />
2、修gcc相关链接<br />
$ cd /usr/bin<br />
$sudo ln -snf gcc-4.3 gcc<br />
$sudo ln -snf g++-4.3 g++<br />
$sudo ln -snf cpp-4.3 cpp<br />
<br />
将gcc,g++链接至4.3版本即可。<br />
<br />
2）JDK 5.0, update 12 or higher.Java 6 is not supported, because of incompatibilities with @Override.<br />
<br />
3）$ sudo apt-get install git-core gnupg flex bison gperf build-essential zip curl sun-java5-jdk zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev ia32-libs x11proto-core-dev libx11-dev lib32readline5-dev lib32z-dev<br />
参见http://source.android.com/source/download.html<br />
<br />
2、拷贝development/ide/eclipse/.classpath到.classpath.<br />
<br />
3、启动 eclipse ，按照这个步骤 File-&gt;New-&gt;Java Project (不是 Android Project!) -&gt;Create project from existing source 选到代码树根目录 .<br />
<br />
4、在经过长时间等待之后， source code将被导入project，正常情况下应该没有error。<br />
<br />
5启动模拟器<br />
[calvin@calvin-desktop ~/android/source-code/android_1.5_Sourcecode 10:28:03 ] $ . build/envsetup.sh <br />
[calvin@calvin-desktop ~/android/source-code/android_1.5_Sourcecode 10:28:18 ] $ lunch 1<br />
[calvin@calvin-desktop ~/android/source-code/android_1.5_Sourcecode 10:30:31 ] $ ./out/host/linux-x86/bin/emulator<br />
<br />
6、<strong>在ddms中选中要调试的进程</strong><br />
<br />
7、在source code中设置断点<br />
<br />
8、在eclipse里, Run-&gt;Debug Configuration-&gt;Remote Java Application-&gt;New, 设置 Connection port to 8700 (DDMS&#8217;s 默认端口),即可正常调试了<br />
<span class="Apple-style-span" style="border-collapse: separate; color: #000000; font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium;"></span>
<img src ="http://www.blogjava.net/lihao336/aggbug/336058.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-10-25 10:09 <a href="http://www.blogjava.net/lihao336/archive/2010/10/25/336058.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>滚动时显示scrollbar</title><link>http://www.blogjava.net/lihao336/archive/2010/10/18/335455.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Mon, 18 Oct 2010 06:25:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/10/18/335455.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/335455.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/10/18/335455.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/335455.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/335455.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/lihao336/archive/2010/10/18/335455.html'>阅读全文</a><img src ="http://www.blogjava.net/lihao336/aggbug/335455.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-10-18 14:25 <a href="http://www.blogjava.net/lihao336/archive/2010/10/18/335455.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Building, running, and debugging Android source</title><link>http://www.blogjava.net/lihao336/archive/2010/10/17/335355.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Sun, 17 Oct 2010 06:05:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/10/17/335355.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/335355.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/10/17/335355.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/335355.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/335355.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/lihao336/archive/2010/10/17/335355.html'>阅读全文</a><img src ="http://www.blogjava.net/lihao336/aggbug/335355.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-10-17 14:05 <a href="http://www.blogjava.net/lihao336/archive/2010/10/17/335355.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>android调试工具集</title><link>http://www.blogjava.net/lihao336/archive/2010/10/02/333674.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Sat, 02 Oct 2010 14:44:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/10/02/333674.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/333674.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/10/02/333674.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/333674.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/333674.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/lihao336/archive/2010/10/02/333674.html'>阅读全文</a><img src ="http://www.blogjava.net/lihao336/aggbug/333674.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-10-02 22:44 <a href="http://www.blogjava.net/lihao336/archive/2010/10/02/333674.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Android关机界面代码</title><link>http://www.blogjava.net/lihao336/archive/2010/10/02/333671.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Sat, 02 Oct 2010 13:39:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/10/02/333671.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/333671.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/10/02/333671.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/333671.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/333671.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/lihao336/archive/2010/10/02/333671.html'>阅读全文</a><img src ="http://www.blogjava.net/lihao336/aggbug/333671.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-10-02 21:39 <a href="http://www.blogjava.net/lihao336/archive/2010/10/02/333671.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HTTP/1.1 Cache-Control的理解</title><link>http://www.blogjava.net/lihao336/archive/2010/09/29/333429.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Wed, 29 Sep 2010 13:43:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/09/29/333429.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/333429.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/09/29/333429.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/333429.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/333429.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/lihao336/archive/2010/09/29/333429.html'>阅读全文</a><img src ="http://www.blogjava.net/lihao336/aggbug/333429.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-09-29 21:43 <a href="http://www.blogjava.net/lihao336/archive/2010/09/29/333429.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>