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;
      }
  }
posted @ 2012-01-14 14:17  绿色的麦田  阅读(1063)  评论(0编辑  收藏  举报