/var/log/messages

debugging with sixth sense

Navigation Drawer 雛形掘削

とりあえず Activity の onCreate から確認着手。定義が以下です。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.d(TAG, "onCreate");
    setContentView(R.layout.activity_my);

    mNavigationDrawerFragment = (NavigationDrawerFragment)
            getFragmentManager().findFragmentById(R.id.navigation_drawer);
    mTitle = getTitle();

    // Set up the drawer.
    mNavigationDrawerFragment.setUp(
            R.id.navigation_drawer,
            (DrawerLayout) findViewById(R.id.drawer_layout));
}

activity_my というレイアウトを setContentView して getTitle しています。getTitle については別途確認の方向。この例では ListView を持ってる Fragment を Drawer として保持している、という形になっています。activity_my.xml が以下です。

<!-- A DrawerLayout is intended to be used as the top-level content view using match_parent for both width and height to consume the full space available. -->
<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MyActivity">

    <!-- As the main content view, the view below consumes the entire
         space available using match_parent in both dimensions. -->
    <FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <!-- android:layout_gravity="start" tells DrawerLayout to treat
         this as a sliding drawer on the left side for left-to-right
         languages and on the right side for right-to-left languages.
         If you're not building against API 17 or higher, use
         android:layout_gravity="left" instead. -->
    <!-- The drawer is given a fixed width in dp and extends the full height of
         the container. -->
    <fragment android:id="@+id/navigation_drawer"
        android:layout_width="@dimen/navigation_drawer_width"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:name="com.example.rms.myapplication.NavigationDrawerFragment"
        tools:layout="@layout/fragment_navigation_drawer" />

</android.support.v4.widget.DrawerLayout>

findFragmentById でオブジェクトを首都して setUp というメソドを呼び出しています。setUp の中身を確認する前に呼び出されているであろう、callback を確認しておきたいと思います。以下の順で呼びだし、なのだったかどうか。

  • onCreate
  • onCreateView
  • onActivityCreated

ひとまず onCreate から。

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Log.d(TAG, "onCreate");

    // Read in the flag indicating whether or not the user has demonstrated awareness of the
    // drawer. See PREF_USER_LEARNED_DRAWER for details.
    SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity());
    mUserLearnedDrawer = sp.getBoolean(PREF_USER_LEARNED_DRAWER, false);

    if (savedInstanceState != null) {
        mCurrentSelectedPosition = savedInstanceState.getInt(STATE_SELECTED_POSITION);
        mFromSavedInstanceState = true;
    }

    // Select either the default item (0) or the last selected item.
    selectItem(mCurrentSelectedPosition);
}

PREF_USER_LEARNED_DRAWER という設定と mUserLearnedDrawer という属性が出てきます。これも別途確認ってことで。あとは private な selectItem を呼び出してます。最初の項目を選択した、って状態にしておくのかどうか。selectItem も別途確認入れます。

次、onCreateView ですが、ここでは ListView の設定が主になっています。最後に先頭チェックしたことにして終了してます。

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    Log.d(TAG, "onCreateView");

    mDrawerListView = (ListView) inflater.inflate(
            R.layout.fragment_navigation_drawer, container, false);
    mDrawerListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            selectItem(position);
        }
    });
    mDrawerListView.setAdapter(new ArrayAdapter<String>(
            getActionBar().getThemedContext(),
            android.R.layout.simple_list_item_activated_1,
            android.R.id.text1,
            new String[]{
                    getString(R.string.title_section1),
                    getString(R.string.title_section2),
                    getString(R.string.title_section3),
            }));
    mDrawerListView.setItemChecked(mCurrentSelectedPosition, true);
    return mDrawerListView;
}

よくよく見てみるに onAttach は onCrate よりも先に (?) 呼び出されるのか。Activity なオブジェクトの参照が渡されて mCallbacks という属性に参照を保持してますね。

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    Log.d(TAG, "onAttach");
    try {
        mCallbacks = (NavigationDrawerCallbacks) activity;
    } catch (ClassCastException e) {
        throw new ClassCastException("Activity must implement NavigationDrawerCallbacks.");
    }
}

これは確か selectItem で呼び出されている callback のはず。ちなみに NavigationDrawerCallbacks という interface の定義は以下ですね。

public static interface NavigationDrawerCallbacks {
    /**
     * Called when an item in the navigation drawer is selected.
     */
    void onNavigationDrawerItemSelected(int position);
}

ということで onCrate から呼び出されている selectItem メソド確認します。

private void selectItem(int position) {
    mCurrentSelectedPosition = position;
    if (mDrawerListView != null) {
        mDrawerListView.setItemChecked(position, true);
    }
    if (mDrawerLayout != null) {
        mDrawerLayout.closeDrawer(mFragmentContainerView);
    }
    if (mCallbacks != null) {
        mCallbacks.onNavigationDrawerItemSelected(position);
    }
}

選択された位置が引数で渡されて

  • ListView の setItemChecked メソド呼び出し
  • DrawerLayout の closeDrawer メソド呼び出し
  • NavigationDrawerCallbacks の callback 呼び出し

という形です。

時間切れ

setUP および mUserLearnedDrawer あたりが継続ですね。あと要確認なのが

  • setHasOptionsMenu メソド (Fragment?)
  • ListView#setItemChecked メソド
  • getTitle メソド (Activity?)

あたりですね。

ちなみに

ってことで callback の呼び出し順を確認してみました。以下な順になっている模様。

  • Activity#onCreate
  • Fragment#onAttach
  • Fragment#onCreate
  • Fragment#onCreateView
  • Fragment#onActivityCreated

Comments