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

  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

  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

  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

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

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

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

@ComponentInfo.java

  1. public String processName;

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

@PackageItemInfo.java

  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中进行设置

  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

  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。

  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

  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

  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

  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

  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

  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

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

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

  1. android Application Component研究之Activity(一)

    http://blog.csdn.net/windskier/article/details/7096521 终于下定决心写写ActivityManagerService的源码分析的文章了,Activ ...

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

    (转自:http://wenku.baidu.com/view/af39b3164431b90d6c85c72f.html) 一. Android学习第二天——初识Activity 昨天程序搭建成功以 ...

  3. Android application 和 activity 标签详解

    extends:http://blog.csdn.net/self_study/article/details/54020909 Application 标签 android:allowTaskRep ...

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

    http://www.cnblogs.com/dolphin0520/p/3355728.html 现在走在大街小巷都能看到二维码,而且最近由于项目需要,所以研究了下二维码开发的东西,开源的二维码扫描 ...

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

    Android平台下利用zxing实现二维码开发 现在走在大街小巷都能看到二维码,而且最近由于项目需要,所以研究了下二维码开发的东西,开源的二维码扫描库主要有zxing和zbar,zbar在iPos平 ...

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

    一. 绝大部分情况下,Service的作用是用来“执行”后台的.耗时的.重要的任务,三者缺一不可,而最重要的原因是第三点:要执行重要的任务. 因为当一个进程启动了Service后,进程的优先级变高了, ...

  7. (转载)Android平台下利用zxing实现二维码开发

    Android平台下利用zxing实现二维码开发 现在走在大街小巷都能看到二维码,而且最近由于项目需要,所以研究了下二维码开发的东西,开源的二维码扫描库主要有zxing和zbar,zbar在iPos平 ...

  8. Android应用程序窗口(Activity)与WindowManagerService服务的连接过程分析

    在前两文中,我们分析了Activity组件的窗口对象和视图对象的创建过程.Activity组件在其窗口对象和视图对象创建完成之后,就会请求与WindowManagerService建立一个连接,即请求 ...

  9. android数据存储之Sqlite(二)

    SQLite学习笔记 前言:上一章我们介绍了sqlite的一些基本知识以及在dos命令下对sqlite进行的增删改查的操作,这一章我们将在android项目中实际来操作sqlite. 1. SQLit ...

随机推荐

  1. 关于wepack的使用总结以及优化探讨

    一.前言 不知不觉,webpack版本已经到4.0了.使用它也有很长一段时间了,回头看看,自己木有总结webpack方面的知识,现在有空起个头,主要是总结自己常用的配置和一下优化的探讨,以后有啥想法也 ...

  2. IOS获取资源路径

    1. 获取已经添加到xcode工程中的某一资源文件 file.txt 的路径 NSString *filePath_= [[NSBundle mainBundle] pathForResource:@ ...

  3. c++语言的输入输出流库

    1.c++语言标准输入输出流 <1>控制符的用法 #include <iostream> #include <iomanip> using namespace st ...

  4. c#实战开发:用.net core开发一个简单的Web以太坊钱包 (六)

    今天就来开发一个C# 版的简易钱包 先回顾以前的内容 c#实战开发:以太坊Geth 命令发布智能合约 (五) c#实战开发:以太坊Geth 常用命令 (四) c#实战开发:以太坊钱包快速同步区块和钱包 ...

  5. mysql 主从模式总结(一)

    1. 主从模式的部署步骤 目标:部署一个有3台主机的单主模式的MySQL分组. Primary:192.168.197.110. Secondary:192.168.197.111. Secondar ...

  6. 【22】访问者模式(Visitor Pattern)

    一.引言 在这篇博文中,我将为大家分享我对访问者模式的理解. 二.访问者模式介绍 2.1 访问者模式的定义 访问者模式是封装一些施加于某种数据结构之上的操作.一旦这些操作需要修改的话,接受这个操作的数 ...

  7. Internet Download Manager IDM 破解器

    IDM 全名Internet Download Manager  是一款国外的多线程下载神器(简称IDM),Internet Download Manager 支持多媒体下载.自动捕获链接.自动识别文 ...

  8. JS 数组位置方法 indexOf()和lastIndexOf()的理解

    var numbers = [1,3,5,7,9,4,3,2,1]; console.log(numbers.indexOf(5)); //从数组的0位开始查找 5 位于数组里面的位置 输出2 首先 ...

  9. AppBoxPro(权限管理框架--FineUIPro基础版+工厂模式+ADO.NET+存储过程)

    FineUIPro基础版火爆来袭,特献上ADO.NET纯SQL方式AppBoxPro,希望大家能够喜欢! 下载源码请到[知识星球] https://t.zsxq.com/3rrNFyv

  10. MySQL 性能优化--优化数据库结构之优化数据类型

    MySQL性能优化--优化数据库结构之优化数据类型   By:授客  QQ:1033553122   优化数字数据(Numeric Data) l   对于唯一ID或其它可用字符串或数字表示的值,选择 ...