Android-ViewPager+Fragment数据更新问题

因为FragmentPagerAdapter内部存在缓存,因此调用notifyDataSetChanged()并不能够去更新Fragment的内容。

参考:http://www.devba.com/index.php/archives/5826.html

http://stackoverflow.com/questions/7263291/viewpager-pageradapter-not-updating-the-view/7287121#7287121

可以有两种解决办法:

(1)重写Adapter的getItemPosition():

public int getItemPosition(Object object) {
    return POSITION_NONE;
}
当调用notifyDataSetChanged()的时候,ViewPager会remove掉所有的view,然后重新去加载。可行,但是效率低。

(2)在view上调用SetTag,然后用ViewPager.findViewWithTag()来找到要更新的view,然后做更新。

因为FragmentPagerAdapter内部缓存Fragment的时候,已经是按照tag的方式缓存的,因此,在更新的时候,我们只要根据tag,拿到fragment,然后去更新fragment就可以了。

看下FragmentPagerAdapter的instantiateItem()方法:

public Object instantiateItem(ViewGroup container, int position)
  {
    if (this.mCurTransaction == null) {
      this.mCurTransaction = this.mFragmentManager.beginTransaction();
    }

    long itemId = getItemId(position);

    String name = makeFragmentName(container.getId(), itemId);//这里就是在生成fragment的tag
    Fragment fragment = this.mFragmentManager.findFragmentByTag(name);//这里是根据tag查找
    if (fragment != null)
    {
      this.mCurTransaction.attach(fragment);//找到直接attch
    } else {
      fragment = getItem(position);//找不到的时候,才会调用getItem

      this.mCurTransaction.add(container.getId(), fragment, makeFragmentName(container.getId(), itemId));
    }

    if (fragment != this.mCurrentPrimaryItem) {
      fragment.setMenuVisibility(false);
      fragment.setUserVisibleHint(false);
    }

    return fragment;
  }
根据原代码我们可以知道系统给每一个Fragment都打上了一个标签,通过标签来寻找相应的fragment,所以当我们第二次进入fragment的时候,fragment的oncreate,oncreateView方法都不会被调用的,因为FragmentPageAdapter中的getitem()方法根本不会被调用,因为系统会根据标签找到相应的fragment,如果已经存在,就不会被调用,fragment有一个缓存机制在这里。
现在的问题是必须要做更新,那么可以这么弄:

public class FragmentViewPagerAdapter extends FragmentPagerAdapter {
	
	private FragmentManager mFragmentManager;
	private List mDatas;
	private List tagList = new ArrayList();

	public FragmentViewPagerAdapter(FragmentManager fm, List datas) {
		super(fm);
		this.mFragmentManager = fm;
		this.mDatas = datas;
	}
	
	@Override
	public Object instantiateItem(ViewGroup container, int position) {    
        tagList.add(makeFragmentName(container.getId(), getItemId(position))); //把tag存起来   
        return super.instantiateItem(container, position);    
    } 
	
	@Override
	public void destroyItem(ViewGroup container, int position, Object object){
		super.destroyItem(container, position, object);
		tagList.remove(makeFragmentName(container.getId(), getItemId(position)));//把tag删掉
	}
	
	@Override
	public Fragment getItem(int position) {
		String url = mDatas.get(position);
		WebViewFragmentV4 webview = new WebViewFragmentV4(url);//本文测试的Fragment是一个WebViewFragment
		return webview;
	}

	@Override
	public int getCount() {
		if (mDatas == null) {
			return 0;
		} else {
			return mDatas.size();
		}
	}

	public void update(List datas){
		this.mDatas = datas;
		notifyDataSetChanged();//并不能起到更新Fragment内容的作用。
	}
	
	public void update(int position){//这个事真正的更新Fragment的内容
		WebViewFragmentV4 fragment = (WebViewFragmentV4)mFragmentManager.findFragmentByTag(tagList.get(position));  
		if(fragment == null){
			return;
		}
		fragment.update();
	}

	private static String makeFragmentName(int viewId, long id) {
	    return "android:switcher:" + viewId + ":" + id;
	}
}
WebViewFragmentV4.java:

public class WebViewFragmentV4 extends Fragment {
	private WebView mWebView;
	private boolean mIsWebViewAvailable;
	private String mUrl;
	public WebViewFragmentV4(String url) {
		this.mUrl = url;
	}

	/**
	 * Called to instantiate the view. Creates and returns the WebView.
	 */
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		if (mWebView != null) {
			mWebView.destroy();
		}
		mWebView = new WebView(getActivity());
		mWebView.getSettings().setUseWideViewPort(true);
		mWebView.getSettings().setLoadWithOverviewMode(true); 
		mWebView.setWebViewClient(new MyWebViewClient());
		mWebView.loadUrl(mUrl);
		mIsWebViewAvailable = true;
		return mWebView;
	}

	/**
	 * Called when the fragment is visible to the user and actively running.
	 * Resumes the WebView.
	 */
	@Override
	public void onPause() {
		super.onPause();
		mWebView.onPause();
	}

	/**
	 * Called when the fragment is no longer resumed. Pauses the WebView.
	 */
	@Override
	public void onResume() {
		mWebView.onResume();
		super.onResume();
	}

	/**
	 * Called when the WebView has been detached from the fragment. The WebView
	 * is no longer available after this time.
	 */
	@Override
	public void onDestroyView() {
		mIsWebViewAvailable = false;
		super.onDestroyView();
	}

	/**
	 * Called when the fragment is no longer in use. Destroys the internal state
	 * of the WebView.
	 */
	@Override
	public void onDestroy() {
		if (mWebView != null) {
			mWebView.destroy();
			mWebView = null;
		}
		super.onDestroy();
	}

	public void update(){
		if (mWebView != null) {
			mWebView.reload();
		}
	}
	
	/**
	 * Gets the WebView.
	 */
	public WebView getWebView() {
		return mIsWebViewAvailable ? mWebView : null;
	}
	
	private static class MyWebViewClient extends WebViewClient {
		
		@Override
		public boolean shouldOverrideUrlLoading(WebView view, String url) {
			view.loadUrl(url);
			return true;
		}

		@Override
		public void onPageStarted(WebView view, String url, Bitmap favicon) {
			super.onPageStarted(view, url, favicon);
		}
		
		@Override
		public void onPageFinished(WebView view, String url) {
			super.onPageFinished(view, url);
		}

		@Override
		public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
			super.onReceivedError(view, errorCode, description, failingUrl);
		}
	}
}

转载请标明出处:http://blog.csdn.net/goldenfish1919/article/details/47661443

测试代码:

//1. 初始化
viewpager = (ViewPager)this.findViewById(R.id.viewpager);
adapter = new FragmentViewPagerAdapter(getSupportFragmentManager(), null);
viewpager.setAdapter(adapter);
//2. 加载数据
List urls = new ArrayList();
urls.add("http://172.16.28.253:8080/web/1.jsp");
urls.add("http://172.16.28.253:8080/web/2.jsp");
urls.add("http://172.16.28.253:8080/web/3.jsp");
urls.add("http://172.16.28.253:8080/web/4.jsp");
adapter.update(urls);
//3. 做更新
Button update = (Button) this.findViewById(R.id.update);
update.setOnClickListener(new View.OnClickListener() {
	@Override
	public void onClick(View v) {
		if(viewpager != null && adapter != null){
			viewpager.setCurrentItem(3, true);
			adapter.update(3);//重新加载position是3的页面
		}
	}
});

重构一下:

(1)BaseFragmentPagerAdapter.java

public abstract class BaseFragmentPagerAdapter extends FragmentPagerAdapter{
	
	private FragmentManager mFragmentManager;
	private List tagList = new ArrayList();
	
	public BaseFragmentPagerAdapter(FragmentManager fm) {
		super(fm);
		this.mFragmentManager = fm;
	}
	
	@Override
	public Object instantiateItem(ViewGroup container, int position) {    
        tagList.add(makeFragmentName(container.getId(), getItemId(position)));    
        return super.instantiateItem(container, position);    
    } 
	
	@Override
	public void destroyItem(ViewGroup container, int position, Object object){
		super.destroyItem(container, position, object);
		tagList.remove(makeFragmentName(container.getId(), getItemId(position)));
	}
	
	private static String makeFragmentName(int viewId, long id) {
	    return "android:switcher:" + viewId + ":" + id;
	}
	
	public void update(int position){
		Fragment fragment = (Fragment)mFragmentManager.findFragmentByTag(tagList.get(position));  
		if(fragment == null){
			return;
		}
		if(fragment instanceof UpdateAble){//这里唯一的要求是Fragment要实现UpdateAble接口
			((UpdateAble)fragment).update();
		}
	}
	
	public interface UpdateAble {
		public void update();
	}
}
以后我们的Adapter只要继承BaseFragmentPagerAdapter就可以了,比如:

(2)FragmentViewPagerAdapter.java

public class FragmentViewPagerAdapter extends BaseFragmentPagerAdapter {
	
	private List mDatas;

	public FragmentViewPagerAdapter(FragmentManager fm, List datas) {
		super(fm);
		this.mDatas = datas;
	}

	@Override
	public Fragment getItem(int position) {
		String url = mDatas.get(position);
		WebViewFragmentV4 webview = new WebViewFragmentV4(url);
		return webview;
	}

	@Override
	public int getCount() {
		if (mDatas == null) {
			return 0;
		} else {
			return mDatas.size();
		}
	}

	public void update(List datas){
		this.mDatas = datas;
		notifyDataSetChanged();
	}
}
跟普通的用法一样,唯一的要求是,Fragment必须要实现UpdateAble接口,perfect!


你可能感兴趣的:(android)