Android: вызов функции внутри фрагмента из пользовательской панели действий
У меня есть следующая проблема:
У меня есть собственный макет для панели действий моей деятельности:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:divider="?android:attr/dividerVertical"
android:showDividers="middle"
android:dividerPadding="6dp">
<include layout="@layout/include_cancel_button" />
<include layout="@layout/include_done_button" />
</LinearLayout>
с включенной кнопкой вот так:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="?android:actionButtonStyle"
android:id="@+id/actionbar_done"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:onClick="saveSchwein" >
<TextView style="?android:actionBarTabTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingRight="10dp"
android:drawableLeft="@drawable/ic_action_ok"
android:drawablePadding="8dp"
android:gravity="center_vertical"
android:text="@string/ok" />
</FrameLayout>
Этот фрагмент добавляется в ViewPager во время onCreate() такого действия:
viewPager = (ViewPager) findViewById(R.id.schweinpager);
tabPagerAdapter = new SchweinFragmentAdapter(getSupportFragmentManager());
viewPager.setAdapter(tabPagerAdapter);
actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
for (String tab_name : tabs) {
actionBar.addTab(actionBar.newTab().setText(tab_name).setTabListener(this).setTag(tab_name));
}
Пока все отлично работает. У меня есть три фрагмента, отображаемых во вкладках на панели действий, и я могу без проблем провести переключение между ними.
Теперь возникает моя настоящая проблема: я хочу вызвать функцию внутри фрагмента из панели пользовательских действий.
saveSchwein () в активности (поскольку функция во фрагменте не найдена):
public void saveSchwein(View v) {
Fragment fragment = tabPagerAdapter.getItem(0);
((StammdatenFragment) fragment).saveSchwein();
}
и соответствующая функция во фрагменте:
public void saveSchwein() {
if (getActivity() == null) {
System.out.println("getActivity ist null");
}
if (rootView == null) {
System.out.println("rootView ist null");
}
if (isAdded()) { System.out.println("Attached to Activity"); } else { System.out.println("NOT attached to Activity"); }
Schwein schwein = new Schwein();
schwein.setName(add_name.getText().toString());
schwein.setGeschlecht(geschlecht_spinner.getSelectedItem().toString());
schwein.setRasse(rasse_spinner.getSelectedItem().toString());
schwein.setGeburtsdatum(add_geburtsdatum.getText().toString());
schwein.setBesonderheiten(add_besonderheiten.getText().toString());
}
RootView и представления назначаются во время onCreateView() следующим образом:
rootView = inflater.inflate(R.layout.fragment_schwein_stammdaten, container, false);
add_name = (EditText) rootView.findViewById(R.id.add_name);
geschlecht_spinner = (Spinner) rootView.findViewById(R.id.geschlecht_spinner);
rasse_spinner = (Spinner) rootView.findViewById(R.id.rasse_spinner);
add_geburtsdatum = (TextView) rootView.findViewById(R.id.add_geburtsdatum);
add_besonderheiten = (EditText) rootView.findViewById(R.id.add_besonderheiten);
В результате rootView и getActivity() имеют значение null, а isAdded() - false, поэтому фрагмент больше не привязан к действию. В этой строке я получаю нулевое исключение:
schwein.setName(add_name.getText().toString());
Я ищу ответ на свой вопрос уже несколько дней, но пока не нашел правильного ответа. Но я добился прогресса, узнав о жизненном цикле фрагмента, и выяснил, что это должно быть связано с тем, что фрагмент не активен во время действий в панели пользовательских действий. С опциональным меню, подобным здесь, меню опций Android в Fragment работает, но я предпочитаю использовать для этого настраиваемую панель действий!
Есть идеи?
1 ответ
Как выглядит ваша функция SchweinFragmentAdapter.getItem? Часто эти функции просто создают фрагмент, без предварительной проверки, существует ли фрагмент уже. Это первое, что нужно проверить, потому что в saveSchwein вы вызываете getItem напрямую и хотите убедиться, что вы не создаете новый фрагмент (который не имеет представления или действия), а затем вызываете saveSchwein фрагмента для этого нового ненастроенный фрагмент. Это объясняет поведение, которое вы видите.
Если это так, то вы можете сделать это вместо этого:
public void saveSchwein(View v) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("StammdatenFragment");
((StammdatenFragment) fragment).saveSchwein();
}
Другой альтернативой может быть изменение реализации getItem, чтобы он отслеживал все созданные им фрагменты и создавал новые только при необходимости.
public static class SchweinFragmentAdapter extends FragmentPagerAdapter {
private Fragment [] fragments = new Fragment[3];
@Override
public Fragment getItem(int position) {
Fragment fragment = fragments[position];
if (fragment == null) {
if (position == 0) {
fragment = new ...
} else if (position == 1) {
fragment = new ...
} else if (position == 2) {
fragment = new ...
}
fragments[position] = fragment;
}
return fragment;
}
}
РЕДАКТИРОВАТЬ:
Извините, на самом деле есть проблема с решением, которое я вам дал. Да, это работает, но это также может привести к утечке памяти, поскольку Android уже кэширует фрагменты в FragmentPagerAdapter. Я был разочарован этим классом, потому что нет общедоступного API для получения тегов, которые адаптер использует, когда добавляет фрагменты в вашу деятельность. Однако, поскольку мы можем посмотреть на код, мы можем видеть, что они делают.
Лучшее решение, хотя и некрасивое, это использовать findFragmentByTag. Тем не менее, тег не то, что я положил в своем первоначальном ответе. Попробуйте это вместо этого:
private static final int POSITION_STAMMDATEN = //TODO the position of your fragment in the adapter
public void saveSchwein(View v) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag(
"android:switcher:" + viewPager.getId() + ":"
+ tabPagerAdapter.getItemId(POSITION_STAMMDATEN)");
((StammdatenFragment) fragment).saveSchwein();
}