Android:从自定义操作栏调用片段内的函数

时间:2014-11-29 16:30:04

标签: android android-fragments android-actionbar fragment android-lifecycle

我有以下问题:

我的活动操作栏的自定义布局如下:

<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>

此片段在活动的onCreate()期间添加到ViewPager中,如下所示:

    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 ,因此片段不再附加到活动。在这一行,我得到了nullpointerexception:

schwein.setName(add_name.getText().toString());

我现在正在寻找几天以来我的问题的答案,但还没有找到正确的答案。但是我通过了解片段的生命周期取得了进展,并且发现必须对片段在自定义操作栏中的操作期间不活动这一事实做一些事情。 使用像Android Options Menu in Fragment这样的选项菜单,它可以正常工作,但我更喜欢使用自定义操作栏!

有什么想法吗?

1 个答案:

答案 0 :(得分:0)

您的SchweinFragmentAdapter.getItem功能是什么样的?这些函数通常只是创建一个Fragment,而不首先检查片段是否已经存在。这是第一件要检查的事情,因为在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();
}