Android 从片段ActionBarCompat内部获取SupportActionBar

Android 从片段ActionBarCompat内部获取SupportActionBar,android,android-fragments,android-support-library,android-actionbar-compat,Android,Android Fragments,Android Support Library,Android Actionbar Compat,我正在启动一个新项目,它使用v7支持库中的AppCompat/ActionBarCompat。我试图找出如何在片段中使用getSupportActionBar。托管片段的活动扩展了ActionBarActivity,但我没有看到类似的片段支持类 从我的碎片里 public class CrimeFragment extends Fragment { //... getActivity().getSupportActionBar().setSubt

我正在启动一个新项目,它使用
v7
支持库中的
AppCompat/ActionBarCompat
。我试图找出如何在片段中使用
getSupportActionBar
。托管片段的活动扩展了
ActionBarActivity
,但我没有看到类似的片段支持类

从我的碎片里

    public class CrimeFragment extends Fragment {
          //...

          getActivity().getSupportActionBar().setSubtitle(R.string.subtitle); // getSupportActionBar is not defined in the v4 version of Fragment

          //...
    }

使用它的谷歌页面()说,
v4
片段应该没有变化。我是否需要将所有
getActivity()
调用强制转换为
ActionBarActivity
?这似乎是一个糟糕的设计。

片段之后。onActivityCreated(…)您将拥有一个可通过getActivity()访问的有效活动

您需要将其强制转换为ActionBarActivity,然后调用getSupportActionBar()


你确实需要演员。这不是糟糕的设计,而是向后兼容性。

虽然这个问题已经有了公认的答案,但我必须指出,它并不完全正确:从
Fragment.onAttach()
调用
getSupportActionBar()
将在活动旋转时导致
NullPointerException

简短回答:

在ActivityCreated()上的
中使用
((ActionBarActivity)getActivity()).getSupportActionBar()
(或其生命周期中的任何点),而不是
onAttach()

长答案:


原因是,如果在旋转后重新创建
ActionBar活动
,它将在实际创建
ActionBar
对象之前恢复所有片段


support-v7
库中的
ActionBarActivity
源代码:

@Override
protected void onCreate(Bundle savedInstanceState) {
    mImpl = ActionBarActivityDelegate.createDelegate(this);
    super.onCreate(savedInstanceState);
    mImpl.onCreate(savedInstanceState);
}
  • ActionBarActivityDelegate.createDelegate()
    根据Android版本创建
    mImpl
    对象
  • super.onCreate()
    FragmentActivity.onCreate()
    ,它在一次旋转后恢复任何以前的片段(
    FragmentManagerImpl.dispatchCreate()
    ,&c)
  • mImpl.onCreate(savedInstanceState)
    ActionBarActivityDelegate.onCreate()
    ,它从窗口样式中读取
    mhaActionBar
    变量
  • mhaActionBar
    为true之前,
    getSupportActionBar()
    将始终返回
    null
ActionBarActivityDelegate.getSupportActionBar()的源代码


如果有人使用com.android.support:appcompat-v7:和AppCompatActivity作为活动,那么这将起作用

((AppCompatActivity)getActivity()).getSupportActionBar().setSubtitle(R.string.subtitle);

fragment.xml
中,从支持库添加
工具栏
标记

 <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:layout_collapseMode="pin"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
如果您想在
MyFragment
您必须将这一行添加到
onCreateView
函数中

        setHasOptionsMenu(true);
这一行很重要,如果您忘记了它,android将不会填充您的菜单项

假设我们在
menu/fragment\u menu.xml

之后,覆盖以下功能

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.fragment_menu, menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId();
    switch (id) {
        case R.id.action_1:
            // do stuff
            return true;

        case R.id.action_2:
            // do more stuff
            return true;
    }

    return false;
}

希望这对皮埃尔·安托万·拉法叶的回答有所帮助

ActionBarActivity已被弃用;改用
AppCompatActivity

((AppCompatActivity)getActivity()).getSupportActionBar();

对于使用kotlin的用户

(activity as AppCompatActivity).supportActionBar.setSubtitle(R.string.subtitle)

作为GzDev答案的补充,如果您已经拥有字符串,则可以使用kotlin的自动设置器:

(活动作为AppCompatActivity)。supportActionBar?.subtitle=my_字符串

只需使用一个空字符串就可以将其关闭


请注意,这适用于标题和副标题。

谢谢。我希望这不是答案。我希望getActionBar()可能会返回一个v7 ActionBar,如果我需要额外的功能,我会使用它。现在,我的片段必须知道它们承载在什么类型的活动中。不,这不是因为getActionBar()是一个活动API,它不存在于旧版本的SDK(pre-Honeycom)上。这就是为什么我们需要支持类来反映最新SDK中新的和改进的类和API的功能。@Pierre Antoinalafayette为什么必须在onAttach()中实现这一点?在onActivityCreated()中不是更好吗?是的,因为对getSupportActionBar()的第一次调用将通过查找活动中的视图来初始化ActionBar,所以在onActivityCreated()中进行此调用可能更好。我只是想指出,您需要等待片段有活动。我将更新答案。不推荐使用AppCompatActivity而不是ActionBarActivity
ActionBarActivity
。使用
appcompativity
代替
onActivityCreated
现在也不推荐使用(有关替代方法,请参阅)。
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.fragment_menu, menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId();
    switch (id) {
        case R.id.action_1:
            // do stuff
            return true;

        case R.id.action_2:
            // do more stuff
            return true;
    }

    return false;
}
((AppCompatActivity)getActivity()).getSupportActionBar();
(activity as AppCompatActivity).supportActionBar.setSubtitle(R.string.subtitle)