zoukankan      html  css  js  c++  java
  • android2.2源码初探

    由于代码中涉及到UI的布局,不得已看android源码。

    源码系android-8即2.2

    从调试环境看最初调用NativeStart.java中的main函数,经过底层的若干次调用,途经ActivityThread.java中的main函数调用,代码如下:

    public static final void main(String[] args) {
         SamplingProfilerIntegration.start();
     
         Process.setArgV0("<pre-initialized>");
     
         Looper.prepareMainLooper();
     
         ActivityThread thread = new ActivityThread();
         thread.attach(false);
     
         Looper.loop();
     
         if (Process.supportsProcesses()) {
             throw new RuntimeException("Main thread loop unexpectedly exited");
         }
     
         thread.detach();
         String name = (thread.mInitialApplication != null)
             ? thread.mInitialApplication.getPackageName()
             : "<unknown>";
         Slog.i(TAG, "Main thread of " + name + " is now exiting");
     }

    这儿应是程序的起点,Looper.loop()展示的为相关的消息处理机制。使得程序不像普通的main函数一样立刻就结束了。

    Looper.java中loop()就是一个消息循环,代码如下:

    /**
     *  Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static final void loop() {
        Looper me = myLooper();
        MessageQueue queue = me.mQueue;
        while (true) {
            Message msg = queue.next(); // might block
            //if (!me.mRun) {
            //    break;
            //}
            if (msg != null) {
                if (msg.target == null) {
                    // No target is a magic identifier for the quit message.
                    return;
                }
                if (me.mLogging!= null) me.mLogging.println(
                        ">>>>> Dispatching to " + msg.target + " "
                        + msg.callback + ": " + msg.what
                        );
                msg.target.dispatchMessage(msg);
                if (me.mLogging!= null) me.mLogging.println(
                        "<<<<< Finished to    " + msg.target + " "
                        + msg.callback);
                msg.recycle();
            }
        }
    }

    顺便把怎样结束消息循环的代码也贴出来,方便对照消息开始的地方。

    public void quit() {
        Message msg = Message.obtain();
        // NOTE: By enqueueing directly into the message queue, the
        // message is left with a null target.  This is how we know it is
        // a quit message.
        mQueue.enqueueMessage(msg, 0);
    }

    接着看Handler.java

    /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

    handleMessage()我们在写消息处理的时候经常用到,看ViewRoot.java中,

    @Override
      public void handleMessage(Message msg) {
          switch (msg.what) {
          case View.AttachInfo.INVALIDATE_MSG:
              ((View) msg.obj).invalidate();
              break;
          case View.AttachInfo.INVALIDATE_RECT_MSG:
              final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj;
              info.target.invalidate(info.left, info.top, info.right, info.bottom);
              info.release();
              break;
          case DO_TRAVERSAL:
              if (mProfile) {
                  Debug.startMethodTracing("ViewRoot");
              }
     
              performTraversals();
     
              if (mProfile) {
                  Debug.stopMethodTracing();
                  mProfile = false;
              }
              break;
          case FINISHED_EVENT:
              handleFinishedEvent(msg.arg1, msg.arg2 != 0);
              break;
          case DISPATCH_KEY:
              if (LOCAL_LOGV) Log.v(
                  "ViewRoot", "Dispatching key "
                  + msg.obj + " to " + mView);
              deliverKeyEvent((KeyEvent)msg.obj, true);
              break;
          case DISPATCH_POINTER: {
              MotionEvent event = (MotionEvent)msg.obj;
              boolean callWhenDone = msg.arg1 != 0;
              
              if (event == null) {
                  try {
                      long timeBeforeGettingEvents;
                      if (MEASURE_LATENCY) {
                          timeBeforeGettingEvents = System.nanoTime();
                      }
     
                      event = sWindowSession.getPendingPointerMove(mWindow);
     
                      if (MEASURE_LATENCY && event != null) {
                          lt.sample("9 Client got events      ", System.nanoTime() - event.getEventTimeNano());
                          lt.sample("8 Client getting events  ", timeBeforeGettingEvents - event.getEventTimeNano());
                      }
                  } catch (RemoteException e) {
                  }
                  callWhenDone = false;
              }
              if (event != null && mTranslator != null) {
                  mTranslator.translateEventInScreenToAppWindow(event);
              }
              try {
                  boolean handled;
                  if (mView != null && mAdded && event != null) {
     
                      // enter touch mode on the down
                      boolean isDown = event.getAction() == MotionEvent.ACTION_DOWN;
                      if (isDown) {
                          ensureTouchMode(true);
                      }
                      if(Config.LOGV) {
                          captureMotionLog("captureDispatchPointer", event);
                      }
                      if (mCurScrollY != 0) {
                          event.offsetLocation(0, mCurScrollY);
                      }
                      if (MEASURE_LATENCY) {
                          lt.sample("A Dispatching TouchEvents", System.nanoTime() - event.getEventTimeNano());
                      }
                      handled = mView.dispatchTouchEvent(event);
                      if (MEASURE_LATENCY) {
                          lt.sample("B Dispatched TouchEvents ", System.nanoTime() - event.getEventTimeNano());
                      }
                      if (!handled && isDown) {
                          int edgeSlop = mViewConfiguration.getScaledEdgeSlop();
     
                          final int edgeFlags = event.getEdgeFlags();
                          int direction = View.FOCUS_UP;
                          int x = (int)event.getX();
                          int y = (int)event.getY();
                          final int[] deltas = new int[2];
     
                          if ((edgeFlags & MotionEvent.EDGE_TOP) != 0) {
                              direction = View.FOCUS_DOWN;
                              if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
                                  deltas[0] = edgeSlop;
                                  x += edgeSlop;
                              } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
                                  deltas[0] = -edgeSlop;
                                  x -= edgeSlop;
                              }
                          } else if ((edgeFlags & MotionEvent.EDGE_BOTTOM) != 0) {
                              direction = View.FOCUS_UP;
                              if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
                                  deltas[0] = edgeSlop;
                                  x += edgeSlop;
                              } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
                                  deltas[0] = -edgeSlop;
                                  x -= edgeSlop;
                              }
                          } else if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
                              direction = View.FOCUS_RIGHT;
                          } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
                              direction = View.FOCUS_LEFT;
                          }
     
                          if (edgeFlags != 0 && mView instanceof ViewGroup) {
                              View nearest = FocusFinder.getInstance().findNearestTouchable(
                                      ((ViewGroup) mView), x, y, direction, deltas);
                              if (nearest != null) {
                                  event.offsetLocation(deltas[0], deltas[1]);
                                  event.setEdgeFlags(0);
                                  mView.dispatchTouchEvent(event);
                              }
                          }
                      }
                  }
              } finally {
                  if (callWhenDone) {
                      try {
                          sWindowSession.finishKey(mWindow);
                      } catch (RemoteException e) {
                      }
                  }
                  if (event != null) {
                      event.recycle();
                  }
                  if (LOCAL_LOGV || WATCH_POINTER) Log.i(TAG, "Done dispatching!");
                  // Let the exception fall through -- the looper will catch
                  // it and take care of the bad app for us.
              }
          } break;
          case DISPATCH_TRACKBALL:
              deliverTrackballEvent((MotionEvent)msg.obj, msg.arg1 != 0);
              break;
          case DISPATCH_APP_VISIBILITY:
              handleAppVisibility(msg.arg1 != 0);
              break;
          case DISPATCH_GET_NEW_SURFACE:
              handleGetNewSurface();
              break;
          case RESIZED:
              ResizedInfo ri = (ResizedInfo)msg.obj;
     
              if (mWinFrame.width() == msg.arg1 && mWinFrame.height() == msg.arg2
                      && mPendingContentInsets.equals(ri.coveredInsets)
                      && mPendingVisibleInsets.equals(ri.visibleInsets)
                      && ((ResizedInfo)msg.obj).newConfig == null) {
                  break;
              }
              // fall through...
          case RESIZED_REPORT:
              if (mAdded) {
                  Configuration config = ((ResizedInfo)msg.obj).newConfig;
                  if (config != null) {
                      updateConfiguration(config, false);
                  }
                  mWinFrame.left = 0;
                  mWinFrame.right = msg.arg1;
                  mWinFrame.top = 0;
                  mWinFrame.bottom = msg.arg2;
                  mPendingContentInsets.set(((ResizedInfo)msg.obj).coveredInsets);
                  mPendingVisibleInsets.set(((ResizedInfo)msg.obj).visibleInsets);
                  if (msg.what == RESIZED_REPORT) {
                      mReportNextDraw = true;
                  }
     
                  if (mView != null) {
                      forceLayout(mView);
                  }
                  requestLayout();
              }
              break;
          case WINDOW_FOCUS_CHANGED: {
              if (mAdded) {
                  boolean hasWindowFocus = msg.arg1 != 0;
                  mAttachInfo.mHasWindowFocus = hasWindowFocus;
                  if (hasWindowFocus) {
                      boolean inTouchMode = msg.arg2 != 0;
                      ensureTouchModeLocally(inTouchMode);
     
                      if (mGlWanted) {
                          checkEglErrors();
                          // we lost the gl context, so recreate it.
                          if (mGlWanted && !mUseGL) {
                              initializeGL();
                              if (mGlCanvas != null) {
                                  float appScale = mAttachInfo.mApplicationScale;
                                  mGlCanvas.setViewport(
                                          (int) (mWidth * appScale + 0.5f),
                                          (int) (mHeight * appScale + 0.5f));
                              }
                          }
                      }
                  }
     
                  mLastWasImTarget = WindowManager.LayoutParams
                          .mayUseInputMethod(mWindowAttributes.flags);
     
                  InputMethodManager imm = InputMethodManager.peekInstance();
                  if (mView != null) {
                      if (hasWindowFocus && imm != null && mLastWasImTarget) {
                          imm.startGettingWindowFocus(mView);
                      }
                      mAttachInfo.mKeyDispatchState.reset();
                      mView.dispatchWindowFocusChanged(hasWindowFocus);
                  }
     
                  // Note: must be done after the focus change callbacks,
                  // so all of the view state is set up correctly.
                  if (hasWindowFocus) {
                      if (imm != null && mLastWasImTarget) {
                          imm.onWindowFocus(mView, mView.findFocus(),
                                  mWindowAttributes.softInputMode,
                                  !mHasHadWindowFocus, mWindowAttributes.flags);
                      }
                      // Clear the forward bit.  We can just do this directly, since
                      // the window manager doesn't care about it.
                      mWindowAttributes.softInputMode &=
                              ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
                      ((WindowManager.LayoutParams)mView.getLayoutParams())
                              .softInputMode &=
                                  ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
                      mHasHadWindowFocus = true;
                  }
     
                  if (hasWindowFocus && mView != null) {
                      sendAccessibilityEvents();
                  }
              }
          } break;
          case DIE:
              doDie();
              break;
          case DISPATCH_KEY_FROM_IME: {
              if (LOCAL_LOGV) Log.v(
                  "ViewRoot", "Dispatching key "
                  + msg.obj + " from IME to " + mView);
              KeyEvent event = (KeyEvent)msg.obj;
              if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
                  // The IME is trying to say this event is from the
                  // system!  Bad bad bad!
                  event = KeyEvent.changeFlags(event,
                          event.getFlags()&~KeyEvent.FLAG_FROM_SYSTEM);
              }
              deliverKeyEventToViewHierarchy((KeyEvent)msg.obj, false);
          } break;
          case FINISH_INPUT_CONNECTION: {
              InputMethodManager imm = InputMethodManager.peekInstance();
              if (imm != null) {
                  imm.reportFinishInputConnection((InputConnection)msg.obj);
              }
          } break;
          case CHECK_FOCUS: {
              InputMethodManager imm = InputMethodManager.peekInstance();
              if (imm != null) {
                  imm.checkFocus();
              }
          } break;
          case CLOSE_SYSTEM_DIALOGS: {
              if (mView != null) {
                  mView.onCloseSystemDialogs((String)msg.obj);
              }
          } break;
          }
      }
  • 相关阅读:
    Jenkins构建、推送、拉取镜像和发布应用
    我们是如何做DevOps的?
    记录这两年是如何一步一步转型到.net core+k8s
    spring cloud+.net core搭建微服务架构:服务注册(一)
    .net core gRPC与IdentityServer4集成认证授权
    同时支持EF+Dapper的混合仓储,助你快速搭建数据访问层
    如何更优雅的在kubernetes平台下记录日志
    spring cloud+.net core搭建微服务架构:Api授权认证(六)
    spring cloud+.net core搭建微服务架构:配置中心续(五)
    spring cloud+.net core搭建微服务架构:配置中心(四)
  • 原文地址:https://www.cnblogs.com/luhouxiang/p/2322361.html
Copyright © 2011-2022 走看看