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!

时间: 2024-10-10 10:20:43

Android-ViewPager+Fragment数据更新问题的相关文章

Viewpager+fragment数据更新问题解析

在一个 Android 应用中,我们可以使用 FragmentPageAdapter 来处理多 Fragment 页面的横向滑动.但是当 Fragment 对应的数据集发生改变时,我们都希望能够通过调用 mAdapter.notifyDataSetChanged() 来触发 Fragment 页面使用新的数据调整或重新生成其内容,可是当我们使用 notifyDataSetChanged() 后,我们会发现这个方法不会生效.那为什么会这样呢,之前遇到了相同的问题一直没法解决,在网上给出的乱七八糟的

Android——ViewPager+Fragment+ListView之间

Android--ViewPager+Fragment+ListView之间 <span style="font-size:18px;">package com.example.jreduch05; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.view.ViewPager; import android.support.v7.app.A

Android ViewPager Fragment使用懒加载提升性能

?? Android ViewPager Fragment使用懒加载提升性能 Fragment在如今的Android开发中越来越普遍,但是当ViewPager结合Fragment时候,由于Android ViewPager内在的加载机制,导致一个比较严重的加载性能问题,具体来说,假设一个ViewPager中有n多个Fragment,那么ViewPager在初始化阶段将一次性的初始化FragmentPagerAdapter中的至少3个Fragment(如果Fragment多于3),创建和加载Fra

android viewpager fragment切换时界面卡顿解决办法

目前开发的程序在切换View时界面卡顿现象比较严重,影响用户体验,当前项目共就四个View,每个View也只是按钮,所以可以同时加载,不让其它view销毁. 只需在Adapter中重载destroyItem类即可 @Override public void destroyItem(ViewGroup container, int position, Object object) { //重载该方法,防止其它视图被销毁,防止加载视图卡顿 //super.destroyItem(container,

Android ViewPager + Fragment的布局

ViewPager And Fragment 1.之前有篇博客是讲ViewPager的用法的:http://www.cnblogs.com/liangstudyhome/p/3773156.html 2.这里用ViewPager+Fragment做个导航界面: 效果图如下: 3.对实现的思路进行一个简单的介绍: 上面的导航菜单里面的选项卡的总长度是超过了屏幕的,所以用了一个自定义HorizontalScrollView,在自定义HorizontalScrollView中加了两个箭头的图片根据滚动

Android ViewPager+Fragment滑动选项卡,tab点击选项卡

有一段时间一直再研究这个,自Android 3.0以后,很少开发者再用以前的TabWidget控件了.那种效果不是很好,也不能滑动.后来陆续出现了各种各样滑动选项卡,每种的出现都各有优势吧.但我还是推荐ViewPager+Fragment滑动选项卡,tab点击选项卡.因为横屏或者竖屏效果都还不错,针对这种效果,还有一种开源框架的出现.接下来会有所介绍. 转载请注明出处:http://blog.csdn.net/qq_16064871 本文demo下载:请点击 一.ViewPagerActivit

Android - ViewPager+Fragment初始化问题

Android应用开发中,经常会用到ViewPager + Fragment,虽然效果不错,但随之而来的还有一些问题,下面就说说其中的初始化问题. ViewPager初始化时会预加载前后的2个页面,即使设置了setOffscreenPageLimit(0); 它至少也会预加载一个页面 但在实际场景中,可能我们不需要这个预加载的功能,这时我们就需要对其进行一些控制. 我使用的方法是setUserVisibleHint(boolean isVisibleToUser) 每次ViewPager预加载页

android viewpager + fragment 选中当前fragment再触发一些事情的问题

最近项目中遇到一个问题: 背景:使用viewpager+fragment实现首页的滑动:然后需要在第三个fragment被选中时自动弹出对话框. 解决方法: 1.在 vp.setOnPageChangeListener(new OnPageChangeListener() { @Override public void onPageSelected(int arg0) { //arg0为选中当前的fragment的位置,可以处理一些业务. } } 2.frgment提供了一个方法 @Overri

Android Viewpager+Fragment实现滑动标签页

ViewPager 结合Fragment实现一个Activity里包含多个可滑动的标签页,每个标签页可以有独立的布局及响应. 主页布局 1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="mat

Android viewpager + fragment取消预加载

1,在fragment中重写setUserVisibleHint方法private boolean isVisibleToUser;@Overridepublic void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); this.isVisibleToUser = isVisibleToUser; if (isVisibleToUser) { // TODO:1,如