Элементы панели действий дублируются

У меня есть панель действий в моем приложении. Я добавляю элементы действий, используя menu.xml. Я использую панель действий в качестве библиотеки поддержки. Я заметил странную проблему, когда мои действия дублируются.

Я обнаруживаю эту проблему случайным образом, когда оставляю свое устройство бездействующим или работаю с другими приложениями. Пожалуйста, найдите снимок экрана и мой код ниже:

private LoginWebActivity mContext;
private final String TAG = "LoginFragment";

// for metrics
private String mPageNameSignIn = "signin";

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    mView = inflater.inflate(R.layout.webview, container, false);

    return mView;
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    mContext = (LoginWebActivity) getActivity();
    initFragment();

}

@Override
public void onResume() {

    super.onResume();
}

/**
 * Initialises the views and variables of the fragment.
 */
@SuppressLint({ "JavascriptInterface", "SetJavaScriptEnabled" })
protected void initFragment() {


    mWebView = (WebView) mView.findViewById(R.id.webView);
    Bundle b = mContext.getIntent().getExtras();
    if (b != null) {
        mUrl = b.getString(Constants.EXTRA_WEB_LOGIN_URL);
    }
    super.initFragment();

    setHasOptionsMenu(true);
}

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

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Navigate
    switch (item.getItemId()) {
    case R.id.menu_item_signup:
        mContext.onSignUpClick();
        break;
    case android.R.id.home:
        if (!goBack())
            getActivity().finish();
    default:
        break;
    }
    return super.onOptionsItemSelected(item);
}

Мой XML:

<?xml version="1.0" encoding="utf-8"?>

<item
    android:id="@+id/menu_item_signup"
    allergy:showAsAction="ifRoom"
    android:title="@string/sign_up">
</item>

введите здесь описание изображения


person Ganesh    schedule 05.11.2013    source источник
comment
Вы добавляете свой пункт меню из фрагмента, верно? Вы создаете несколько фрагментов?   -  person Szymon    schedule 05.11.2013
comment
У меня есть действие, которое в основном отображает веб-представление, когда пользователь нажимает кнопку входа. Я в основном заменяю существующий фрагмент другим фрагментом.   -  person Ganesh    schedule 05.11.2013
comment
Так возможно ли, что каждый фрагмент добавляет одну опцию панели действий? Можете ли вы переместить эту опцию в действие?   -  person Szymon    schedule 05.11.2013
comment
Вот что решило мою проблему: stackoverflow.com/a/16582895/565433   -  person CaptainNemo    schedule 03.03.2017


Ответы (5)


Вы должны очистить свой объект меню перед добавлением элементов. У меня была такая же проблема, и это было лучшее решение, которое я нашел.

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    menu.clear();
    inflater.inflate(R.menu.signin, menu);
    super.onCreateOptionsMenu(menu, inflater);
}
person Renan Bandeira    schedule 04.12.2013
comment
Кроме того, когда я перешел на компактное приложение, мне пришлось убедиться, что я ссылаюсь на меню в одном месте, а не в действии и его дочерних фрагментах. - person User3; 20.03.2015
comment
@Renan это также очищает мое меню общих действий. Пожалуйста помоги. - person Roon13; 18.12.2015

Довольно поздно для этой вечеринки, но для тех, кто наткнулся на это через Google, как и я, вот настоящая проблема.

Вы не опубликовали свой код действия, который создает фрагмент, но я рискну предположить, что он выглядит примерно так:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_layout);
        Fragment fragment = ...
        getSupportFragmentManager()
            .beginTransaction()
            .add(R.id.fragment_container, fragment)
            .commit();
    }

Проблема в том, что когда действие проходит свой жизненный цикл (что может произойти, как вы говорите, "когда мое устройство простаивает или работает с другими приложениями", как вы говорите), система будет сохранять и восстанавливать состояние фрагментов для вас. . Но с этим кодом вы также добавляете новый фрагмент в свою активность, поэтому в итоге вы получаете несколько фрагментов, работающих в вашей деятельности, каждый из которых добавляет элемент в меню.

Хотя опубликованный обходной путь решит проблему дублирования пунктов меню, он оставит эти дополнительные экземпляры фрагментов лежащими вокруг, что, очевидно, не то, что вам нужно.

Правильное исправление — простая проверка на ноль:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_layout);

        if (savedInstanceState == null) {
            Fragment fragment = ...
            getSupportFragmentManager()
                .beginTransaction()
                .add(R.id.fragment_container, fragment)
                .commit();
        }
    }

Поскольку система укажет, что действие воссоздается с ненулевым Bundle для параметра saveInstanceState, вы проверяете это, чтобы определить, следует ли создавать и добавлять новый фрагмент.

Надеюсь, это поможет.

person dominicoder    schedule 20.01.2015
comment
Спасибо, это было очень полезно. Но разве условие не должно быть if (savedInstanceState == null) { /* add fragment */ }, а не наоборот? - person Jonik; 02.06.2015
comment
Да, должно. Отредактировано. Спасибо! - person dominicoder; 03.06.2015
comment
Tnx dominicoder, я тоже считаю это лучшим решением. - person Dezo; 25.12.2019
comment
Наконец-то нашел решение, которое не является обходным путем с использованием подхода menu?.clear(). - person Damia Fuentes; 28.04.2020

Я использовал отличное решение Ренана Бандейры, и у меня была ошибка, поэтому я немного изменил его, и оно тоже сработало для меня. тогда я делюсь своим опытом: может быть, он снова станет полезным, вся заслуга в его отличном решении.

@Override
    public void onCreateOptionsMenu(Menu menu ) {
       menu.clear();
       MenuInflater inflater = getMenuInflater();    
       inflater.inflate(R.menu."your current activity name ", menu);
    return true;
}
person afra mehrparvar    schedule 01.07.2014
comment
почему вы return true для метода void? - person Robust; 15.12.2017

Я столкнулся с той же проблемой и точно так же, как сказал @Szymon: «Я добавляю пункт меню из фрагмента, я создаю несколько фрагментов?» Итак, мое решение выглядело так, как показано ниже.

при создании:

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    menu.clear();
    inflater.inflate(R.menu.menu, menu);
    menu.findItem(R.id.action_one).setVisible(true);
    menu.findItem(R.id.action_two).setVisible(false);
    super.onCreateOptionsMenu(menu, inflater);
}

onPrepare :

@Override
public void onPrepareOptionsMenu(Menu menu) {
    if (isAdded()
            && !isDetached()
            && isVisible()
            && !isRemoving()
            )
    {
        // show the menu
        if (menu.findItem(R.id.action_one).isVisible())
            menu.findItem(R.id.action_one).setVisible(true);
        // hide the menu
        if (menu.findItem(R.id.action_two).isVisible())
            menu.findItem(R.id.action_two).setVisible(false);
    }
}
person Idunk    schedule 09.09.2015

Вместо этого вы должны использовать следующий метод, и вы больше не увидите дубликатов (обратите внимание, что в качестве аргумента он имеет только объект меню)

  @Override
    public boolean onCreateOptionsMenu( Menu menu )
    {
        getMenuInflater().inflate( R.menu.main_activity_menu, menu );
        return true;
    }
person Santiago Carrillo    schedule 18.09.2015
comment
Сантьяго, пожалуйста, обратите внимание, что он вызывает onCreateOptionsMenu во фрагменте, а не в действии. - person Dezo; 25.12.2019