android Application Component研究之Activity(二)

http://blog.csdn.net/windskier/article/details/7172710

本文为原创文章,欢迎转载!转载时请注明出处:http://blog.csdn.net/windskier

上篇文章分析完了task的创建或者复用,接下来接着分析activity在启动过程中还有哪些工作需要去完成?首先给出整个activity的过程图。

1. Starting Window

当该activity运行在新的task中或者进程中时,需要在activity显示之前显示一个Starting Window。如上图所示的setAppStartingWindow()方法,这个Starting Window上并没有绘制任何的view,它就是一个空白的Window,但是WMS赋予了它一个animation。这个Starting Window的处理过程需要注意几点:

·1. 在AMS请求WMS启动Starting Window时,这个过程是被置在WMS的消息队列中,也就是说这个过程是一个异步的过程,并且需要将其置在WMS消息队列的队首。

一般情况下,Starting Window是在activity Window之前显示的,但是由于是异步过程,因此从理论上来说activity Window较早显示是有可能的,如果这样的话,Starting Window将会被清除而不再显示。例如在addStartingWindow()@PhoneWindowManager.java方法调用addView之前做一个sleep操作,结果就可能不显示Starting Window。

setAppStartingWindow()@WindowManagerService.java

[java] view plain copy

  1. // The previous app was getting ready to show a
  2. // starting window, but hasn‘t yet done so.  Steal it!
  3. if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
  4. "Moving pending starting from " + ttoken
  5. + " to " + wtoken);
  6. wtoken.startingData = ttoken.startingData;
  7. ttoken.startingData = null;
  8. ttoken.startingMoved = true;
  9. Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
  10. // Note: we really want to do sendMessageAtFrontOfQueue() because we
  11. // want to process the message ASAP, before any other queued
  12. // messages.
  13. mH.sendMessageAtFrontOfQueue(m);
  14. return;

2. Starting Window是设置了Animation的

addStartingWindow()@PhoneWindowManager.java

[java] view plain copy

  1. final WindowManager.LayoutParams params = win.getAttributes();
  2. params.token = appToken;
  3. params.packageName = packageName;
  4. params.windowAnimations = win.getWindowStyle().getResourceId(
  5. com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
  6. params.setTitle("Starting " + packageName);

3. Starting Window同普通的activity Window一样,均为一个PhoneWindow,其中包看着DecorView和ViewRoot。

addStartingWindow()@PhoneWindowManager.java

[java] view plain copy

  1. try {
  2. Context context = mContext;
  3. boolean setTheme = false;
  4. //Log.i(TAG, "addStartingWindow " + packageName + ": nonLocalizedLabel="
  5. //        + nonLocalizedLabel + " theme=" + Integer.toHexString(theme));
  6. if (theme != 0 || labelRes != 0) {
  7. try {
  8. context = context.createPackageContext(packageName, 0);
  9. if (theme != 0) {
  10. context.setTheme(theme);
  11. setTheme = true;
  12. }
  13. } catch (PackageManager.NameNotFoundException e) {
  14. // Ignore
  15. }
  16. }
  17. if (!setTheme) {
  18. context.setTheme(com.android.internal.R.style.Theme);
  19. }
  20. //创建PhoneWindow
  21. Window win = PolicyManager.makeNewWindow(context);
  22. if (win.getWindowStyle().getBoolean(
  23. com.android.internal.R.styleable.Window_windowDisablePreview, false)) {
  24. return null;
  25. }
  26. Resources r = context.getResources();
  27. win.setTitle(r.getText(labelRes, nonLocalizedLabel));
  28. win.setType(
  29. WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
  30. // Force the window flags: this is a fake window, so it is not really
  31. // touchable or focusable by the user.  We also add in the ALT_FOCUSABLE_IM
  32. // flag because we do know that the next window will take input
  33. // focus, so we want to get the IME window up on top of us right away.
  34. win.setFlags(
  35. WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
  36. WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
  37. WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
  38. WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
  39. WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
  40. WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
  41. win.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
  42. WindowManager.LayoutParams.MATCH_PARENT);
  43. final WindowManager.LayoutParams params = win.getAttributes();
  44. params.token = appToken;
  45. params.packageName = packageName;
  46. params.windowAnimations = win.getWindowStyle().getResourceId(
  47. com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
  48. params.setTitle("Starting " + packageName);
  49. WindowManagerImpl wm = (WindowManagerImpl)
  50. context.getSystemService(Context.WINDOW_SERVICE);
  51. View view = win.getDecorView();
  52. if (win.isFloating()) {
  53. // Whoops, there is no way to display an animation/preview
  54. // of such a thing!  After all that work...  let‘s skip it.
  55. // (Note that we must do this here because it is in
  56. // getDecorView() where the theme is evaluated...  maybe
  57. // we should peek the floating attribute from the theme
  58. // earlier.)
  59. return null;
  60. }
  61. if (localLOGV) Log.v(
  62. TAG, "Adding starting window for " + packageName
  63. + " / " + appToken + ": "
  64. + (view.getParent() != null ? view : null));
  65. <span style="white-space: pre;">  </span>    //向WindowManager addView
  66. wm.addView(view, params);
  67. // Only return the view if it was successfully added to the
  68. // window manager... which we can tell by it having a parent.
  69. return view.getParent() != null ? view : null;
  70. }

2. 启动新进程

如果新启动的activity需要运行在新的进程中,那么这个流程就涉及到了一个新进程的启动,由于画图的局限性,这个过程在上图中没有体现出来。

所有的ProcessRecord被存储在mProcessNames变量中,以当前的进程的名字为索引。

@ActivityManagerService.java

[java] view plain copy

  1. final ProcessMap<ProcessRecord> mProcessNames
  2. = new ProcessMap<ProcessRecord>();

进程名字的确定有如下规则:

如果Activity设置了Android:process属性,则processName为属性设置的值;

@ComponentInfo.java

[java] view plain copy

  1. public String processName;

如果Activity没有设置android:process属性,那么Activity的processName为Application的processName。如果Application设置了process属性,那么processName为该值;如果没有设置,processName为Package的名字,即

@PackageItemInfo.java

[java] view plain copy

  1. public String packageName;

整个进程启动的过程前面有一篇文章介绍过,就不在介绍。

3. Application Transition

Application Transition是android在实现窗口切换过程中,为了提供更好的用户体验和特定的指示,来呈现出的过渡效果。一般情况下,Application Transition是一个动画效果。

Application Transition有两种,一种是启动activity时的Transition动画,一种是启动一些widget时的Transition动画。

Transition类型的设置通过函数prepareAppTransition()@WindowManagerService.java来进行.

设置完Transition类型之后,通过executeAppTransition()@WindowManagerService.java函数来执行这个Transition。

prepareAppTransition()-->executeAppTransition()-->performLayoutAndPlaceSurfacesLocked();

具体的Transition的animation绘制过程在分析WMS再做分析。

3.1 activity Transition

当启动一个activity时,系统会给它的window呈现提供一个animation,这个animation可以在frameworks/base/core/res/res/values/styles.xml中进行设置

[html] view plain copy

  1. <!-- Standard animations for a full-screen window or activity. -->
  2. <style name="Animation.Activity">
  3. <item name="activityOpenEnterAnimation">@anim/activity_open_enter</item>
  4. <item name="activityOpenExitAnimation">@anim/activity_open_exit</item>
  5. <item name="activityCloseEnterAnimation">@anim/activity_close_enter</item>
  6. <item name="activityCloseExitAnimation">@anim/activity_close_exit</item>
  7. <item name="taskOpenEnterAnimation">@anim/task_open_enter</item>
  8. <item name="taskOpenExitAnimation">@anim/task_open_exit</item>
  9. <item name="taskCloseEnterAnimation">@anim/task_close_enter</item>
  10. <item name="taskCloseExitAnimation">@anim/task_close_exit</item>
  11. <item name="taskToFrontEnterAnimation">@anim/task_open_enter</item>
  12. <item name="taskToFrontExitAnimation">@anim/task_open_exit</item>
  13. <item name="taskToBackEnterAnimation">@anim/task_close_enter</item>
  14. <item name="taskToBackExitAnimation">@anim/task_close_exit</item>
  15. <item name="wallpaperOpenEnterAnimation">@anim/wallpaper_open_enter</item>
  16. <item name="wallpaperOpenExitAnimation">@anim/wallpaper_open_exit</item>
  17. <item name="wallpaperCloseEnterAnimation">@anim/wallpaper_close_enter</item>
  18. <item name="wallpaperCloseExitAnimation">@anim/wallpaper_close_exit</item>
  19. <item name="wallpaperIntraOpenEnterAnimation">@anim/wallpaper_intra_open_enter</item>
  20. <item name="wallpaperIntraOpenExitAnimation">@anim/wallpaper_intra_open_exit</item>
  21. <item name="wallpaperIntraCloseEnterAnimation">@anim/wallpaper_intra_close_enter</item>
  22. <item name="wallpaperIntraCloseExitAnimation">@anim/wallpaper_intra_close_exit</item>
  23. </style>

activity启动的animation根据当前的activity所在的task状态有所不同,从上面的xml中的animation定义中就可以看出,它的分类:

★ 如果启动的activity运行在原来的task中,那么使用animation activityOpenEnterAnimation/activityOpenExitAnimation;

★ 如果启动的activity运行在新的task中,那么使用animation taskOpenEnterAnimation/taskOpenExitAnimation;

★ 如果结束的activity结束之后原来的task还存在,那么使用activityCloseEnterAnimation/activityCloseExitAnimation;

★ 如果结束的activity结束之后原来的task将不存在,也即次activity为task最后的activity,那么使用taskCloseEnterAnimation/taskCloseExitAnimation;

★ 一些特定的情况下,AMS需要将某个task move到最前面,例如上一篇文章中的task reparenting过程,此时使用taskToFrontEnterAnimation/taskToFrontExitAnimation;

★ 一些特定的情况下,AMS需要将某个task move到最底端,此时使用taskToBackEnterAnimation/taskToBackExitAnimation;

★ 如果当前的activity使用的theme中的参数android:windowShowWallpaper为true,此时的activity应该以当前的壁纸为背景,并且前一个显示的activity的背景不是当前的壁纸,此时使用wallpaperOpenEnterAnimation/wallpaperOpenExitAnimation/wallpaperCloseEnterAnimation/wallpaperCloseExitAnimation,

如下面activity所示:

★ 如果当前的activity使用的theme中的参数android:windowShowWallpaper为true,此时的activity应该以当前的壁纸为背景,并且前一个显示的activity的背景是当前的壁纸,此时使用wallpaperIntraOpenEnterAnimation/wallpaperIntraOpenExitAnimation/wallpaperIntraCloseEnterAnimation/wallpaperIntraCloseExitAnimation.

下面代码即是判断当前应该选择那些带有wallpaper的Transition类型。

performLayoutAndPlaceSurfacesLockedInner()@WindowManagerService.java

[java] view plain copy

  1. final int NC = mClosingApps.size();
  2. NN = NC + mOpeningApps.size();
  3. for (i=0; i<NN; i++) {
  4. AppWindowToken wtoken;
  5. int mode;
  6. if (i < NC) {
  7. wtoken = mClosingApps.get(i);
  8. mode = 1;
  9. } else {
  10. wtoken = mOpeningApps.get(i-NC);
  11. mode = 2;
  12. }
  13. if (mLowerWallpaperTarget != null) {
  14. if (mLowerWallpaperTarget.mAppToken == wtoken
  15. || mUpperWallpaperTarget.mAppToken == wtoken) {
  16. foundWallpapers |= mode;
  17. }
  18. }
  19. if (wtoken.appFullscreen) {
  20. WindowState ws = wtoken.findMainWindow();
  21. if (ws != null) {
  22. // If this is a compatibility mode
  23. // window, we will always use its anim.
  24. if ((ws.mAttrs.flags&FLAG_COMPATIBLE_WINDOW) != 0) {
  25. animLp = ws.mAttrs;
  26. animToken = ws.mAppToken;
  27. bestAnimLayer = Integer.MAX_VALUE;
  28. } else if (ws.mLayer > bestAnimLayer) {
  29. animLp = ws.mAttrs;
  30. animToken = ws.mAppToken;
  31. bestAnimLayer = ws.mLayer;
  32. }
  33. }
  34. }
  35. }
  36. if (foundWallpapers == 3) {
  37. if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
  38. "Wallpaper animation!");
  39. switch (transit) {
  40. case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
  41. case WindowManagerPolicy.TRANSIT_TASK_OPEN:
  42. case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
  43. transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN;
  44. break;
  45. case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
  46. case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
  47. case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
  48. transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE;
  49. break;
  50. }
  51. if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
  52. "New transit: " + transit);
  53. } else if (oldWallpaper != null) {
  54. // We are transitioning from an activity with
  55. // a wallpaper to one without.
  56. transit = WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE;
  57. if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
  58. "New transit away from wallpaper: " + transit);
  59. } else if (mWallpaperTarget != null) {
  60. // We are transitioning from an activity without
  61. // a wallpaper to now showing the wallpaper
  62. transit = WindowManagerPolicy.TRANSIT_WALLPAPER_OPEN;
  63. if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
  64. "New transit into wallpaper: " + transit);
  65. }

3.2 widget  Transition

每个widget在启动时的animation和activity不一样,并且在frameworks/base/core/res/res/values/styles.xml中可以设置不同widget。

[java] view plain copy

  1. private boolean applyAnimationLocked(WindowState win,
  2. int transit, boolean isEntrance) {
  3. if (win.mLocalAnimating && win.mAnimationIsEntrance == isEntrance) {
  4. // If we are trying to apply an animation, but already running
  5. // an animation of the same type, then just leave that one alone.
  6. return true;
  7. }
  8. // Only apply an animation if the display isn‘t frozen.  If it is
  9. // frozen, there is no reason to animate and it can cause strange
  10. // artifacts when we unfreeze the display if some different animation
  11. // is running.
  12. if (!mDisplayFrozen && mPolicy.isScreenOn()) {
  13. int anim = mPolicy.selectAnimationLw(win, transit);
  14. int attr = -1;
  15. Animation a = null;
  16. if (anim != 0) {
  17. a = AnimationUtils.loadAnimation(mContext, anim);
  18. } else {
  19. switch (transit) {
  20. case WindowManagerPolicy.TRANSIT_ENTER:
  21. attr = com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation;
  22. break;
  23. case WindowManagerPolicy.TRANSIT_EXIT:
  24. attr = com.android.internal.R.styleable.WindowAnimation_windowExitAnimation;
  25. break;
  26. case WindowManagerPolicy.TRANSIT_SHOW:
  27. attr = com.android.internal.R.styleable.WindowAnimation_windowShowAnimation;
  28. break;
  29. case WindowManagerPolicy.TRANSIT_HIDE:
  30. attr = com.android.internal.R.styleable.WindowAnimation_windowHideAnimation;
  31. break;
  32. }
  33. if (attr >= 0) {
  34. a = loadAnimation(win.mAttrs, attr);
  35. }
  36. }
  37. if (DEBUG_ANIM) Slog.v(TAG, "applyAnimation: win=" + win
  38. + " anim=" + anim + " attr=0x" + Integer.toHexString(attr)
  39. + " mAnimation=" + win.mAnimation
  40. + " isEntrance=" + isEntrance);
  41. if (a != null) {
  42. if (DEBUG_ANIM) {
  43. RuntimeException e = null;
  44. if (!HIDE_STACK_CRAWLS) {
  45. e = new RuntimeException();
  46. e.fillInStackTrace();
  47. }
  48. Slog.v(TAG, "Loaded animation " + a + " for " + win, e);
  49. }
  50. win.setAnimation(a);
  51. win.mAnimationIsEntrance = isEntrance;
  52. }
  53. } else {
  54. win.clearAnimation();
  55. }
  56. return win.mAnimation != null;
  57. }

4. Activity启动

文章的前面的内容中分析的一直是AMS对一个新启动的activity的管理,activity在AMS中的形态是以ActivityRecord的形式来管理的,下面的时序图中则是描绘了应用中一个activity的创建并启动的过程。

5. Activity pausing过程

Activity pausing过程有3种情况:

1. 第一种情况是从一个activity启动另一个activity的同时,也伴随着前一个activity的pause过程。

resumeTopActivityLocked()@ActivityStack.java

[java] view plain copy

  1. // We need to start pausing the current activity so the top one
  2. // can be resumed...
  3. if (mResumedActivity != null) {
  4. if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: need to start pausing");
  5. startPausingLocked(userLeaving, false);
  6. return true;
  7. }

2. 第二种情况是当PowerManagerService要求AMS休眠或者设备shutDown时;

@ActivityStack.java

[java] view plain copy

  1. void pauseIfSleepingLocked() {
  2. if (mService.mSleeping || mService.mShuttingDown) {
  3. if (!mGoingToSleep.isHeld()) {
  4. mGoingToSleep.acquire();
  5. if (mLaunchingActivity.isHeld()) {
  6. mLaunchingActivity.release();
  7. mService.mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
  8. }
  9. }
  10. // If we are not currently pausing an activity, get the current
  11. // one to pause.  If we are pausing one, we will just let that stuff
  12. // run and release the wake lock when all done.
  13. if (mPausingActivity == null) {
  14. if (DEBUG_PAUSE) Slog.v(TAG, "Sleep needs to pause...");
  15. if (DEBUG_USER_LEAVING) Slog.v(TAG, "Sleep => pause with userLeaving=false");
  16. startPausingLocked(false, true);
  17. }
  18. }
  19. }

3.第三种情况是一个activity finish过程中。这个下面再介绍。

下图为第一种情况的时序图,整个pausing过程的是相同的,因此以一种情况的时序图来体现activity的pausing过程。

6. Activity Stoping 过程

我们知道,当Activity不可见时会执行stoping的过程,下面我们就来分析以下一个activity是怎么来进行stop的。下面给出整个stop过程的时序图:

在stop中有一个很重要的概念就是activity idle状态,不论是activity被新启动的activity完全覆盖,还是activity被finish,也就是activity的stop过程以及finsh过程,均是在最新被resume的activity已经resume完成之后才去处理。

我们可以想象一下,每个应用程序的主线程ActivityThread中,当没有任何的消息待处理时,此时我们可以认为此时的已被resumed的activity状态时空闲的,没有任何的人机交互。因此android设计者将前一个被完全覆盖不可见的或者finish的activity的stop或finish操作放在此时来处理。这样做是合情合理,毕竟stop或者finish一个activity以及显示新的activity之间的关系是同步,是必须有先后顺序的,为了达到更好的用户体验,理所当然应该是先显示新的activity,然后采取stop或者finish旧的activity。为了实现这个目的,android设计者使用了MessageQueue的这个IdleHandler机制。

首先,我们看一下MessageQueue的IdleHandler机制。

next ()@MessageQueue.java

[java] view plain copy

  1. // Run the idle handlers.
  2. // We only ever reach this code block during the first iteration.
  3. for (int i = 0; i < pendingIdleHandlerCount; i++) {
  4. final IdleHandler idler = mPendingIdleHandlers[i];
  5. mPendingIdleHandlers[i] = null; // release the reference to the handler
  6. boolean keep = false;
  7. try {
  8. keep = idler.queueIdle();
  9. } catch (Throwable t) {
  10. Log.wtf("MessageQueue", "IdleHandler threw exception", t);
  11. }
  12. if (!keep) {
  13. synchronized (this) {
  14. mIdleHandlers.remove(idler);
  15. }
  16. }
  17. }

在ActivityThread线程的Looper中,Looper会不停的去查找消息队列中是否有消息需要处理,如果没有任何的消息待处理,那么将查看当前的消息队列是否有IdleHandler注册,如果有逐个执行这些IdleHandler。
    明白了IdleHandler的机制,回过头来了看ActivityThread的IdleHandler的注册过程,代码如下。

handleResumeActivity()@ActivityThread.java

[java] view plain copy

  1. r.nextIdle = mNewActivities;
  2. mNewActivities = r;
  3. if (localLOGV) Slog.v(
  4. TAG, "Scheduling idle handler for " + r);
  5. Looper.myQueue().addIdleHandler(new Idler());

7. Activity finishing过程

用户从application结束当前的activity,如按back键;

如同activity不可见时的处理一样,activity的finishing过程同样是在新的activity被resume之后才去执行,但是存在一种情况,当mHistory栈中存在多个(多于4个)activity时,假如此时user以很快的速度去按back键,并且在第一个需resume的activity尚未被resume完成时,已经被user触发了多次back键,此时应该怎么处理finish过程呢?

按照上面的逻辑来看,user不停的以很快的速度去触发back键,直到回到home activity,这种情况下ActivityThread的Looper一直会有消息需要处理,根本不可能去处理它的IdleHandler,也就不可能去处理各个activity的finish过程,直到回到home activity之后才能有空闲去处理。我们可以想象一下如果按照这个逻辑去操作的话,会有什么问题?

设想一下,我们累计了多个activity在ActivityThread的Looper在idle状态下处理,那么这个过程将是比较长的,假如此时又有user触发了启动actibity的操作,那么ActivityThread将会同时处理累计的activity的finish过程,同时又需要处理activity的启动过程,那么这么做的结果只能是给用户带来系统很慢的用户体验。因此上面的finish逻辑需要进行一定的矫正与修改。

AMS在累计的activity超过3个时,就会强制调用Idle处理操作。这么做就有效的消耗了累计的activity的finish过程,就很大程度上减轻了上述所说的问题。

finishCurrentActivityLocked()@ActivityStack.java

[java] view plain copy

  1. // First things first: if this activity is currently visible,
  2. // and the resumed activity is not yet visible, then hold off on
  3. // finishing until the resumed one becomes visible.
  4. if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
  5. if (!mStoppingActivities.contains(r)) {
  6. mStoppingActivities.add(r);
  7. Slog.d(TAG, "finishCurrentActivityLocked mStoppingActivities size:" + mStoppingActivities.size());
  8. if (mStoppingActivities.size() > 3) {
  9. // If we already have a few activities waiting to stop,
  10. // then give up on things going idle and start clearing
  11. // them out.
  12. Message msg = Message.obtain();
  13. msg.what = IDLE_NOW_MSG;
  14. mHandler.sendMessage(msg);
  15. }
  16. }
  17. r.state = ActivityState.STOPPING;
  18. mService.updateOomAdjLocked();
  19. return r;
  20. }

同样的问题也存在与activity启动过程中,假如user以很快的速度去不停的启动activity,那么被覆盖的activity的stop过程很上述的finish过程一样,也会不停的累计,出现相同的问题。解决的思路也是一致的。
completePauseLocked()@ActivityStack.java

[java] view plain copy

    1. mStoppingActivities.add(prev);
    2. if (mStoppingActivities.size() > 3) {
    3. // If we already have a few activities waiting to stop,
    4. // then give up on things going idle and start clearing
    5. // them out.
    6. if (DEBUG_PAUSE) Slog.v(TAG, "To many pending stops, forcing idle");
    7. Message msg = Message.obtain();
    8. msg.what = IDLE_NOW_MSG;
    9. mHandler.sendMessage(msg);
    10. }
时间: 2024-10-10 07:36:51

android Application Component研究之Activity(二)的相关文章

android Application Component研究之Activity(一)

http://blog.csdn.net/windskier/article/details/7096521 终于下定决心写写ActivityManagerService的源码分析的文章了,ActivityManagerService 业务的整个逻辑关系被各种复杂的数据结构包裹着,因此对ActivityManagerService 的分析主要就是对各种数据结构的分析,明白了这些数据结构,理解ActivityManagerService的业务内容就水到渠成了. AMS提供了一个ArrayList

Android 四大组件学习之Activity二

上一节学习如何创建一个Activity,以及如何加载界面. 这一节学习,如何从一个Activity跳转到另外一个Activity. 首先: 先创建二个Activity, 我就用上节课的MainActivity和SecondActivity MainActivity的布局文件,就随便拖放一个TextView和一个Button: <TextView android:id="@+id/textView1" android:layout_width="wrap_content&

二、Android学习第二天——初识Activity(转)

(转自:http://wenku.baidu.com/view/af39b3164431b90d6c85c72f.html) 一. Android学习第二天——初识Activity 昨天程序搭建成功以后,就可以开发跟运行Android应用程序了,因为Activity是开发中不可或缺的组成部分,所以要对Activity有所认识. 以下两点是需要注意的:(个人总结) 凡是覆写得方法,在方法体中的第一行一定是super.XXX(),一定要先调用父类里的相应方法做必要的事情,再根据自己的需求去写其他的代

Android application 和 activity 标签详解

extends:http://blog.csdn.net/self_study/article/details/54020909 Application 标签 android:allowTaskReparenting Android:allowTaskReparenting=["true" | "false"] 表明了这个应用在 reset task 时,它的所有 activity 是否可以从打开它们的 task 栈中迁移到它们声明的 taskAffinity 亲和

Android 浏览器的研究(六)--- ADT调试通过Intent启动的Activity

今天遇到一个问题,在音乐应用里长按一个歌曲,在弹出菜单中选择搜索,在搜索选择框中选择浏览器.正常情况下应该打开浏览器并且使用默认的搜索引擎启动搜索,但是现在浏览器搜索界面并没有打开.首先想到的是打开浏览器工程,在相关位置设置断点,启动调试,发现一切处理正常,浏览器界面打开并正常启动了搜索过程.原来问题只发生在浏览器进程尚未启动,音乐应用使用Intent启动浏览器来进行搜索的情况下.这里分享一下这种情况下如何启动调试分析. 首先,该应用是其他应用通过Intent启动的,而我们需要调试它.在C/C+

关于android编程中service和activity的区别

一. 绝大部分情况下,Service的作用是用来"执行"后台的.耗时的.重要的任务,三者缺一不可,而最重要的原因是第三点:要执行重要的任务. 因为当一个进程启动了Service后,进程的优先级变高了,系统除非在非常极端的情况下,不会杀掉该进程,反观Activity,不具备这样的特性. 如果没有满足上面所说的三点,请谨慎使用Service,千万别把使用Service的理由变成:这样可以常驻后台.从资源使用的角度来看,这是非常不可取的. 二. 1.Activity和Service的生命周期

【转】Android平台下利用zxing实现二维码开发

http://www.cnblogs.com/dolphin0520/p/3355728.html 现在走在大街小巷都能看到二维码,而且最近由于项目需要,所以研究了下二维码开发的东西,开源的二维码扫描库主要有zxing和zbar,zbar在iPos平台上应用比较成熟,而在Android平台上主流还是用zxing库,因此这里主要讲述如何利用zxing进行二维码开发. 1.如何将zxing的Android源码导入工程. 在导入zxing的android源码之前,先去官方下载zxing的源码:http

Android平台下利用zxing实现二维码开发

http://www.cnblogs.com/dolphin0520/p/3355728.html 现在走在大街小巷都能看到二维码,而且最近由于项目需要,所以研究了下二维码开发的东西,开源的二维码扫描库主要有zxing和zbar,zbar在iPos平台上应用比较成熟,而在Android平台上主流还是用zxing库,因此这里主要讲述如何利用zxing进行二维码开发. 1.如何将zxing的Android源码导入工程. 在导入zxing的android源码之前,先去官方下载zxing的源码:http

深入分析:Android中app之间的交互(二,使用ComponentName)

在前一篇相关主题的博文中我们了解了如何使用Action来启动当前应用之外的Activity处理我们的业务逻辑,在本篇笔记中我在简单介绍一下使用ComponentName来与当前应用之外的应用进行交互. 在介绍Component之前,我们首先来了解ComponentName这个类:ComponentName与Intent同位于android.content包下,我们从Android官方文档中可以看到,这个类主要用来定义可见一个应用程序组件,例如:Activity,Service,Broadcast