Android-ViewPager+Fragment数据更新问题

Posted zhchoutai

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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<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数据更新问题的主要内容,如果未能解决你的问题,请参考以下文章

Android-ViewPager2

Android-ViewPager源码解析与性能优化

Fragmen直接来回切换deno

安卓开发之Activity传输数据到Fragmen+实例分析

gitee查询用户名和密码 Android Studio 3.5以上版本新特性 sharePreferences 使用 不同的Activity间的preferences共享问题 Fragmen

关于ViewPager.PageTransformer的一些理解