Android Activity 의 시작 프로 세 스 원본 분석

19939 단어 AndroidActivity
머리말
Activity 는 Android 에서 매우 중요 한 개념 으로 4 대 구성 요소 의 첫 번 째 라 고 할 수 있 습 니 다.Activity 에 대해 많은 내용 이 있 습 니 다.예 를 들 어 생명 주기 와 Flags 를 시작 하 는 것 입 니 다.이 두 가 지 는 분명히 말 하고 싶 습 니 다.아마도 두 편의 긴 글 을 써 야 할 것 입 니 다.게다가 그들의 소스 코드 를 분석 해 야 할 것 입 니 다.그러나 본 논문 의 중심 은 그들 이 아니 라 제 가 소개 하고 자 하 는 것 은 Activity 의 전형 적 인 작 동 과정 입 니 다.본 고 는 소스 코드 의 측면 에서 이 를 분석 할 것 입 니 다.startActivity 가 호출 될 때 Activity 를 시작 할 수 있다 는 것 을 알 고 있 습 니 다.그런데 이 Activity 가 어떻게 시작 되 는 지 아 십 니까?모든 Activity 도 하나의 대상 입 니 다.이 대상 이 언제 만 들 어 졌 는 지 아 세 요?왜 onCreate 가 Activity 의 실행 입구 입 니까?이 모든 것 이 시스템 에 의 해 봉 인 됩 니 다.우리 에 게 투명 합 니 다.우리 가 사용 할 때 하나의 intent 를 전달 한 다음 에 startActivity 만 목적 을 달성 할 수 있 습 니 다.그러나 본 고 를 읽 은 후에 그 뒤에 어떤 일 을 했 는 지 알 게 될 것 입 니 다.분석 하기 전에 나 는 먼저 몇 가지 유형 을 소개 한다.
  • Activity:이것 은 모두 가 잘 알 고 있 습 니 다.startActivity 방법의 진정한 실현 은 Activity 에서
  • Instrumentation:Activity 를 보조 하여 Activity 를 시작 하 는 과정 을 완성 합 니 다
  • Activity Thread(ApplicationThread+ApplicationThread Native+IApplicationThread 포함):Activity 를 진정 으로 시작 하 는 실현 은 모두 여기에 있 습 니 다
  • 소스 코드 분석
    일단 입 구 를 볼 게 요.
    code:Activity#startActivity
    
    @Override 
    public void startActivity(Intent intent) { 
     startActivity(intent, null); 
    } 
     
    @Override 
    public void startActivity(Intent intent, Bundle options) { 
     if (options != null) { 
      startActivityForResult(intent, -1, options); 
     } else { 
      // Note we want to go through this call for compatibility with 
      // applications that may have overridden the method. 
      startActivityForResult(intent, -1); 
     } 
    } 
     
    public void startActivityForResult(Intent intent, int requestCode) { 
     startActivityForResult(intent, requestCode, null); 
    } 
    
    설명:위 에서 아래로,결국 startActivity ForResult 로 이 루어 진 것 이 분명 합 니 다.
    이어서 보다
    code:Activity#startActivityForResult
    
    public void startActivityForResult(Intent intent, int requestCode, Bundle options) { 
     //   Activity mParent null,mParent   ActivityGroup ,ActivityGroup    
     if (mParent == null) { 
      //       Activity,      mMainThread.getApplicationThread()    
      Instrumentation.ActivityResult ar = 
       mInstrumentation.execStartActivity( 
        this, mMainThread.getApplicationThread(), mToken, this, 
        intent, requestCode, options); 
      if (ar != null) { 
       //    , onActivityResult     
       mMainThread.sendActivityResult( 
        mToken, mEmbeddedID, requestCode, ar.getResultCode(), 
        ar.getResultData()); 
      } 
      if (requestCode >= 0) { 
       // If this start is requesting a result, we can avoid making 
       // the activity visible until the result is received. Setting 
       // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the 
       // activity hidden during this time, to avoid flickering. 
       // This can only be done when a result is requested because 
       // that guarantees we will get information back when the 
       // activity is finished, no matter what happens to it. 
       mStartedActivity = true; 
      } 
     
      final View decor = mWindow != null ? mWindow.peekDecorView() : null; 
      if (decor != null) { 
       decor.cancelPendingInputEvents(); 
      } 
      // TODO Consider clearing/flushing other event sources and events for child windows. 
     } else { 
      // ActivityGroup   Activity  startActivity        ,              
      if (options != null) { 
       mParent.startActivityFromChild(this, intent, requestCode, options); 
      } else { 
       // Note we want to go through this method for compatibility with 
       // existing applications that may have overridden it. 
       mParent.startActivityFromChild(this, intent, requestCode); 
      } 
     } 
    } 
    
    설명:상기 코드 의 관건 은 모두 주석 이 있 습 니 다.activity 를 진정 으로 여 는 것 이 Instrumentation 의 exec Start Activity 방법 에서 이 루어 진 것 을 발견 할 수 있 습 니 다.
    code:Instrumentation#execStartActivity
    
    public ActivityResult execStartActivity( 
      Context who, IBinder contextThread, IBinder token, Activity target, 
      Intent intent, int requestCode, Bundle options) { 
     //       whoThread   ,   scheduleLaunchActivity      activity    
     IApplicationThread whoThread = (IApplicationThread) contextThread; 
     if (mActivityMonitors != null) { 
      synchronized (mSync) { 
       //            activity 
       final int N = mActivityMonitors.size(); 
       for (int i=0; i<N; i++) { 
        final ActivityMonitor am = mActivityMonitors.get(i); 
        if (am.match(who, null, intent)) { 
         //           
         am.mHits++; 
         //    activity    ,  return 
         if (am.isBlocking()) { 
          return requestCode >= 0 ? am.getResult() : null; 
         } 
         break; 
        } 
       } 
      } 
     } 
     try { 
      intent.migrateExtraStreamToClipData(); 
      intent.prepareToLeaveProcess(); 
      //        activity   ,     whoThread   。 
      int result = ActivityManagerNative.getDefault() 
       .startActivity(whoThread, who.getBasePackageName(), intent, 
         intent.resolveTypeIfNeeded(who.getContentResolver()), 
         token, target != null ? target.mEmbeddedID : null, 
         requestCode, 0, null, null, options); 
      //           ,         ,      activity, 
      //     ActivityNotFoundException        
      checkStartActivityResult(result, intent); 
     } catch (RemoteException e) { 
     } 
     return null; 
    } 
    
    설명:이 방법 을 다시 한 번 말씀 드 리 고 싶 습 니 다.checkStart Activity Result 도 전문 적 으로 이상 한 것 을 던 집 니 다.코드 를 보면 아래 의 이상 한 정보 가 낯 설 지 않 을 것 이 라 고 믿 습 니 다.바로 이 방법 입 니 다.그 중에서 가장 익숙 한 것 은 Unable to find explicit activity class 입 니 다.xml 에 목표 activity 를 등록 하지 않 으 면 이 이상 은 던 집 니 다.
    
    /*package*/ static void checkStartActivityResult(int res, Object intent) { 
     if (res >= ActivityManager.START_SUCCESS) { 
      return; 
     } 
      
     switch (res) { 
      case ActivityManager.START_INTENT_NOT_RESOLVED: 
      case ActivityManager.START_CLASS_NOT_FOUND: 
       if (intent instanceof Intent && ((Intent)intent).getComponent() != null) 
        throw new ActivityNotFoundException( 
          "Unable to find explicit activity class " 
          + ((Intent)intent).getComponent().toShortString() 
          + "; have you declared this activity in your AndroidManifest.xml?"); 
       throw new ActivityNotFoundException( 
         "No Activity found to handle " + intent); 
      case ActivityManager.START_PERMISSION_DENIED: 
       throw new SecurityException("Not allowed to start activity " 
         + intent); 
      case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT: 
       throw new AndroidRuntimeException( 
         "FORWARD_RESULT_FLAG used while also requesting a result"); 
      case ActivityManager.START_NOT_ACTIVITY: 
       throw new IllegalArgumentException( 
         "PendingIntent is not an activity"); 
      default: 
       throw new AndroidRuntimeException("Unknown error code " 
         + res + " when starting " + intent); 
     } 
    } 
    
    다음은 IApplicationThread 를 살 펴 보 겠 습 니 다.핵심 기능 은 내부 의 scheduleLaunchActivity 방법 으로 이 루어 집 니 다.IApplicationThread 는 인터페이스 이기 때문에 실현 류 를 찾 아야 합 니 다.제 가 찾 아 드 렸 습 니 다.이것 이 바로 Activity Thread 의 내부 류 ApplicationThread 입 니 다.계승 관 계 를 보 겠 습 니 다.
    private class ApplicationThread extends ApplicationThreadNative;
    public abstract class ApplicationThreadNative extends Binder implements IApplicationThread;
    애플 리 케 이 션 스 레 드 는 IApplicationThread 인 터 페 이 스 를 간접 적 으로 실현 한 것 으로 나 타 났 다.먼저 이러한 구 조 를 살 펴 보 자.

    ApplicationThread 의 대체적인 구 조 를 보면 Activity 의 생명주기 중의 resume,newIntent,pause,stop 등 사건 이 모두 그것 에 의 해 촉발 되 었 다 는 것 을 추측 할 수 있 을 것 이다.사실은 그렇다.여기 서 우 리 는 문 제 를 설명 하기 위해 scheduleLaunchActivity 방법 만 본다.
    code:ApplicationThread#scheduleLaunchActivity
    
    public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident, 
      ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo, 
      int procState, Bundle state, List<ResultInfo> pendingResults, 
      List<Intent> pendingNewIntents, boolean notResumed, boolean isForward, 
      String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) { 
     
     updateProcessState(procState, false); 
     
     ActivityClientRecord r = new ActivityClientRecord(); 
     
     r.token = token; 
     r.ident = ident; 
     r.intent = intent; 
     r.activityInfo = info; 
     r.compatInfo = compatInfo; 
     r.state = state; 
     
     r.pendingResults = pendingResults; 
     r.pendingIntents = pendingNewIntents; 
     
     r.startsNotResumed = notResumed; 
     r.isForward = isForward; 
     
     r.profileFile = profileName; 
     r.profileFd = profileFd; 
     r.autoStopProfiler = autoStopProfiler; 
     
     updatePendingConfiguration(curConfig); 
     
     queueOrSendMessage(H.LAUNCH_ACTIVITY, r); 
    } 
    
    설명:상기 코드 는 이해 하기 쉽 고 activity 기록 을 작성 한 다음 에 메 시 지 를 보 냅 니 다.그래서 우 리 는 Handler 가 이 메 시 지 를 어떻게 처리 하 는 지 봐 야 합 니 다.지금 이 Handler 로 넘 어가 면 아주 짧 은 이름 이 H 라 고 합 니 다.
    code:ActivityThread#H
    
    //     ,             
    private class H extends Handler { 
     
     public void handleMessage(Message msg) { 
      if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what)); 
      switch (msg.what) { 
       //    LAUNCH_ACTIVITY     
       case LAUNCH_ACTIVITY: { 
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart"); 
        ActivityClientRecord r = (ActivityClientRecord)msg.obj; 
     
        r.packageInfo = getPackageInfoNoCheck( 
          r.activityInfo.applicationInfo, r.compatInfo); 
        //    startActivity   
        handleLaunchActivity(r, null); 
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 
       } break; 
       case RELAUNCH_ACTIVITY: { 
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart"); 
        ActivityClientRecord r = (ActivityClientRecord)msg.obj; 
        handleRelaunchActivity(r); 
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 
       } break; 
       case PAUSE_ACTIVITY: 
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause"); 
        handlePauseActivity((IBinder)msg.obj, false, msg.arg1 != 0, msg.arg2); 
        maybeSnapshot(); 
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 
        break; 
       ... 
      } 
    } 
    
    설명:handleLaunchActivity 도 봐 야 할 것 같 아 요.
    code:ActivityThread#handleLaunchActivity
    
    private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) { 
     // If we are getting ready to gc after going to the background, well 
     // we are back active so skip it. 
     unscheduleGcIdler(); 
     
     if (r.profileFd != null) { 
      mProfiler.setProfiler(r.profileFile, r.profileFd); 
      mProfiler.startProfiling(); 
      mProfiler.autoStopProfiler = r.autoStopProfiler; 
     } 
     
     // Make sure we are running with the most recent config. 
     handleConfigurationChanged(null, null); 
     
     if (localLOGV) Slog.v( 
      TAG, "Handling launch of " + r); 
     //     ,          ,        , 
     //performLaunchActivity     activity   , 
     //  activity     ,  onCreate     
     Activity a = performLaunchActivity(r, customIntent); 
     
     if (a != null) { 
      r.createdConfig = new Configuration(mConfiguration); 
      Bundle oldState = r.state; 
      //   ,  activity onResume     
      handleResumeActivity(r.token, false, r.isForward, 
        !r.activity.mFinished && !r.startsNotResumed); 
     
      if (!r.activity.mFinished && r.startsNotResumed) { 
       // The activity manager actually wants this one to start out 
       // paused, because it needs to be visible but isn't in the 
       // foreground. We accomplish this by going through the 
       // normal startup (because activities expect to go through 
       // onResume() the first time they run, before their window 
       // is displayed), and then pausing it. However, in this case 
       // we do -not- need to do the full pause cycle (of freezing 
       // and such) because the activity manager assumes it can just 
       // retain the current state it has. 
       try { 
        r.activity.mCalled = false; 
        //  ,   activity    , activity onPause     
        mInstrumentation.callActivityOnPause(r.activity); 
        // We need to keep around the original state, in case 
        // we need to be created again. But we only do this 
        // for pre-Honeycomb apps, which always save their state 
        // when pausing, so we can not have them save their state 
        // when restarting from a paused state. For HC and later, 
        // we want to (and can) let the state be saved as the normal 
        // part of stopping the activity. 
        if (r.isPreHoneycomb()) { 
         r.state = oldState; 
        } 
        if (!r.activity.mCalled) { 
         throw new SuperNotCalledException( 
          "Activity " + r.intent.getComponent().toShortString() + 
          " did not call through to super.onPause()"); 
        } 
     
       } catch (SuperNotCalledException e) { 
        throw e; 
     
       } catch (Exception e) { 
        if (!mInstrumentation.onException(r.activity, e)) { 
         throw new RuntimeException( 
           "Unable to pause activity " 
           + r.intent.getComponent().toShortString() 
           + ": " + e.toString(), e); 
        } 
       } 
       r.paused = true; 
      } 
     } else { 
      // If there was an error, for any reason, tell the activity 
      // manager to stop us. 
      try { 
       ActivityManagerNative.getDefault() 
        .finishActivity(r.token, Activity.RESULT_CANCELED, null); 
      } catch (RemoteException ex) { 
       // Ignore 
      } 
     } 
    } 
    
    설명:원래 activity 와 새로운 activity 간 의 상태 동기 화 에 대해 여러분 이 관심 이 있 으 면 스스로 연구 할 수 있 습 니 다.논리 가 너무 복잡 하기 때문에 저 는 모든 문 제 를 분명하게 말 할 수 없습니다.그렇지 않 으 면 디 테 일 한 부분 에 너무 깊이 들 어가 전체적인 논 리 를 파 묻 히 고 소스 코드 를 연구 하 는 데 필요 한 것 은 전체적인 논 리 를 잘 알 아야 합 니 다.다음은 마지막 방법 을 보 겠 습 니 다.이 방법 은 activity 의 시작 과정의 진정한 실현 입 니 다.
    code:ActivityThread#performLaunchActivity
    
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { 
     // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")"); 
     
     ActivityInfo aInfo = r.activityInfo; 
     if (r.packageInfo == null) { 
      r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo, 
        Context.CONTEXT_INCLUDE_CODE); 
     } 
     //   intent      activity      
     ComponentName component = r.intent.getComponent(); 
     if (component == null) { 
      component = r.intent.resolveActivity( 
       mInitialApplication.getPackageManager()); 
      r.intent.setComponent(component); 
     } 
     
     if (r.activityInfo.targetActivity != null) { 
      component = new ComponentName(r.activityInfo.packageName, 
        r.activityInfo.targetActivity); 
     } 
     
     Activity activity = null; 
     try { 
      java.lang.ClassLoader cl = r.packageInfo.getClassLoader(); 
      // ClassLoader(    )   activity             newInstance         
      //      Activity        new    ,       new   。 
      activity = mInstrumentation.newActivity( 
        cl, component.getClassName(), r.intent); 
      StrictMode.incrementExpectedActivityCount(activity.getClass()); 
      r.intent.setExtrasClassLoader(cl); 
      if (r.state != null) { 
       r.state.setClassLoader(cl); 
      } 
     } catch (Exception e) { 
      if (!mInstrumentation.onException(activity, e)) { 
       throw new RuntimeException( 
        "Unable to instantiate activity " + component 
        + ": " + e.toString(), e); 
      } 
     } 
     
     try { 
      Application app = r.packageInfo.makeApplication(false, mInstrumentation); 
     
      if (localLOGV) Slog.v(TAG, "Performing launch of " + r); 
      if (localLOGV) Slog.v( 
        TAG, r + ": app=" + app 
        + ", appName=" + app.getPackageName() 
        + ", pkg=" + r.packageInfo.getPackageName() 
        + ", comp=" + r.intent.getComponent().toShortString() 
        + ", dir=" + r.packageInfo.getAppDir()); 
     
      if (activity != null) { 
       Context appContext = createBaseContextForActivity(r, activity); 
       CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager()); 
       Configuration config = new Configuration(mCompatConfiguration); 
       if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity " 
         + r.activityInfo.name + " with config " + config); 
       activity.attach(appContext, this, getInstrumentation(), r.token, 
         r.ident, app, r.intent, r.activityInfo, title, r.parent, 
         r.embeddedID, r.lastNonConfigurationInstances, config); 
     
       if (customIntent != null) { 
        activity.mIntent = customIntent; 
       } 
       r.lastNonConfigurationInstances = null; 
       activity.mStartedActivity = false; 
       int theme = r.activityInfo.getThemeResource() 
       if (theme != 0) { 
        activity.setTheme(theme); 
       } 
     
       activity.mCalled = false; 
       //  activity onCreate    ,    ,Activity    ,        Activity      , 
       //        ,              ApplicationThread      
       mInstrumentation.callActivityOnCreate(activity, r.state); 
       if (!activity.mCalled) { 
        throw new SuperNotCalledException( 
         "Activity " + r.intent.getComponent().toShortString() + 
         " did not call through to super.onCreate()"); 
       } 
       r.activity = activity; 
       r.stopped = true; 
       if (!r.activity.mFinished) { 
        activity.performStart(); 
        r.stopped = false; 
       } 
       if (!r.activity.mFinished) { 
        if (r.state != null) { 
         mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state); 
        } 
       } 
       if (!r.activity.mFinished) { 
        activity.mCalled = false; 
        mInstrumentation.callActivityOnPostCreate(activity, r.state); 
        if (!activity.mCalled) { 
         throw new SuperNotCalledException( 
          "Activity " + r.intent.getComponent().toShortString() + 
          " did not call through to super.onPostCreate()"); 
        } 
       } 
      } 
      r.paused = true; 
     
      mActivities.put(r.token, r); 
     
     } catch (SuperNotCalledException e) { 
      throw e; 
     
     } catch (Exception e) { 
      if (!mInstrumentation.onException(activity, e)) { 
       throw new RuntimeException( 
        "Unable to start activity " + component 
        + ": " + e.toString(), e); 
      } 
     } 
     
     return activity; 
    } 
    
    총결산
    이곳 을 보 았 을 때 Activity 의 작 동 과정 에 대해 감성 적 인 인식 을 가지 게 될 것 이 라 고 믿 습 니 다.Activity 는 매우 복잡 하고 특성 이 많아 서 본 고 는 각 세부 사항 에 대해 깊이 분석 할 수 없다.그리고 정말 각 세부 사항 에 대해 깊이 분석 을 했 더 라 도 그 문장 은 얼마나 길 어야 하 는 지,그리고 인내심 을 가지 고 계속 볼 수 있 는 사람 이 있 습 니까?본문 이 여러분 에 게 도움 을 줄 수 있 기 를 바 랍 니 다.읽 어 주 셔 서 감사합니다.많은 응원 부 탁 드 리 겠 습 니 다.

    좋은 웹페이지 즐겨찾기