在onresume之后,ViewPager中的片段为null

时间:2013-11-29 07:52:59

标签: java android android-activity android-fragments tabs

我正在编写一个在MainActivity中有2个标签的应用程序。我使用适用于Eclipse的Android插件创建了活动模板并对其进行了调整。 无论如何,当我在一段时间后恢复应用程序时,片段将为空。

以下是我的活动代码(我删除了“不重要的”部分)

public class MainActivity extends FragmentActivity implements
    ActionBar.TabListener {

/**
 * The {@link android.support.v4.view.PagerAdapter} that will provide
 * fragments for each of the sections. We use a
 * {@link android.support.v4.app.FragmentPagerAdapter} derivative, which
 * will keep every loaded fragment in memory. If this becomes too memory
 * intensive, it may be best to switch to a
 * {@link android.support.v4.app.FragmentStatePagerAdapter}.
 */
SectionsPagerAdapter mSectionsPagerAdapter;

private static final String ARG_SECTION_NUMBER = "section_number";

/**
 * Fragment to display markets on a {@link GoogleMap}.
 */
private GluehweinMapFragment mGluehweinMapFragment;

/**
 * Fragment to display available markets as list.
 */
private GluehweinListFragment mGluehweinListFragment;


/**
 * The {@link ViewPager} that will host the section contents.
 */
ViewPager mViewPager;



/*
 * (non-Javadoc)
 * 
 * @see android.support.v4.app.FragmentActivity#onCreate(android.os.Bundle)
 */
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);


    setContentView(R.layout.activity_main);


    initSectionsPagerAdapter();
//[...]

}

private void initSectionsPagerAdapter() {
    if (mSectionsPagerAdapter == null || mViewPager == null) {
        final ActionBar actionBar = getActionBar();
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
        // Create the adapter that will return a fragment for each of the
        // three
        // primary sections of the app.
        mSectionsPagerAdapter = new SectionsPagerAdapter(
                getSupportFragmentManager());

        // Set up the ViewPager with the sections adapter.
        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(mSectionsPagerAdapter);

        // When swiping between different sections, select the corresponding
        // tab. We can also use ActionBar.Tab#select() to do this if we have
        // a reference to the Tab.
        mViewPager
                .setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
                    @Override
                    public void onPageSelected(int position) {
                        switch (position) {
                        case 0:
                            break;

                        }
                        refreshFragments();
                        actionBar.setSelectedNavigationItem(position);
                    }
                });
        actionBar.getSelectedNavigationIndex();

        // For each of the sections in the app, add a tab to the action bar.
        for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
            // Create a tab with text corresponding to the page title
            // defined by
            // the adapter. Also specify this Activity object, which
            // implements
            // the TabListener interface, as the callback (listener) for
            // when
            // this tab is selected.
            actionBar.addTab(actionBar.newTab()
                    .setText(mSectionsPagerAdapter.getPageTitle(i))
                    .setTabListener(this));
        }
    }
}



/**
 * Hides or shows the closed markets on the list and map
 */
private void updateVisibility() {
    if (this.mGluehweinMapFragment != null) {
        mGluehweinMapFragment.updateVisibility();
    }
    if (this.mGluehweinListFragment != null) {
        mGluehweinListFragment.updateVisibility();
    }
}

@Override
public void onTabSelected(ActionBar.Tab tab,
        FragmentTransaction fragmentTransaction) {

    mViewPager.setCurrentItem(tab.getPosition());
    invalidateOptionsMenu();
}

@Override
public void onTabUnselected(ActionBar.Tab tab,
        FragmentTransaction fragmentTransaction) {
}

@Override
public void onTabReselected(ActionBar.Tab tab,
        FragmentTransaction fragmentTransaction) {
}

/**
 * A {@link FragmentPagerAdapter} that returns a fragment corresponding to
 * one of the sections/tabs/pages.
 */
public class SectionsPagerAdapter extends FragmentPagerAdapter {

    public SectionsPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        // getItem is called to instantiate the fragment for the given page.
        // Return a DummySectionFragment (defined as a static inner class
        // below) with the page number as its lone argument.
        Fragment fragment = null;

        Bundle args = new Bundle();
        args.putInt(ARG_SECTION_NUMBER, position + 1);

        switch (position) {
        case 0:
            // position 0 is the Map
            if (mGluehweinMapFragment == null) {
                mGluehweinMapFragment = new GluehweinMapFragment();
            }
            fragment = mGluehweinMapFragment;
            break;
        case 1:
            // position 1 is the List
            if (mGluehweinListFragment == null) {
                mGluehweinListFragment = new GluehweinListFragment();
            }
            fragment = mGluehweinListFragment;
            break;
        }
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public int getCount() {
        return 2;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        Locale l = Locale.getDefault();
        switch (position) {
        case 0:
            return getString(R.string.tab_map).toUpperCase(l);
        case 1:
            return getString(R.string.tab_list).toUpperCase(l);
        }
        return null;
    }

}

@Override
protected void onResume() {
    // on resume, restart requesting location updates
    super.onResume();
    //[..]
    initSectionsPagerAdapter();
    //some calls on the fragments which are null here!!!
    refreshFragments();
}



/**
 * Notifies the Fragments in the Tabs that data has changed
 */
private void refreshFragments() {
    if (this.mGluehweinMapFragment != null) {
        mGluehweinMapFragment.updateVisibility();
    }
    if (this.mGluehweinListFragment != null) {
        mGluehweinListFragment.updateVisibility();
    }
}   

 }

我问了一位同事他告诉我,将两个片段作为成员放在我的Activity中并不好,因为Android最终会创建片段onResume的新实例,这就是为什么我的引用是null。但他无法告诉我如何解决我的问题。 我正在考虑编写一个getFragment()方法,该方法将使用FragmentManager来获取片段,但我不知道如何将片段置于一个状态,我可以使用{{{ 1}}。

提前谢谢!

1 个答案:

答案 0 :(得分:8)

您的同事是对的:在您的活动变量中使用对片段的引用并不是一个好习惯。您的活动将被销毁,例如当您旋转屏幕时,引用可能会导致内存泄漏。

至于您的问题,请将初始化ViewPager(您的initSectionsPagerAdapter()方法)的代码移至onResume。它将在活动首次启动时以及何时变为可见时被调用,例如,当另一个在顶部的应用程序关闭时。您不需要onResume中的当前代码。

编辑:

创建片段时,不要在活动的变量中存储对它的引用。要稍后访问片段,您可以使用:

FragmentManager fm = this.getFragmentManager();
GluehweinMapFragment f1 = (GluehweinMapFragment)fm.getFragments().get(0); // to get one fragment

for (Fragment f : fm.getFragments()) { // to loop through fragments and checking their type
    if (f instanceof GluehweinMapFragment) {
    }
}