ViewPager не обновляется с помощью FragmentStatePagerAdapter

У меня есть два fragments, Fragment A и Fragment B. Fragment A перечислены все продукты, а Fragment B - подробная информация о продукте и его изображениях.

Fragment A вызывает Fragment B и Fragment B извлекает данные из веб-службы и устанавливает на ViewPager с помощью Adapter. Первоначально он отображает правильное изображение, но после этого он всегда имеет одинаковое изображение.

Если мы стреляем из adapter.notifyDataSetChanged() из любого события click в фрагменте B, то он работает отлично, но мы должны отображать, как только отображается фрагмент B

Посмотрите на код.

 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();
   }
}

Фрагмент 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

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

ПОСЛЕДНЕЕ ОБНОВЛЕНИЕ

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

    }

}

Любая помощь/идея высоко оценена.

Ответ 1

Наконец, я решил ответ. Fragment B сохранялся в navigateFragment, он был предотвращен следующей строкой и работал.

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

Ответ 2

Вы можете использовать следующий базовый класс PagerFragment для своих фрагментов и при необходимости применять метод onVisible:

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()");
    }
}

}

Или вы просто предварительно загружаете данные на Fragment A и уведомляете адаптер при загрузке данных, а затем изменяете страницы. Всегда можно добавлять и удалять фрагменты динамически из ViewPager. Таким образом, вы также можете попытаться удалить фрагмент со старыми данными и впоследствии создать новый.

Ответ 3

Вы не показали критическую часть, т.е. MyTabActivity.navigateFragment().

Я считаю, что вы пытаетесь повторно использовать существующий экземпляр фрагмента B и передавать новые данные Fragment.setArguments()

setArguments не работает после создания фрагмента

либо

  • каждый раз создавать новый экземпляр фрагмента B и заменять существующий, или
  • передавать новые данные с помощью пользовательских функций в фрагменте

Я предлагаю метод 1, потому что, делая это, ваши данные сохраняются даже при активном отдыхе, например. вращение экрана. Для метода 2 вам потребуется дополнительная работа для обработки активности.

Ответ 4

Если я правильно вас понимаю, вы можете попробовать использовать onPageSelected и в зависимости от позиции обновить фрагменты, на которых выбрана страница.

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

        }
    });

Ответ 5

Как вы знаете, вы загружаете изображение в фоновом режиме. i.e с использованием библиотеки волейбола.

ваш adapter.notifyDataSetChanged() вызывается еще до завершения процесса. Но, как вы сказали, когда вы назовете его нажатием кнопки, он работает, тогда решение прост.

Вызовите adapter.notifyDataSetChanged() после фона процесс завершен.

внутри внутри: -

  @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);
            adapter.notifyDataSetChanged();
        }
    }
});

Ответ 6

Когда вы используете FragmentStatePagerAdapter, getItem() вызывается только один раз, поэтому изначально у вас есть правильное изображение, но тогда оно остается прежним.

Вы должны перезагрузить свои данные с помощью интерфейса обратного вызова. Поэтому, когда выбран один из элементов в вашем фрагменте A, вы перезагружаете данные в своем фрагменте B. Для этого вам нужно будет добавить

public void reloadData() {
//relaod your data here
}

Затем создайте интерфейс обратного вызова в фрагменте A, подобном этому

public interface itemSelectedListener {
    void onItemSelected(View view, int position)
}

Внедрить этот интерфейс в действие, которое содержит оба фрагмента

в

onItemSelected() {
    MyFragmentB myFragmentB = ...//get your fragment
    myFragmentB.reloadData();
}