简体   繁体   中英

Fragment return null in viewPager.setOnPageChangeListener()

I have a main activity called GuivActivity that uses viewPager to switch between two fragments (listFragment and SearchFragment). But when I try to get Fragment by id inside onPageSelected, it returns null.

All I want to do here is to restart the loader in ListFragment so that every time when I come back I will have most updated data.

in GuivActivity.java

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_guiv);

        viewPager = (ViewPager)findViewById(R.id.viewpager);
        indicator = (TitlePageIndicator) findViewById(R.id.titleindicator);
        pagerAdapter = new PagerAdapter(getSupportFragmentManager());
        viewPager.setAdapter(pagerAdapter);
        indicator.setViewPager(viewPager);
        indicator.setOnPageChangeListener(listener);
    }
   ViewPager.OnPageChangeListener listener = new ViewPager.SimpleOnPageChangeListener(){
       @Override
       public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

       }
       @Override
       public void onPageSelected(int position) {

           switch (position){
               case 0:
                   FragmentManager fm = getSupportFragmentManager();
                   ListFragment listFragment = (ListFragment) fm.findFragmentById(R.id.list_fragment_id);

               case 1:

               default:
                   break;
           }
       }

       @Override
       public void onPageScrollStateChanged(int state) {

       }
   };

in ListFragment.java

@Override
public void onResume() {
    Message.message(mContext,"on resumed called");
    getLoaderManager().restartLoader(LIST_LOADER,null,this);
    super.onResume();
}

in GuivActivity.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">


<com.viewpagerindicator.TitlePageIndicator
    android:id="@+id/titleindicator"
    android:layout_height="wrap_content"
    android:layout_width="fill_parent" />

<android.support.v4.view.ViewPager
    android:id="@+id/viewpager"
    android:layout_width="match_parent"
    android:layout_height="0px"
    android:layout_weight="1"
    android:background="@android:color/white"/>

in the fragment adatper

 @Override
public Fragment getItem(int position) {
    switch(position){
        case 0:
            return new ListFragment();
        case 1:
            return new SearchFragment();
        default:
            break;
    }

    return null;
}

Solution 1

ListFragment listFragment = (ListFragment) pagerAdapter.instantiateItem(viewPager, position)

Solution 2 It's a hack

ListFragment listFragment = (ListFragment) getSupportFragmentManager().findFragmentByTag(
       "android:switcher:" + R.id.viewpager + ":" + viewPager.getCurrentItem());

Note But I would suggest you to use FragmentPagerAdapter . It would give you much more control than PageAdapter

Why don't you call your fragment class to get the view? then call add on your fragment manager. It's a lot cleaner that way and easier to implement the "back" button.

public void displayView(int position, Bundle arguments) {

         Fragment fragment = null;
        switch (position) {
            case 0:
                fragment = new ListFragment();
                break;
            case 1:               
                break;          
            default:
                break;
        }

        if (fragment != null) {
            FragmentManager fragmentManager = getFragmentManager();

            String backStateName = fragment.getClass().getName();
            boolean fragmentPopped = fragmentManager.popBackStackImmediate (backStateName, 0);

            if (!fragmentPopped&&fragmentManager.findFragmentByTag(backStateName) == null){ //fragment not in back stack, create it.
                FragmentTransaction ft =fragmentManager.beginTransaction();
                ft.replace(R.id.frame_container, fragment,backStateName);
                ft.addToBackStack(backStateName);
                ft.commit();

            }

            // update selected item and title, then close the drawer
            mDrawerList.setItemChecked(position, true);
            mDrawerList.setSelection(position);
            setTitle(navMenuTitles[position]);
            mDrawerLayout.closeDrawer(mDrawerList);
            if (position==0){

            }
        } else {
            // error in creating fragment
            Log.e("MainActivity", "Error in creating fragment");
        }
    }

Coincidentially I was tackling the same problem today. They key is to instantiate the adapter like this:

  mAdapter = new FragmentPagerAdapter(getSupportFragmentManager()) {
    @Override
    public void setPrimaryItem(ViewGroup container, int position, Object object) {
      super.setPrimaryItem(container, position, object);

      mCurrentFragment = (Fragment) object;
    }
  };

Now everytime the view pager switches to another fragment (even on first load and screen orientations) that fragment will be loaded into the mCurrentFragment field variable (don't forget to declare it).

Pros: You don't have to work with internal fragment ids. I just tested it. And it's quite elegant.

Cons: None that I know of.

Note: Also don't forget to implement onSaveInstanceState(Bundle) and onViewStateRestored(Bundle) in your paged fragments if you need that. Based on true story.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM