ViewPager 未使用 FragmentStatePagerAdapter 更新
ViewPager not getting updated using FragmentStatePagerAdapter
我有两个 fragments
、Fragment A
和 Fragment B
。 Fragment A
列出所有产品,Fragment B
显示有关产品及其图像的详细信息。
Fragment A
调用 Fragment B
和 Fragment B
从 Web 服务获取数据并使用 Adapter
设置为 ViewPager
。最初它显示正确的图像,但此后它总是显示相同的图像。
如果我们从 Fragment B 中的任何点击事件中触发 adapter.notifyDataSetChanged()
那么它会完美运行,但我们必须在 Fragment 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();
P图像片段
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);
}
}
});
}
}
更新
// 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);
}
}
非常感谢help/idea。
您可以为片段使用以下 PagerFragment
基础 class 并根据需要实施 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 动态添加和删除 Fragment。所以你也可以尝试删除旧数据的片段,然后再创建一个新的片段。
您没有显示关键部分,即 MyTabActivity.navigateFragment()
。
我相信您正在尝试重用 Fragment B 的现有实例,并通过 Fragment.setArguments()
传递新数据
fragment创建后setArguments没有用
或者
- 每次都创建 Fragment B 的新实例并替换现有实例,或者
- 使用片段中的自定义函数传递新数据
我会建议方法 1,因为通过这样做,即使 Activity 娱乐,例如屏幕旋转。对于方法 2,您需要额外的工作来处理 Activity 重新创建。
如果我的理解正确,您可以尝试使用 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) {
}
});
您可能知道您正在后台进程中加载图像。即 使用 volley 库。
您的 adapter.notifyDataSetChanged()
甚至在进程完成之前就被调用了。
但是正如您所说,当您在按钮上调用它时,单击它会起作用,那么解决方案很简单。
Call your adapter.notifyDataSetChanged()
after the background
process is completed.
即里面:-
@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();
}
}
});
当您使用 FragmentStatePagerAdapter 时,getItem() 仅被调用一次,因此最初您拥有正确的图像,但随后它保持不变。
您应该使用回调接口重新加载数据。因此,当您的片段 A 中的一项被选中时,您将在片段 B 中重新加载数据。为此,您需要添加
public void reloadData() {
//relaod your data here
}
然后像这样在Fragment A中创建一个回调接口
public interface itemSelectedListener {
void onItemSelected(View view, int position)
}
在包含两个片段的 activity 中实现此接口
在
onItemSelected() {
MyFragmentB myFragmentB = ...//get your fragment
myFragmentB.reloadData();
}
终于找到答案了。 Fragment B
被保存在 navigateFragment
中,它已被以下行阻止并且有效。
if (mCurrentFragment != null) {
if (mCurrentFragment instanceof GetProducts)
saveFragmentState(mCurrentFragment.getClass().getName(), mCurrentFragment);
}
我有两个 fragments
、Fragment A
和 Fragment B
。 Fragment A
列出所有产品,Fragment B
显示有关产品及其图像的详细信息。
Fragment A
调用 Fragment B
和 Fragment B
从 Web 服务获取数据并使用 Adapter
设置为 ViewPager
。最初它显示正确的图像,但此后它总是显示相同的图像。
如果我们从 Fragment B 中的任何点击事件中触发 adapter.notifyDataSetChanged()
那么它会完美运行,但我们必须在 Fragment 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();
P图像片段
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);
}
}
});
}
}
更新
// 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);
}
}
非常感谢help/idea。
您可以为片段使用以下 PagerFragment
基础 class 并根据需要实施 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 动态添加和删除 Fragment。所以你也可以尝试删除旧数据的片段,然后再创建一个新的片段。
您没有显示关键部分,即 MyTabActivity.navigateFragment()
。
我相信您正在尝试重用 Fragment B 的现有实例,并通过 Fragment.setArguments()
fragment创建后setArguments没有用
或者
- 每次都创建 Fragment B 的新实例并替换现有实例,或者
- 使用片段中的自定义函数传递新数据
我会建议方法 1,因为通过这样做,即使 Activity 娱乐,例如屏幕旋转。对于方法 2,您需要额外的工作来处理 Activity 重新创建。
如果我的理解正确,您可以尝试使用 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) {
}
});
您可能知道您正在后台进程中加载图像。即 使用 volley 库。
您的 adapter.notifyDataSetChanged()
甚至在进程完成之前就被调用了。
但是正如您所说,当您在按钮上调用它时,单击它会起作用,那么解决方案很简单。
Call your
adapter.notifyDataSetChanged()
after the background process is completed.
即里面:-
@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();
}
}
});
当您使用 FragmentStatePagerAdapter 时,getItem() 仅被调用一次,因此最初您拥有正确的图像,但随后它保持不变。
您应该使用回调接口重新加载数据。因此,当您的片段 A 中的一项被选中时,您将在片段 B 中重新加载数据。为此,您需要添加
public void reloadData() {
//relaod your data here
}
然后像这样在Fragment A中创建一个回调接口
public interface itemSelectedListener {
void onItemSelected(View view, int position)
}
在包含两个片段的 activity 中实现此接口
在
onItemSelected() {
MyFragmentB myFragmentB = ...//get your fragment
myFragmentB.reloadData();
}
终于找到答案了。 Fragment B
被保存在 navigateFragment
中,它已被以下行阻止并且有效。
if (mCurrentFragment != null) {
if (mCurrentFragment instanceof GetProducts)
saveFragmentState(mCurrentFragment.getClass().getName(), mCurrentFragment);
}