Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ViewPager not getting updated using FragmentStatePagerAdapter

I've a two fragments, Fragment A and Fragment B. Fragment A lists all products and Fragment B shows detail about the product and its images.

Fragment A calls Fragment B and Fragment B fetches data from web service and sets to ViewPager using Adapter. Initially it displays correct image but thereafter it always have the same image.

If we fire adapter.notifyDataSetChanged() from any click event in Fragment B then it works perfectly but we have to display as soon as Fragment B is visible

Please look at the code.

 public class ImageAdapter extends FragmentStatePagerAdapter {

private List<String> pImageURL;

public ImageAdapter(FragmentManager fm, List<String> imageURL) {
    super(fm);
    // TODO Auto-generated constructor stub

    pImageURL = imageURL;
    Utility.showLog("PagerAdapter URL", pImageURL.toString());
}

@Override
public Fragment getItem(int position) {
    // TODO Auto-generated method stub

    String imageURL = pImageURL.get(position);

    PImageFragment imageFragment = (PImageFragment) PImageFragment.getInstance();
    imageFragment.setProductImage(imageURL);
    return imageFragment;
}

@Override
public int getItemPosition(Object object) {

    PImageFragment pFragment = (PImageFragment) object;
    String URL = pFragment.getProductImage();

    int position = pImageURL.indexOf(URL);

    if (position>=0)
        URL = pImageURL.get(position);

    if (position>=0)
        return position;
    else
        return POSITION_NONE;

}

@Override
public int getCount() {
    // TODO Auto-generated method stub
    return pImageURL.size();
   }
}

Fragment B

   // Image Loading Process

    String p_images = model.getProdutImageURL();

    imageUrl = new ArrayList<String>();


    if (p_images.contains(","))
        imageUrl.addAll(Arrays.asList(p_images.split(",")));
    else
        imageUrl.add(p_images);

    mAdapter = new ImageAdapter(getChildFragmentManager(), imageUrl);
    vPager.setPageTransformer(true, new DepthPageTransformer());
    vPager.setAdapter(mAdapter);

    mAdapter.notifyDataSetChanged();

PImage Fragment

public class PImageFragment extends Fragment {

private static final String TAG = "Product_Images_Fragment";
private View rootView;

private ImageView ivProductImage;
private String imageURL;

@Override
@Nullable
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // TODO Auto-generated method stub

    rootView = inflater.inflate(R.layout.p_detail_images, container, false);

    bindComponents(rootView);
    loadImages(imageURL);
    return rootView;

}

public static Fragment getInstance() {

    Fragment fragment = new PImageFragment();
    return fragment;
}

public void setProductImage(String image_url) {

    imageURL = image_url;
    Utility.showLog(TAG + "Received URL : ", imageURL.toString());

}

public String getProductImage() {

    return imageURL;
}

private void bindComponents(View v) {
    // TODO Auto-generated method stub

    ivProductImage = (ImageView) v.findViewById(R.id.ivProductImage);
}

private void loadImages(String image_url) {


    Utility.showLog(TAG,
            "http://baryapp.com/kickzexchange/assets/products/" + image_url);

    final ProgressBar pBar = (ProgressBar) rootView
            .findViewById(R.id.pBarLoader);
    pBar.setVisibility(View.VISIBLE);

    ImageLoader imgLoader = VolleySingleton.getInstance().getImageLoader();

    imgLoader.get("http://baryapp.com/kickzexchange/assets/products/"
            + image_url, new ImageListener() {

        @Override
        public void onErrorResponse(VolleyError vError) {
            // TODO Auto-generated method stub

            Utility.showLog(TAG, vError.getLocalizedMessage() + "");
        }

        @Override
        public void onResponse(ImageContainer response, boolean result) {
            // TODO Auto-generated method stub

            if (response.getBitmap() != null) {

                ivProductImage.setImageBitmap(response.getBitmap());
                pBar.setVisibility(View.GONE);

            }
        }
    });
}


}

UPDATE

    // This is how fragment A calls fragment B
   ProductDetail pDetail = new ProductDetail();

    Bundle bundle = new Bundle();
    bundle.putString("product_id", productList.get(position).getProductID());
    bundle.putString("product_title", productList.get(position).getProductTitle());

    pDetail.setArguments(bundle);

    ((MyTabActivity) mActivity).navigateFragment(Utility.BUY_TAB, pDetail,
            true);

LATEST UPDATE

    public void navigateFragment(String tag, Fragment fragment,
                             boolean shouldAdd) {

    FragmentManager manager = getSupportFragmentManager();
    FragmentTransaction ft = manager.beginTransaction();


    if (shouldAdd)
        mStacks.get(tag).push(fragment); // push fragment on stack


    if (mCurrentFragment != null) {
        saveFragmentState(mCurrentFragment.getClass().getName(), mCurrentFragment);
    }

    mCurrentFragment = fragment;
    restoreFragmentState(fragment.getClass().getName(), fragment);


    ft.replace(android.R.id.tabcontent, fragment);

    ft.commit();


}

 @Override
protected void onSaveInstanceState(Bundle outState) {
    // TODO Auto-generated method stub
    super.onSaveInstanceState(outState);

    Bundle fragmentStates = new Bundle(mFragmentStates.size());

    for (Map.Entry<String, Fragment.SavedState> entry : mFragmentStates.entrySet()) {
        fragmentStates.putParcelable(entry.getKey(), entry.getValue());
    }
    outState.putParcelable(KEY_FRAGMENT_STATES, fragmentStates);
}


private void saveFragmentState(String id, Fragment fragment) {

    Fragment.SavedState fragmentState =
            getSupportFragmentManager().saveFragmentInstanceState(fragment);
    mFragmentStates.put(id, fragmentState);


}

private void restoreFragmentState(String id, Fragment fragment) {

    Fragment.SavedState fragmentState = mFragmentStates.remove(id);

    if (fragmentState != null) {

        if (!fragment.isAdded())
            fragment.setInitialSavedState(fragmentState);

    }

}

Any help/idea is highly appreciated.

like image 273
moDev Avatar asked Aug 20 '15 22:08

moDev


People also ask

How do I refresh ViewPager fragments?

Using the ViewPager. OnPageChangeListener is the correct way to go, but you will need to refactor your adapter a bit in order to keep a reference to each Fragment contained in the FragmentPagerAdapter. Then, instead of creating a new Fragment, use the one contained in the adapter: mViewPager.

How do I update my Android ViewPager adapter?

Firstly set viewpager adapter to null then recreate the adapter and set i to it to viewpager. Show activity on this post. Define which message which is needed to update. Write below code in the Fragment which is needed update.

Is ViewPager deprecated?

setOnPageChangeListener (listener: ViewPager. OnPageChangeListener!) This function is deprecated.

Should I use ViewPager or ViewPager2?

ViewPager2 is an improved version of the ViewPager library that offers enhanced functionality and addresses common difficulties with using ViewPager . If your app already uses ViewPager , read this page to learn more about migrating to ViewPager2 .


3 Answers

You could use the following PagerFragment base class for your fragments and implement the onVisible method as needed:

public abstract class PagerFragment extends Fragment {

private boolean mCalled = false;
private boolean mWasVisible = false;
private boolean mIsResumed = false;
private boolean mIsPaused = false;

protected void onVisible() {
    mCalled = true;
}

protected void onHide() {
    mCalled = true;
}

/**
 * {@inheritDoc}
 * 
 * @see android.app.Fragment#onAttach(android.app.Activity)
 */
@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
}

/**
 * {@inheritDoc}
 * 
 * @see android.app.Fragment#onDetach()
 */
@Override
public void onDetach() {
    super.onDetach();
}

/**
 * {@inheritDoc}
 * 
 * @see android.app.Fragment#onResume()
 */
@Override
public void onResume() {
    super.onResume();
    mIsPaused = false;
    mIsResumed = true;
    setUserVisibleHint(getUserVisibleHint());
}

/**
 * {@inheritDoc}
 * 
 * @see android.app.Fragment#onPause()
 */
@Override
public void onPause() {
    mIsPaused = true;
    mIsResumed = false;
    setUserVisibleHint(getUserVisibleHint());
    super.onPause();
}

/**
 * {@inheritDoc}
 * 
 * @see android.app.Fragment#setUserVisibleHint(boolean)
 */
@Override
public void setUserVisibleHint(boolean visible) {
    super.setUserVisibleHint(visible);

    mCalled = false;
    if (mIsResumed) {
        if (visible) {
            performVisible();
            mWasVisible = visible;
        } else {
            performHide();
            mWasVisible = visible;
        }
    } else if (mIsPaused && mWasVisible) {
        performHide();
        mWasVisible = visible;
    }

}

private void performVisible() {
    onVisible();
    if (!mCalled) {
        throw new SuperNotCalledException("PagerFragment " + this + " did not call through to super.onVisible()");
    }
}

private void performHide() {
    onHide();
    if (!mCalled) {
        throw new SuperNotCalledException("PagerFragment " + this + " did not call through to super.onHide()");
    }
}

}

Or you simply preload the Data on Fragment A and notify the Adapter when the data was loaded and then change the pages. It is always possible to add and remove Fragments dynamically from a ViewPager. So you may also try to delete the fragment with the old data and create a new one afterwards.

like image 151
Denis Loh Avatar answered Sep 20 '22 07:09

Denis Loh


You haven't shown the critical part, i.e. MyTabActivity.navigateFragment().

I believe you are trying to reuse existing instance of Fragment B, and pass new data by Fragment.setArguments()

setArguments has no use after Fragment is created

either

  1. create new instance of Fragment B every time and replace the existing one, or
  2. pass the new data using custom functions in the fragment

I would suggest method 1, because by doing this, your data is kept even if Activity recreation, e.g. screen rotation. For method 2, you need extra work to handle Activity recreate.

like image 43
Derek Fung Avatar answered Sep 22 '22 07:09

Derek Fung


If I understand you correctly, you can try using the onPageSelected and depending on position update your fragments on which page is selected.

        viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

        }

        @Override
        public void onPageSelected(int position) {

        //use this to run when your fragment is visible

        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    });
like image 24
dejavu89 Avatar answered Sep 21 '22 07:09

dejavu89