1. 程式人生 > >Android-ViewPager+Fragment數據更新問題

Android-ViewPager+Fragment數據更新問題

!= ima pri bool content 要求 transacti new nds

由於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<String> mDatas;
	private List<String> tagList = new ArrayList<String>();

	public FragmentViewPagerAdapter(FragmentManager fm, List<String> 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<String> 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<String> urls = new ArrayList<String>();
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<String> tagList = new ArrayList<String>();
	
	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<String> mDatas;

	public FragmentViewPagerAdapter(FragmentManager fm, List<String> 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<String> datas){
		this.mDatas = datas;
		notifyDataSetChanged();
	}
}
跟普通的使用方法一樣。唯一的要求是。Fragment必需要實現UpdateAble接口,perfect!




Android-ViewPager+Fragment數據更新問題