Android
toolbar
SupportLibrary

Toolbarのタイトルのセット方法について

setSupportActionBarについてちょっとハマったのでメモします
動的にタイトルを変えたいときに以下だと反映できません。

NG

onCreate内
setSupportActionBar(toolbar)
toolbar.setTitle("test")

ただ以下だと大丈夫です。

OK

onCreate内
toolbar.setTitle("test")
setSupportActionBar(toolbar)

OK

onCreate内
setSupportActionBar(toolbar)
supportActionBar?.setTitle("test")

なぜ?

setSupportActionBar()でToolbarWidgetWrapperがnewされます。
そのタイミングで以下のようにタイトルがあればmTitleSetがtrueになります。
あとからセットするため、最初はmTitleSetはfalseになります。このフラグが後から効いてきます。

ToolbarWidgetWrapper.java
    public ToolbarWidgetWrapper(Toolbar toolbar, boolean style,
            int defaultNavigationContentDescription, int defaultNavigationIcon) {
        mToolbar = toolbar;
        mTitle = toolbar.getTitle();
...
        mTitleSet = mTitle != null;

setSupportActionBar()を呼んだ後、onCreate内でtoolbarにタイトルをセットしていたとしてもActivity#onPostCreate()から呼ばれる一連の流れで、toolbarのsetTitle()が呼ばれます。

〜一連の流れ〜

Activity.java
    @CallSuper
    protected void onPostCreate(@Nullable Bundle savedInstanceState) {
        if (!isChild()) {
            mTitleReady = true;
            onTitleChanged(getTitle(), getTitleColor());
        }
        mCalled = true;
    }
AppCompatActivity.java
    @Override
    protected void onTitleChanged(CharSequence title, int color) {
        super.onTitleChanged(title, color);
        getDelegate().setTitle(title);
    }
AppCompatDelegateImplV9.java
    @Override
    void onTitleChanged(CharSequence title) {
        ...
            peekSupportActionBar().setWindowTitle(title);
        ...
    }

ToobarWidgetWrapperで mTitleSetがfalseであればtoolbarへActivityのタイトルのセットがされます。

ToolbarのsetTitleではなくToobarWidgetWrapperのsetTitleを呼ぶことで、mTitleSetがtrueになるので、これを阻止できます。つまりgetSupportActionBar().setTitle("test")であれば阻止できます。

ToobarWidgetWrapper.java
    @Override
    public void setWindowTitle(CharSequence title) {
        // "Real" title always trumps window title.
        if (!mTitleSet) {
            setTitleInt(title);
        }
    }

...
    @Override
    public void setTitle(CharSequence title) {
        mTitleSet = true;
        setTitleInt(title);
    }

    private void setTitleInt(CharSequence title) {
        mTitle = title;
        if ((mDisplayOpts & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
            mToolbar.setTitle(title);
        }
    }