تقديم الإطار الأول لتطبيق Android

صورة



تحية للجميع! هذا المنشور هو استمرار للمنشور حول الغوص العميق في عملية تنزيل تطبيق Android وتشغيله. سنذهب اليوم إلى أبعد من ذلك قليلاً ونناقش اللحظة التي يتم فيها إطلاق النشاط الرئيسي للتطبيق ويجب أن يعرض النظام الإطار الأول. من فضلك تحت القطة.



باتباع الوثائق الرسمية ، فإن عملية التطبيق الجارية مسؤولة عن تنفيذ الخطوات التالية:



  1. إنشاء كائن من فئة التطبيق.
  2. ابدأ الخيط الرئيسي (MainThread ويعرف أيضًا باسم UiThread).
  3. إنشاء نشاط البدء المحدد في البيان.
  4. توسع (تضخيم) الآراء. أي إنشاء طرق العرض التي يتم تسجيلها في ملف xml.
  5. تخطيط الأحجام (View.measure ()) والموضع (View.layout ()) للعروض على الشاشة.
  6. أداء التصيير الأولي.


بعد أن تم استخلاصها الإطار الأول، عملية النظام محل خلفية إطار عرض، والاستعاضة عنها مع تطبيق آخر . يمكن للمستخدم الآن التفاعل مع التطبيق.



صورة



الآن دعونا نلقي نظرة فاحصة على جميع الخطوات.



بداية الدفق الرئيسي



في المنشور السابق تعلمنا:



  • عندما تبدأ عملية التطبيق ، فإنها تستدعي طريقة ActivityThread. main () ، مما يجعل طلب IPC حظرًا إلى طريقة ActivityManagerService. attachApplication () في عملية system_server .
  • system_server IPC- ActivityThread.bindApplication(), BIND_APPLICATION MessageQueue .
  • IPC- ActivityManagerService.attachApplication() , ActivityThread.main() Looper.loop(), ( ) MessageQueue.
  • , BIND_APPLICATION. ActivityThread.handleBindApplication(), APK .


صورة



نقطة مهمة: لا يحدث شيء في الخيط الرئيسي لعملية التطبيق حتى يتم إجراء مكالمة IPC إلى ActivityManagerService. attachApplication () .



التخطيط لإطلاق النشاط



دعونا نرى ما يحدث في عملية system_server بعد استدعاء طريقة ActivityThread. bindApplication () :



public class ActivityManagerService extends IActivityManager.Stub {

  private boolean attachApplicationLocked(
      IApplicationThread thread, int pid, int callingUid,
      long startSeq) {
    thread.bindApplication(...);

    // See if the top visible activity is waiting to run
    //  in this process...
    mAtmInternal.attachApplication(...);

    // Find any services that should be running in this process...
    mServices.attachApplicationLocked(app, processName);

    // Check if a next-broadcast receiver is in this process...
    if (isPendingBroadcastProcessLocked(pid)) {
        sendPendingBroadcastsLocked(app);
    }
    return true;
  }
}


السلسلة ذات الصلة ببدء النشاط هي mAtmInternal. attachApplication (...) . تستدعي الطريقة ActivityTaskManagerService. attachApplication () ، والتي بدورها تستدعي RootActivityContainer. attachApplication () :



class RootActivityContainer extends ConfigurationContainer {

  boolean attachApplication(WindowProcessController app) {
    for (ActivityDisplay display : mActivityDisplays) {
      ActivityStack stack = display.getFocusedStack()
      ActivityRecord top = stack.topRunningActivityLocked();
      stack.getAllRunningVisibleActivitiesLocked(mTmpActivityList);
      for (ActivityRecord activity : mTmpActivityList) {
        if (activity.app == null
            && app.mUid == activity.info.applicationInfo.uid
            && app.mName.equals(activity.processName)) {
          mStackSupervisor.realStartActivityLocked(
            activity,
            app,
            top == activity /* andResume */,
            true /* checkConfig */
          )
        }
      }
    }
    ...
  }
}


يقوم الكود بما يلي:



  • يتجاوز كل شاشة.
  • يحصل على حزمة الأنشطة المركزة لهذا العرض.
  • حلقات خلال كل نشاط من مكدس النشاط المستهدف.
  • إذا كان النشاط ينتمي إلى عملية قيد التشغيل ، فسيتم استدعاء طريقة ActivityStackSupervisor. realStartActivityLocked () . لاحظ أن معلمة andResume ستكون صحيحة إذا كان النشاط في أعلى المكدس.


هذا ما تبدو عليه طريقة ActivityStackSupervisor. realStartActivityLocked () :



public class ActivityStackSupervisor{

  boolean realStartActivityLocked(
    ActivityRecord r,
    WindowProcessController proc,
    boolean andResume,
    boolean checkConfig
  ) {
    ...
    ClientTransaction clientTransaction = ClientTransaction.obtain(
            proc.getThread(), r.appToken);

    clientTransaction.addCallback(LaunchActivityItem.obtain(...));

    // Set desired final state.
    final ActivityLifecycleItem lifecycleItem;
    if (andResume) {
        boolean forward = dc.isNextTransitionForward()
        lifecycleItem = ResumeActivityItem.obtain(forward);
    } else {
        lifecycleItem = PauseActivityItem.obtain();
    }
    clientTransaction.setLifecycleStateRequest(lifecycleItem);

    // Schedule transaction.
    mService.getLifecycleManager()
      .scheduleTransaction(clientTransaction);
    ...
  }
}


جميع استدعاءات الطرق التي رأيناها تحدث في عملية خادم النظام . طريقة ClientLifecycleManager. يقوم ScheduleThread () بإجراء مكالمة IPC إلى ActivityThread. ScheduleTransaction () في عملية التطبيق التي تستدعي ClientTransactionHandler. ScheduleTransaction () لقائمة انتظار رسالة EXECUTE_TRANSACTION :



public abstract class ClientTransactionHandler {

    /** Prepare and schedule transaction for execution. */
    void scheduleTransaction(ClientTransaction transaction) {
        transaction.preExecute(this);
        sendMessage(
          ActivityThread.H.EXECUTE_TRANSACTION,
          transaction
        );
    }
}


عند معالجة رسالة EXECUTE_TRANSACTION ، يتم استدعاء أسلوب TransactionExecutor. تنفيذ () .



يمكنك الآن تحديث الرسم التخطيطي:



صورة



الإطلاق الفعلي للنشاط



منفذ المعاملات. تنفيذ () يدعو TransactionExecutor.

PerformLifecycleSequence () ، والتي بدورها تقوم بإجراء رد اتصال في ActivityThread لإنشاء ( إنشاء ) وبدء ( بدء ) واستئناف ( استئناف ) النشاط:



public class TransactionExecutor {

  private void performLifecycleSequence(...) {
    for (int i = 0, state; i < path.size(); i++) {
      state = path.get(i);
      switch (state) {
        case ON_CREATE:
          mTransactionHandler.handleLaunchActivity(...);
          break;
        case ON_START:
          mTransactionHandler.handleStartActivity(...);
          break;
        case ON_RESUME:
          mTransactionHandler.handleResumeActivity(...);
          break;
        case ON_PAUSE:
          mTransactionHandler.handlePauseActivity(...);
          break;
        case ON_STOP:
          mTransactionHandler.handleStopActivity(...);
          break;
        case ON_DESTROY:
          mTransactionHandler.handleDestroyActivity(...);
          break;
        case ON_RESTART:
          mTransactionHandler.performRestartActivity(...);
          break;
      }
    }
  }
}


تحديث الرسم التخطيطي:



صورة



الإطار الأول



دعنا نلقي نظرة على تسلسل استدعاءات الطريقة التي تؤدي إلى عرض الإطار الأول:



  • النشاط handleResumeActivity ()
  • WindowManagerImpl. addView ()
  • WindowManagerGlobal. addView ()
  • ViewRootImpl. setView ()
  • ViewRootImpl. طلب تخطيط ()
  • ViewRootImpl. الجدول الزمني
  • مصمم الرقصات. postCallback ()
  • مصمم الرقصات. الجدول الزمني


طريقة مصمم الرقصات. ScheduleFrameLocked () في قائمة انتظار رسالة MSG_DO_FRAME :



صورة



عند معالجة رسالة MSG_DO_FRAME ، يتم استدعاء أسلوب Choreographer. doFrame () ، والذي بدوره يستدعي ViewRootImpl. doTraversal () ، الذي يمر مرور قياس و تمرير تخطيط ، وأخيرا أول تمريرة التعادل من خلال التسلسل الهرمي رأي:



صورة



خاتمة



بدأنا بمستوى عالٍ من الفهم لما يحدث عندما ينشئ النظام عملية التطبيق:



صورة



الآن نحن نعرف ما يحدث بالضبط "تحت الغطاء":



صورة



الآن دعنا نربط المخططات من المنشور السابق ، من اللحظة التي ينقر فيها المستخدم على أيقونة التطبيق حتى يتم رسم الرمز الأول. الإطار:



صورة



الآن بعد أن أصبح لدينا الصورة الكاملة ، يمكننا البدء في معرفة كيفية التحكم في البداية الباردة بشكل صحيح. المنشور التالي سيكون عن ذلك! أراك لاحقا.



All Articles