[컴][안드로이드] onCreateOptionsMenu 관련 소스 분석

onCreateOptionsMenu / 액션바 메뉴 만들어지는 원리 / 소스 분석 / action bar menu item click 시 routine / 소스 분석 / option menu


Stack trace

onCreateOptionsMenu():95, MainActivity {com.grabeco}
onCreatePanelMenu():2490, Activity {android.app}
onCreatePanelMenu():224, FragmentActivity {android.support.v4.app}
superOnCreatePanelMenu():224, ActionBarActivity {android.support.v7.app}
onCreatePanelMenu():141, ActionBarActivityDelegateICS {android.support.v7.app}
onCreatePanelMenu():199, ActionBarActivity {android.support.v7.app}
onCreatePanelMenu():280, ActionBarActivityDelegateICS$WindowCallbackWrapper {android.support.v7.app}
preparePanel():407, PhoneWindow {com.android.internal.policy.impl}
doInvalidatePanelMenu():769, PhoneWindow {com.android.internal.policy.impl}
run():201, PhoneWindow$1 {com.android.internal.policy.impl}
run():749, Choreographer$CallbackRecord {android.view}
doCallbacks():562, Choreographer {android.view}
doFrame():531, Choreographer {android.view}
run():735, Choreographer$FrameDisplayEventReceiver {android.view}
handleCallback():725, Handler {android.os}
dispatchMessage():92, Handler {android.os}
loop():137, Looper {android.os}
main():5041, ActivityThread {android.app}



Flow of onCreateOptionsMenu

public void run() {
    mHavePendingVsync = false;
    doFrame(mTimestampNanos, mFrame);
}

void doFrame(long frameTimeNanos, int frame) {
  final long startNanos;
  synchronized (mLock) {
      if (!mFrameScheduled) {
          return; // no work to do
      }
      ...
      mFrameScheduled = false;
      mLastFrameTimeNanos = frameTimeNanos;
  }
  doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
  doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
  doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
  ...
}


void doCallbacks(int callbackType, long frameTimeNanos) {
    CallbackRecord callbacks;
    synchronized (mLock) {
        ...
        final long now = SystemClock.uptimeMillis();
        callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(now);
        if (callbacks == null) {
            return;
        }
        mCallbacksRunning = true;
    }
    try {
        for (CallbackRecord c = callbacks; c != null; c = c.next) {
            c.run(frameTimeNanos);
        }
    } finally {
        ...
    }
}


public void run(long frameTimeNanos) {
    if (token == FRAME_CALLBACK_TOKEN) {
        ((FrameCallback)action).doFrame(frameTimeNanos);
    } else {
        ((Runnable)action).run();
    }
}

com.android.internal.policy.impl.PhoneWindow
private final Runnable mInvalidatePanelMenuRunnable = new Runnable() {
    @Override 
    public void run() {
        for (int i = 0; i <= FEATURE_MAX; i++) {
            if ((mInvalidatePanelMenuFeatures & 1 << i) != 0) {
                doInvalidatePanelMenu(i);
            }
        }
        mInvalidatePanelMenuPosted = false;
        mInvalidatePanelMenuFeatures = 0;
    }
};


void doInvalidatePanelMenu(int featureId) {
    ...
    // Prepare the options panel if we have an action bar
    if ((featureId == FEATURE_ACTION_BAR || featureId == FEATURE_OPTIONS_PANEL)
            && mActionBar != null) {
        st = getPanelState(Window.FEATURE_OPTIONS_PANEL, false);
        if (st != null) {
            st.isPrepared = false;
            preparePanel(st, null);
        }
    }
}


public final boolean preparePanel(PanelFeatureState st, KeyEvent event) {

  final Callback cb = getCallback();

  if (cb != null) {
      st.createdPanelView = cb.onCreatePanelView(st.featureId);
  }

  ...
  if (st.createdPanelView == null) {
    // Init the panel state's menu--return false if init failed
    if (st.menu == null || st.refreshMenuContent) {
        if (st.menu == null) {
            if (!initializePanelMenu(st) || (st.menu == null)) {
                return false;
            }
        }
        if (mActionBar != null) {
            if (mActionMenuPresenterCallback == null) {
                mActionMenuPresenterCallback = new ActionMenuPresenterCallback();
            }
            mActionBar.setMenu(st.menu, mActionMenuPresenterCallback);
        }
        // Call callback, and return if it doesn't want to display menu.

        // Creating the panel menu will involve a lot of manipulation;
        // don't dispatch change events to presenters until we're done.
        st.menu.stopDispatchingItemsChanged();
        if ((cb == null) || !cb.onCreatePanelMenu(st.featureId, st.menu)) {
          // Ditch the menu created above
            st.setMenu(null);
            if (mActionBar != null) {
                // Don't show it in the action bar either
                mActionBar.setMenu(null, mActionMenuPresenterCallback);
            }
            return false;
        }
        ...
    }
    ...
  }
}

android.app.Activity
public boolean onCreatePanelMenu(int featureId, Menu menu) {
    if (featureId == Window.FEATURE_OPTIONS_PANEL) {
        boolean show = onCreateOptionsMenu(menu);
        show |= mFragments.dispatchCreateOptionsMenu(menu, getMenuInflater());
        return show;
    }
    return false;
}

MainActivity
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu_actions, menu);

    return super.onCreateOptionsMenu(menu);
}

end


댓글 없음:

댓글 쓰기