Хорошим стилем программирования в Google считают использование ActionBar и Фрагментов.
Для этого они даже изменили конструктор нового проекта в Eclipse .
Таким образом, они тонко намекают, и как бы приучают программистов писать более или менее красивый и изящный код.
Думаю, стоит отметить, что начинание это правильное. Для себя я беру образцы родных гугловских приложений и строю интерфейс, опираясь на их работу.
Сейчас уже сложилась целая традиция в написании кода, чтобы потом не восклицать “какой идиот это написал?” “как это вообще работает?”, я вывожу общий функционал в конкретный класс. Например: класс для работы с базой данных, класс для работы с железом устройства, класс для работы с интернетом.
Так и каждый фрагмент храню отдельным классом унаследованным от чистого Fragment. А когда надо, создаю его через newInstance.
К примеру вот так :
[cce lang=”java” tab_size=”2″ no_links=”false”]
Fragment f = AddCitationFragment.newInstance(R.string.Citation_edit, true);
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ft.replace(R.id.container, f);
ft.addToBackStack(null);
ft.commit();
[/cce]
А внутри его задаю нужные свойства:
[cce lang=”java” tab_size=”2″ no_links=”false”]
static AddCitationFragment newInstance(int galerytype, boolean isEdit) {
AddCitationFragment f = new AddCitationFragment();
Bundle arguments = new Bundle();
arguments.putInt(GALLERY_TYPE, galerytype);
arguments.putBoolean(EDIT, isEdit);
f.setArguments(arguments);
f.setHasOptionsMenu(true);
return f;
}
[/cce]
В Bundle мы закладываем разные данные, нужные по ходу жизни фрагмента. А вот свойство setHasOptionsMenu(true) отвечает за наличие собственного меню в ActionBar этого фрагмента. Для этого нужно переопределить onCreateOptionsMenu у данного фрагмента.
[cce lang=”java” tab_size=”2″ no_links=”false”]
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.clear();
inflater.inflate(R.menu.add_citation, menu);
super.onCreateOptionsMenu(menu, inflater);
}
[/cce]
А при вызове этого меню нужно переопределить onOptionsItemSelected у данного фрагмента:
[cce lang=”java” tab_size=”2″ no_links=”false”]
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.save_citation:
Save_Citation();
return true;
}
return false;
}
[/cce]
На этом можно возрадоваться и успокоиться, но только гладко это все в теории, а на практике не у каждого фрагмента отработает onOptionsItemSelected, как и задумано. В частности, два дня было потрачено на осознание, почему в одном и том же фрагменте onOptionsItemSelected, в одном случае вызывается, а в другом нет.
Сначала данный метод отработает в главной активности, подробно товарищи расписали этот механизм здесь, и если не нашлось в нем нужного действия, вернуть он должен false. Далее вызовется onOptionsItemSelected вашего фрагмента и в нем нужно искать и вызывать нужное действие. Также важно следить за тем, какие фрагменты и в какой последовательности вы создаете, т.к. есть фрагменты, которые как бы и не активны, а перехватывают ваш метод onOptionsItemSelected у себя, и у конечного фрагмента он не вызовется. Таким, к примеру, является ViewPagerFragment, именно он отнял у меня два дня, которые были проведены с отладчиком и поисковиком. Решений у данной проблемы может быть несколько, например, можно добавить в onOptionsItemSelected самого пейджера нужное нам действие, но тогда страдает архитектура классов, т.к. реализация действия одного фрагмента будет находиться в другом. Другой метод состоит в том, чтобы вычистить стек транзакций от злополучного фрагмента и тогда все действия будут в одном классе, но правда тогда придется более детально продумывать всю очередь фрагментов.Или можно просто в каждом onOptionsItemSelected возвращать false, если мы не нашли в нём нужного нам действия.