当前位置:  编程技术>移动开发
本页文章导读:
    ▪Task与Activity有关 和 四种加载模式        Task与Activity相关 和 四种加载模式 android:allowTaskReparenting    用来标记Activity能否从启动的Task移动到有着affinity的Task(当这个Task进入到前台时)——“true”,表示能移动,“false”,表示它.........
    ▪ [转]Show Stopper 一次 crash 调试的夺命飞奔        [转]Show Stopper 一次 crash 调试的夺命狂奔 这几天一直在忙着调试 crash 的问题。周末两天都在加班。 周日更是从早上8:00 到晚上 12:50 一直没离开过办公室. 加上这个项目对我们整个开发组.........
    ▪ JAVA 中 replace 跟 replaceAll 的区别       JAVA 中 replace 和 replaceAll 的区别 replace和replaceAll是JAVA中常用的替换字符的方法,它们的区别是:1)replace的参数是char和CharSequence,即可以支持字符的替换,也支持字符串的替换(CharSequence即字符串.........

[1]Task与Activity有关 和 四种加载模式
    来源: 互联网  发布时间: 2014-02-18
Task与Activity相关 和 四种加载模式

android:allowTaskReparenting
    用来标记Activity能否从启动的Task移动到有着affinity的Task(当这个Task进入到前台时)——“true”,表示能移动,“false”,表示它必须呆在启动时呆在的那个Task里。
    如果这个特性没有被设定,设定到<application>元素上的allowTaskReparenting特性的值会应用到Activity上。默认值为“false”。
    一般来说,当Activity启动后,它就与启动它的Task关联,并且在那里耗尽它的整个生命周期。当当前的Task不再显示时,你可以使用这个特性来强制Activity移动到有着affinity的Task中。典型用法是:把一个应用程序的Activity移到另一个应用程序的主Task中。
    例如,如果e-mail中包含一个web页的链接,点击它就会启动一个Activity来显示这个页面。这个Activity是由Browser应用程序定义的,但是,现在它作为e-mail Task的一部分。如果它重新宿主到Browser Task里,当Browser下一次进入到前台时,它就能被看见,并且,当e-mail Task再次进入前台时,就看不到它了。
    Actvity的affinity是由taskAffinity特性定义的。Task的affinity是通过读取根Activity的affinity决定。因此,根据定义,根Activity总是位于相同affinity的Task里。由于启动模式为“singleTask”和“singleInstance”的Activity只能位于Task的底部,因此,重新宿主只能限于“standard”和“singleTop”模式。

android:alwaysRetainTaskState
    用来标记Activity所在的Task的状态是否总是由系统来保持——“true”,表示总是;“false”,表示在某种情形下允许系统恢复Task到它的初始化状态。默认值是“false”。这个特性只针对Task的根Activity有意义;对其它Activity来说,忽略之。
    一般来说,特定的情形如当用户从主画面重新选择这个Task时,系统会对这个Task进行清理(从stack中删除位于根Activity之上的所有Activivity)。典型的情况,当用户有一段时间没有访问这个Task时也会这么做,例如30分钟。
    然而,当这个特性设为“true”时,用户总是能回到这个Task的最新状态,无论他们是如何启动的。这非常有用,例如,像Browser应用程序,这里有很多的状态(例如多个打开的Tab),用户不想丢失这些状态。

android:clearTaskOnLaunch
    用来标记是否从Task中清除所有的Activity,除了根Activity外(每当从主画面重新启动时)——“true”,表示总是清除至它的根Activity,“false”表示不。默认值是“false”。这个特性只对启动一个新的Task的Activity(根Activity)有意义;对Task中其它的Activity忽略。
    当这个值为“true”,每次用户重新启动这个Task时,都会进入到它的根Activity中,不管这个Task最后在做些什么,也不管用户是使用BACK还是HOME离开的。当这个值为“false”时,可能会在一些情形下(参考alwaysRetainTaskState特性)清除Task的Activity,但不总是。
    假设,某人从主画面启动了Activity P,并从那里迁移至Activity Q。接下来用户按下HOME,然后返回Activity P。一般,用户可能见到的是Activity Q,因为它是P的Task中最后工作的内容。然而,如果P设定这个特性为“true”,当用户按下HOME并使这个Task再次进入前台时,其上的所有的Activity(在这里是Q)都将被清除。因此,当返回到这个Task时,用户只能看到P。
    如果这个特性和allowTaskReparenting都设定为“true”,那些能重新宿主的Activity会移动到共享affinity的Task中;剩下的Activity都将被抛弃,如上所述。

android:finishOnTaskLaunch
    用来标记当用户再次启动它的Task(在主画面选择这个Task)时已经存在的Activity实例是否要关闭(结束)——“true”,表示应该关闭,“false”表示不关闭。默认值是“false”。
    如果这个特性和allowTaskReparenting都设定为“true”,这个特性胜出。Activity的affinity忽略。这个Activity不会重新宿主,但是会销毁。

android:launchMode
    用于指示Activity如何启动。这里有四种模式,与Intent对象中的Activity Flags(FLAG_ACTIVITY_*变量)共同作用,来决定Activity如何启动来处理Intent。它们是:

    "standard"
    "singleTop"
    "singleTask"
    "singleInstance"

    默认模式是“standard”。
    
    这些模式可以分成两大组别,“standard”和“singleTop”一组,“singleTask”和“singleInstance”一组。具有“standard”和“singleTop”启动模式的Activity可以实例化很多次。这些实例可以属于任何Task并且可以位于Activity stack的任何位置。典型的情况是,它们会进入调用startActivity()的Task(除非Intent对象包含FLAG_ACTIVITY_NEW_TASK标志,在这种情况下会选择一个不同的Task——参考taskAffinity特性)。
    相反的,“singleTask”和“singleInstance”只能启动一个Task。它们总是位于Activity stack的底部。甚至,设备一次只能拥有一个Activity的实例——只有一个这样的Task。
    “standard”和“singleTop”模式只在一种情况下有差别:每次有一个新的启动“standard”Activity的Intent,就会创建一个新的实例来响应这个Intent。每个实例处理一个Intent。相似的,一个“singleTop”的Activity实例也有可能被创建来处理新的Intent。然而,如果目标Task已经有一个存在的实例并且位于stack的顶部,那么,这个实例就会接收到这个新的Intent(调用onNewIntent());不会创建新的实例。在其他情况下——例如,如果存在的“singleTop”的Activity实例在目标Task中,但不是在stack的顶部,或者它在一个stack的顶部,但不是在目标Task中——新的实例都会被创建并压入stack中。
    “singleTask”和“singleInstance”模式也只在一种情况下有差别:“singleTask”Activity允许其它Activity成为它的Task的部分。它位于Activity stack的底部,其它Activity(必须是“standard”和“singleTop”Activity)可以启动加入到相同的Task中。“singleInstance”Activity,换句话说,不允许其它Activity成为它的Task的部分。它是Task中的唯一Activity。如果它启动其它的Activity,这个Activity会被放置到另一个task中——好像Intent中包含了FLAG_ACTIVITY_NEW_TASK标志。

android:noHistory
    用于标记当用户从Activity上离开并且它在屏幕上不再可见时Activity是否从Activity stack中清除并结束(调用finish()方法)——“true”,表示它应该关闭,“false”,表示不需要。默认值是“false”。
    “true”值意味着Activity不会留下历史痕迹。因为它不会在Activity stack的Task中保留,因此,用户不能返回它。

android:taskAffinity
   Activity为Task拥有的一个affinity。拥有相同的affinity的Activity理论上属于相同的Task(在用户的角度是相同的“应用程序”)。Task的affinity是由它的根Activity决定的。 
   affinity决定两件事情——Activity重新宿主的Task(参考allowTaskReparenting特性)和使用FLAG_ACTIVITY_NEW_TASK标志启动的Activity宿主的Task。
    默认情况,一个应用程序中的所有Activity都拥有相同的affinity。捏可以设定这个特性来重组它们,甚至可以把不同应用程序中定义的Activity放置到相同的Task中。为了明确Activity不宿主特定的Task,设定该特性为空的字符串。
    如果这个特性没有设置,Activity将从应用程序的设定那里继承下来(参考<application>元素的taskAffinity特性)。应用程序默认的affinity的名字是<manifest>元素中设定的package名。

FLAG_ACTIVITY_BROUGHT_TO_FRONT 
    这个标志一般不是由程序代码设置的,如在launchMode中设置singleTask模式时系统帮你设定。

FLAG_ACTIVITY_CLEAR_TOP
    如果设置,并且这个Activity已经在当前的Task中运行,因此,不再是重新启动一个这个Activity的实例,而是在这个Activity上方的所有Activity都将关闭,然后这个Intent会作为一个新的Intent投递到老的Activity(现在位于顶端)中。
    例如,假设一个Task中包含这些Activity:A,B,C,D。如果D调用了startActivity(),并且包含一个指向Activity B的Intent,那么,C和D都将结束,然后B接收到这个Intent,因此,目前stack的状况是:A,B。
    上例中正在运行的Activity B既可以在onNewIntent()中接收到这个新的Intent,也可以把自己关闭然后重新启动来接收这个Intent。如果它的启动模式声明为“multiple”(默认值),并且你没有在这个Intent中设置FLAG_ACTIVITY_SINGLE_TOP标志,那么它将关闭然后重新创建;对于其它的启动模式,或者在这个Intent中设置FLAG_ACTIVITY_SINGLE_TOP标志,都将把这个Intent投递到当前这个实例的onNewIntent()中。
    这个启动模式还可以与FLAG_ACTIVITY_NEW_TASK结合起来使用:用于启动一个Task中的根Activity,它会把那个Task中任何运行的实例带入前台,然后清除它直到根Activity。这非常有用,例如,当从Notification Manager处启动一个Activity。

FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
    如果设置,这将在Task的Activity stack中设置一个还原点,当Task恢复时,需要清理Activity。也就是说,下一次Task带着FLAG_ACTIVITY_RESET_TASK_IF_NEEDED标记进入前台时(典型的操作是用户在主画面重启它),这个Activity和它之上的都将关闭,以至于用户不能再返回到它们,但是可以回到之前的Activity。
    这在你的程序有分割点的时候很有用。例如,一个e-mail应用程序可能有一个操作是查看一个附件,需要启动图片浏览Activity来显示。这个Activity应该作为e-mail应用程序Task的一部分,因为这是用户在这个Task中触发的操作。然而,当用户离开这个Task,然后从主画面选择e-mail app,我们可能希望回到查看的会话中,但不是查看图片附件,因为这让人困惑。通过在启动图片浏览时设定这个标志,浏览及其它启动的Activity在下次用户返回到mail程序时都将全部清除。

FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
    如果设置,新的Activity不会在最近启动的Activity的列表中保存。

FLAG_ACTIVITY_FORWARD_RESULT
    如果设置,并且这个Intent用于从一个存在的Activity启动一个新的Activity,那么,这个作为答复目标的Activity将会传到这个新的Activity中。这种方式下,新的Activity可以调用setResult(int),并且这个结果值将发送给那个作为答复目标的Activity。

FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY 
    这个标志一般不由应用程序代码设置,如果这个Activity是从历史记录里启动的(常按HOME键),那么,系统会帮你设定。

FLAG_ACTIVITY_MULTIPLE_TASK 
    不要使用这个标志,除非你自己实现了应用程序启动器。与FLAG_ACTIVITY_NEW_TASK结合起来使用,可以禁用把已存的Task送入前台的行为。当设置时,新的Task总是会启动来处理Intent,而不管这是是否已经有一个Task可以处理相同的事情。
    由于默认的系统不包含图形Task管理功能,因此,你不应该使用这个标志,除非你提供给用户一种方式可以返回到已经启动的Task。
    如果FLAG_ACTIVITY_NEW_TASK标志没有设置,这个标志被忽略。

FLAG_ACTIVITY_NEW_TASK 
    如果设置,这个Activity会成为历史stack中一个新Task的开始。一个Task(从启动它的Activity到下一个Task中的Activity)定义了用户可以迁移的Activity原子组。Task可以移动到前台和后台;在某个特定Task中的所有Activity总是保持相同的次序。
    这个标志一般用于呈现“启动”类型的行为:它们提供用户一系列可以单独完成的事情,与启动它们的Activity完全无关。
    使用这个标志,如果正在启动的Activity的Task已经在运行的话,那么,新的Activity将不会启动;代替的,当前Task会简单的移入前台。参考FLAG_ACTIVITY_MULTIPLE_TASK标志,可以禁用这一行为。
    这个标志不能用于调用方对已经启动的Activity请求结果。

FLAG_ACTIVITY_NO_ANIMATION 
    如果在Intent中设置,并传递给Context.startActivity()的话,这个标志将阻止系统进入下一个Activity时应用Acitivity迁移动画。这并不意味着动画将永不运行——如果另一个Activity在启动显示之前,没有指定这个标志,那么,动画将被应用。这个标志可以很好的用于执行一连串的操作,而动画被看作是更高一级的事件的驱动。

FLAG_ACTIVITY_NO_HISTORY 
    如果设置,新的Activity将不再历史stack中保留。用户一离开它,这个Activity就关闭了。这也可以通过设置noHistory特性。

FLAG_ACTIVITY_NO_USER_ACTION 
    如果设置,作为新启动的Activity进入前台时,这个标志将在Activity暂停之前阻止从最前方的Activity回调的onUserLeaveHint()。
    典型的,一个Activity可以依赖这个回调指明显式的用户动作引起的Activity移出后台。这个回调在Activity的生命周期中标记一个合适的点,并关闭一些Notification。
    如果一个Activity通过非用户驱动的事件,如来电或闹钟,启动的,这个标志也应该传递给Context.startActivity,保证暂停的Activity不认为用户已经知晓其Notification。

FLAG_ACTIVITY_PREVIOUS_IS_TOP 
    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. 

FLAG_ACTIVITY_REORDER_TO_FRONT
    如果在Intent中设置,并传递给Context.startActivity(),这个标志将引发已经运行的Activity移动到历史stack的顶端。
    例如,假设一个Task由四个Activity组成:A,B,C,D。如果D调用startActivity()来启动Activity B,那么,B会移动到历史stack的顶端,现在的次序变成A,C,D,B。如果FLAG_ACTIVITY_CLEAR_TOP标志也设置的话,那么这个标志将被忽略。

FLAG_ACTIVITY_RESET_TASK_IF_NEEDED

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. 

FLAG_ACTIVITY_SINGLE_TOP
    如果设置,当这个Activity位于历史stack的顶端运行时,不再启动一个新的。 

Activity和Task

 

之前提到的,一个Activity可以启动另一个,即便是定义在不同应用程序中的Activity。例如,假设你想让用户显示一些地方的街景。而这里已经有一个Activity可以做到这一点,因此,你的Activity所需要做的只是在Intent对象中添加必要的信息,并传递给startActivity()。地图浏览将会显示你的地图。当用户按下BACK键,你的Activity会再次出现在屏幕上。

 

对于用户来说,看起来好像是地图浏览与你的Activity一样,属于相同的应用程序,即便是它定义在其它的应用程序里,并运行在那个应用程序的进程里。Android通过将这两个Activity保存在同一个Task里来体现这一用户体验。简单来说,一个Task就是用户体验上的一个“应用”。它将相关的Activity组合在一起,以stack的方式管理。stack中根Activity启动Task——典型的,它就是用户在应用程序启动栏中选择的Activity。位于stack顶端的Activity是当前正在运行的——能够聚焦用户的动作。当一个Activity启动另一个,新的Activity进入stack;它成为正在运行的Activity。之前的Activity仍保留在stack中。当用户按下BACK键,当前的Activity从stack中退出,之前的那个成为正在运行的Activity。

 

stack包含对象,因此,如果一个Task中有多个同一个Activity的实例时——多个地图浏览,例如——stack为每个实例拥有一个独立的入口。位于stack中的Activity不会重新调整,只是进入和退出。

 

一个Task就是一组Activity,不是一个类或者在manifest中定义的一个元素。因此,没有办法为Task设置独立于它的Activity的属性值。Task的值作为整体在根Activity中设置。例如,下一个章节会讨论Task的“affinity”;那个值就是从Task中的根Activity中读取的。

 

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会显示出来。

 

刚才描述的行为是Activity和Task的默认行为。但有方法来完全改变它。Task之间的关联,和一个Task中的一个Activity行为,受启动Activity的Intent对象中设置的Flag和manifest文件中Activity的<activity>元素的特性值交互控制。调用者和响应者都有权决定如何发生。

 

核心的Intent Flag有:

FLAG_ACTIVITY_NEW_TASK

FLAG_ACTIVITY_CLEAR_TOP

FLAG_ACTIVITY_RESET_TASK_IF_NEEDED

FLAG_ACTIVITY_SINGLE_TOP

 

核心的<activity>特性有:

taskAffinity

launchMode

allowTaskReparenting

clearTaskOnLaunch

alwaysRetainTaskState

finishOnTaskLaunch

 

接下来的章节将描述一些Flag和特性的用法,如何相互影响,以及在使用时的建议。

 

Affinity和新Task

默认情况下,一个应用程序中的所有Activity都有affinity——也就是说,属于同一个Task中所有Activity有一个设定。然而,每个Activity都可以在<activity>元素的taskAffinity特性上设置单独的值。定义在不同应用程序中的Activity可以共享同一个affinity,或者定义在同一个应用程序中的Activity设置不同的affinity。Affinity在两种环境下工作:Intent对象包含FLAG_ACTIVITY_NEW_TASK标志,和Activity的allowTaskReparenting特性设置为“true”。

FLAG_ACTIVITY_NEW_TASK:

之前描述的,一个Activity一般通过调用startActivity()启动并加入到Task中。它同调用者一样,进入同一个Task。然而,如果传递给startActivity()的Intent对象中包含FLAG_ACTIVITY_NEW_TASK时,系统会搜索一个新的Task来容纳新的Activity。通常,如标志的名字所示,是一个新的Task。然而,并不是必须是。如果已经存在一个Task与新Activity的affinity相同,这个Activity就会加入到那个Task中。如果不是,启动一个新的Task。

allowTaskReparenting:

如果一个Activity的allowTaskReparenting特性设置为“true”,它就能从启动的Task中移到有着相同affinity的Task(这个Task进入到前台的时候)。例如,在一个旅游的程序中定义了一个可以报告选择城市的天气情况的Activity。它和同一个应用程序的其它Activity一样,有着相同的Affinity(默认的Affinity),并且它允许重新宿主。你的Activity中的一个启动了天气预报,因此,它初始化到和你Activity相同的Task中。然而,当旅游应用程序下一次进入到前台时,天气预报那个Activity将会重新编排并在那个Task中显示。

 

如果从用户的角度出发,一个.apk文件包含多个“应用”的话,你可能希望为关联的Activity设置不同的affinity。

 

Launch Mode

 

这里4种不同的启动模式可以设置到<activity>元素的launchMode特性上:

standard(默认模式)

singleTop

singleTask

singleInstance

 

这些模式有以下四点区别:

l  哪个Task将容纳响应Intent的Activity。对于“standard”和“singleTop”来说,是产生Intent的那个Task(并调用startActivity())——除非Intent对象包含FLAG_ACTIVITY_NEW_TASK。在那种情况下,不同的Task将被选择,如“Affinity和新Task”中描述的那样。对比而言,“singleTask”和“singleInstance”指示Activity总是一个Task的根。它们定义一个Task;它们不会加入到另一个Task中。

l  是否有多个Activity的实例。“standard”和“singleTop”可以实例化多次。它们可以属于多个Task,一个特定的Task可以有相同Activity的多个实例。对比而言,“singleTask”和“singleInstance”只能有一个实例。因为这些Activity只能位于Task的底部,这一限制意味着在设备的某个时间,不会出现这样Task的多个实例。

l  是否可以在同一个Task中拥有其它的Activity。“singleInstance”Activity保持单身,在它的Task中它是仅有的Activity。如果它启动另一个Activity,那个Activity将会放入到不同的Task中,而不管它的启动模式——好像FLAG_ACTIVITY_NEW_TASK在Intent中一样。对于其它方面,,“singleInstance”等同于“singleTask”。其它三个模式允许多个Activity加入到这个Task中。“singleTask”Activity总是位于Task的底部,但它可以启动其它的Activity并放入到它的Task中。“standard”和“singleTop”的Activity可以出现在stack的任何地方。

l  是否一个新的实例启动来处理新的Intent。对于默认的“standard”来说,都是创建一个新的实例来响应新的Intent。每个实例处理一个Intent。对于“singleTop”来说,如果它位于目标Task的顶端,那么,已经存在的实例就可以重复使用来处理这个新的Intent。如果它不在顶端,那么它就不能重复使用。替代的,新的实例将创建来响应新的Intent,并进入到stack中。

例如,假设一个Task的Activity stack中包含根Activity A和其它Activity B,C,D,并且D位于顶端,因此,stack是A-B-C-D。有一个Intent来了,它要启动D类型的Activity。如果D有默认的“standard”启动模式,那么,一个新的实例将被启动并且stack变成A-B-C-D-D。然而,如果D的启动模式“singleTop”,已经存在的实例将去处理新来的Intent(因为它正好处在stack的顶端),并且stack依旧是A-B-C-D。

换句话说,如果来临的Intent是冲着B类型的,那么,B类型的实例将被创建启动而不管B的模式是“standard”或“singleTop”(因为B不处在stack的顶端),因此,stack将会是A-B-C-D-B。

之前提到的,设备上不会出现超过一个实例的“singleTask”或“singleInstance”Activity,因此,那个实例都将去处理所有新来的Intent。“


    
[2] [转]Show Stopper 一次 crash 调试的夺命飞奔
    来源: 互联网  发布时间: 2014-02-18
[转]Show Stopper 一次 crash 调试的夺命狂奔
这几天一直在忙着调试 crash 的问题。周末两天都在加班。 周日更是从早上8:00 到晚上 12:50 一直没离开过办公室. 加上这个项目对我们整个开发组以及 EM 都很重要,不容有失,这不禁让我想起了微软 NT 开发组开发 NT 的情形,所以有了这个标题.



这次是在 android 上,但不是 arm,而是 x86 atom。我们的程序是从 windows 上移植到 android 上的, 一个 C++ 写的底层库作为 service,UI 是 java 写的。 因为是在 android 2.2 上,java 也是唯一的写 UI 的选择。 java 通过 aidl/jni 与底层 service/c++ 代码交互。这样的架构让调试很悲剧。



之前一直抱怨 xcode 调试多么不给力,而现在在 android 上的调试已经原始到通过 log 分析程序的执行。arm 上的调试还能用 gdb 勉强为之,而 x86 下那简直就是坑爹。好不容易把符号神马的搞定,gdb 远程调试到设备上,却发现程序不 crash 了。



logcat 和 tombstone 显示的 crash 调用栈是这样的:

06370 INF/DEBUG   ( 1670): signal 11 (SIGSEGV), fault addr deadbaad
06371 INF/DEBUG   ( 1670):  eax 00000000  ebx 801614f4  ecx 00000004  edx 00001000
06372 INF/DEBUG   ( 1670):  esi b3afa000  edi bfca7b18
06373 INF/DEBUG   ( 1670):  xcs 00000073  xds 0000007b  xes 0000007b  xfs 00000000 xss 0000007b
06374 INF/DEBUG   ( 1670):  eip 8011c768  ebp bfca7b28  esp bfca7af0  flags 00010286
06375 INF/DEBUG   ( 1670): #00
06376 INF/DEBUG   ( 1670):     eip: 8011c768  /system/lib/libc.so (abort)
06377 INF/DEBUG   ( 1670): #01
06378 INF/DEBUG   ( 1670):     eip: 8010ed4b  /system/lib/libc.so (dlfree)
06379 INF/DEBUG   ( 1670): #02
06380 INF/DEBUG   ( 1670):     eip: 80111503  /system/lib/libc.so (free)
06381 INF/DEBUG   ( 1670): #03
06382 INF/DEBUG   ( 1670):     eip: 80200a1d  /system/lib/libstdc++.so (_ZdlPv)
06383 INF/DEBUG   ( 1670): #04
06384 INF/DEBUG   ( 1670):     eip: 86138519  /data/data/cip.impservice/lib/libimpjni2.so (_ZSt12__stl_deletePv)
06385 INF/DEBUG   ( 1670): #05
06386 INF/DEBUG   ( 1670):     eip: 8613853d  /data/data/cip.impservice/lib/libimpjni2.so (_ZNSt11__new_alloc10deallocateEPvj)
06387 INF/DEBUG   ( 1670): #06
06388 INF/DEBUG   ( 1670):     eip: 8613856e  /data/data/cip.impservice/lib/libimpjni2.so (_ZNSaIcE10deallocateEPcj)
06389 INF/DEBUG   ( 1670): #07
06390 INF/DEBUG   ( 1670):     eip: 861385b1  /data/data/cip.impservice/lib/libimpjni2.so (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j)
06391 INF/DEBUG   ( 1670): stack:
06392 INF/DEBUG   ( 1670): #00
06393 INF/DEBUG   ( 1670):     bfca7af0  00000002   (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j)
06394 INF/DEBUG   ( 1670):     bfca7af4  bfca7b18  [stack] (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j)
06395 INF/DEBUG   ( 1670):     bfca7af8  00000000   (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j)
06396 INF/DEBUG   ( 1670):     bfca7afc  00000000   (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j)
06397 INF/DEBUG   ( 1670):     bfca7b00  00000000   (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j)
06398 INF/DEBUG   ( 1670):     bfca7b04  00000000   (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j)
06399 INF/DEBUG   ( 1670):     bfca7b08  84a60900  /system/lib/libstlport.so (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j)
06400 INF/DEBUG   ( 1670):     bfca7b0c  00000010   (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j)
06401 INF/DEBUG   ( 1670):     bfca7b10  0a1f8300  [heap] (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j)
06402 INF/DEBUG   ( 1670):     bfca7b14  00000001   (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j)
06403 INF/DEBUG   ( 1670):     bfca7b18  fffffbdf   (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j)
06404 INF/DEBUG   ( 1670):     bfca7b1c  801614f4  /system/lib/libc.so (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j)
06405 INF/DEBUG   ( 1670):     bfca7b20  0a1f6c98  [heap] (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j)
06406 INF/DEBUG   ( 1670):     bfca7b24  bfca8410  [stack] (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j)
06407 INF/DEBUG   ( 1670):     bfca7b28  bfca7b68  [stack] (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j)
06408 INF/DEBUG   ( 1670): #01
06409 INF/DEBUG   ( 1670):     bfca7b2c  8010ed4b  /system/lib/libc.so (dlfree)
06410 INF/DEBUG   ( 1670):     bfca7b30  80163118   (dlfree)
06411 INF/DEBUG   ( 1670):     bfca7b34  00000000   (dlfree)
06412 INF/DEBUG   ( 1670):     bfca7b38  8010f3ab  /system/lib/libc.so (dlmalloc)
06413 INF/DEBUG   ( 1670):     bfca7b3c  801614f4  /system/lib/libc.so (dlmalloc)
06414 INF/DEBUG   ( 1670):     bfca7b40  00000066   (dlmalloc)
06415 INF/DEBUG   ( 1670):     bfca7b44  bfca8410  [stack] (dlmalloc)
06416 INF/DEBUG   ( 1670):     bfca7b48  0a1f6c90  [heap] (dlmalloc)
06417 INF/DEBUG   ( 1670):     bfca7b4c  801114d2  /system/lib/libc.so (malloc)
06418 INF/DEBUG   ( 1670):     bfca7b50  0000002f   (malloc)
06419 INF/DEBUG   ( 1670):     bfca7b54  80201d98  /system/lib/libstdc++.so
06420 INF/DEBUG   ( 1670):     bfca7b58  bfca7b68  [stack]
06421 INF/DEBUG   ( 1670):     bfca7b5c  801614f4  /system/lib/libc.so
06422 INF/DEBUG   ( 1670):     bfca7b60  0a1f6caf  [heap]
06423 INF/DEBUG   ( 1670):     bfca7b64  bfca8410  [stack]
06424 INF/DEBUG   ( 1670):     bfca7b68  bfca7b78  [stack]
06425 INF/DEBUG   ( 1670):     ......  ......


每次都几乎看不到我们的代码,好不容易看到一个用户代码的地址,通过 addr2line, 也是 STL 里的 _alloc.h 之类。这其实是一个提示,但一开始我们并没有在意。我们还是坚忍的打着 log,试图逐一的排查 crash, 好不容易向前推进了一些让程序跑得更远一点,再跑一次却发现又回到了起点, crash 又在前面的代码中出现鸟,我勒个去~



不稳定的 crash 让我有些沮丧,同时也让我产生了怀疑,这到底是不是我们的代码的问题? 看看每次 crash 的调用栈,都有 STL 牵涉其中,又联想起我们用的 stlport 不是线程安全的 (编译时使用了 _NOTHREADS 宏),  是不是应该去掉 _NOTHREADS 编译试试? 但遇到的新问题是,我们使用的动态链接的系统自带的 STL,虽然可以替换掉系统的,但势必影响其他的程序。这是不能接受的。 马上想到我们可以编译一个静态库,连接到我们的程序中。说干就干,拿到 stlport 的代码,折腾一番,也就编译好了。这里还有一个小插曲, android 的头文件说它对 #include_next 支持的并不好,但最终我们还是用了 gcc 的这个 feature 才让代码编译通过。



但测试的结果却让人沮丧,我再次确认了的确是链接到了自己编译的静态版本,悲催的发现这次尝试可耻的失败鸟~ 这时已是周一凌晨 0:50 了,而我已经在办公室呆了 16个小时没有离开。



周一早上9:40到达公司。一计不成,又生一计,这次我注意到调用栈顶端的 lib 的 free 函数,既然每次都 crash 在这里,那我能不能让它不调用这个函数。联想起之前看过的 stlport 文档 (http://www.stlport.com/doc/configure.html),的确有一个宏  _STLP_USE_NEWALLOC 可以让 stlport 使用 new/delete 而不是 malloc/free 来分配/释放内存, 无独有偶,目前我们做的这个项目的前身(另一个项目组开发的)编译的时候就加了 stlport 的这个宏(我们在移植代码的时候由于匆忙,急于让代码通过编译,没能加上这个宏),这更坚定了我做这个尝试的决心。于是给十几个模块的 mk 文件都加上了这几个 stlport 相关的宏(看 stlport 文档关于分配内存的宏),rebuild all。 哈利露亚~ 幸福来得那么突然, 程序真的跑起来了,不再 crash!



总结这次调试的经验教训:

1. 开始时调试进展缓慢,问题出在编译/调试环境很不给力。

我们需要把代码放到另一个 site 的唯一的 build machine 上让同事帮忙编译,这个过程让调试过程变得很漫长。 所以我让同事给我在 build machine 上单独弄了一个环境,这样我就可以随意的修改/调试代码了

2. 对问题不敏感,虽然每次都看到 stl/free 出现在调用栈中,直到在错误的方向上迷失才意识到我们可能走错路了

3. 对项目本身不够了解,我没能意识到我们其实有一个能用的版本(虽然我们重构了很多),的确应该早些查看别人是怎么做到的。 这里有一个客观原因是我之前一直不在这个项目。

4. Android 的调试环境太坑爹了。既然符号神马的都齐活了,在调研栈里却只显示地址和莫名其妙的函数名(还是 decorated), 尼玛就不能把代码行也加进去啊!有木有!Android 开发小组在忙于追赶/超越苹果的时候,明显对开发者照顾不够。 当然,也有可能是我被微软给惯坏了.

注:本人转自http://nick.luckygarden.org/?p=454

    
[3] JAVA 中 replace 跟 replaceAll 的区别
    来源: 互联网  发布时间: 2014-02-18
JAVA 中 replace 和 replaceAll 的区别
replace和replaceAll是JAVA中常用的替换字符的方法,它们的区别是:

1)replace的参数是char和CharSequence,

即可以支持字符的替换,也支持字符串的替换(CharSequence即字符串序列的意思,说白了也就是字符串);

2)replaceAll的参数是regex,

即基于规则表达式的替换,比如,可以通过replaceAll("\\d", "*")把一个字符串所有的数字字符都换成星号;
相同点是都是全部替换,即把源字符串中的某一字符或字符串全部换成指定的字符或字符串,

3)replaceFirst()
如果只想替换第一次出现的,可以使用3)replaceFirst() ,这个方法也是基于规则表达式的替换,但与replaceAll()不同的时,只替换第一次出现的字符串;


另外,如果replaceAll()和replaceFirst()所用的参数据不是基于规则表达式的,则与replace()替换字符串的效果是一样的,即这两者也支持字符串的操作;

还有一点注意:执行了替换操作后,源字符串的内容是没有发生改变的.

例子:将src中包含“江苏省”、“玄武区”、“鼓楼区”的字符串同时替换为空,应该为“南京市北京东路徐州市戏马台”。

    public static void main(String[] args) throws Exception {
        String src = "江苏省1南京市玄武区2北京东路鼓楼区3戏马台";
        src = src.replaceAll("(?:江苏省|玄武区|鼓楼区)", "");
        System.out.println(src);
    }



    
最新技术文章:
▪Android开发之登录验证实例教程
▪Android开发之注册登录方法示例
▪Android获取手机SIM卡运营商信息的方法
▪Android实现将已发送的短信写入短信数据库的...
▪Android发送短信功能代码
▪Android根据电话号码获得联系人头像实例代码
▪Android中GPS定位的用法实例
▪Android实现退出时关闭所有Activity的方法
▪Android实现文件的分割和组装
▪Android录音应用实例教程
▪Android双击返回键退出程序的实现方法
▪Android实现侦听电池状态显示、电量及充电动...
▪Android获取当前已连接的wifi信号强度的方法
▪Android实现动态显示或隐藏密码输入框的内容
▪根据USER-AGENT判断手机类型并跳转到相应的app...
▪Android Touch事件分发过程详解
▪Android中实现为TextView添加多个可点击的文本
▪Android程序设计之AIDL实例详解
▪Android显式启动与隐式启动Activity的区别介绍
▪Android按钮单击事件的四种常用写法总结
▪Android消息处理机制Looper和Handler详解
▪Android实现Back功能代码片段总结
▪Android实用的代码片段 常用代码总结
▪Android实现弹出键盘的方法
▪Android中通过view方式获取当前Activity的屏幕截...
▪Android提高之自定义Menu(TabMenu)实现方法
▪Android提高之多方向抽屉实现方法
▪Android提高之MediaPlayer播放网络音频的实现方法...
▪Android提高之MediaPlayer播放网络视频的实现方法...
▪Android提高之手游转电视游戏的模拟操控
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3