Viewpager+fragment数据更新问题解析

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

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

        final long itemId = getItemId(position);  

        // Do we already have this fragment?
        String name = makeFragmentName(container.getId(), itemId);
        Fragment fragment = mFragmentManager.findFragmentByTag(name);
        if (fragment != null) {
            if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
            mCurTransaction.attach(fragment);
        } else {
            fragment = getItem(position);
            if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
            mCurTransaction.add(container.getId(), fragment,
                    makeFragmentName(container.getId(), itemId));
        }
        if (fragment != mCurrentPrimaryItem) {
            fragment.setMenuVisibility(false);
            fragment.setUserVisibleHint(false);
        }  

        return fragment;
    }  

我们特别关注下以下这句

    String name = makeFragmentName(container.getId(), itemId);
    Fragment fragment = mFragmentManager.findFragmentByTag(name);  

根据原代码我们可以知道系统给每一个Fragment都打上了一个标签,通过标签来寻找相应的fragment,所以当我们第二次进入fragment的时候,fragment的oncreate,oncreateView方法都不会被调用的,因为FragmentPageAdapter中的getitem()方法根本不会被调用,因为系统会根据标签找到相应的fragment,如果已经存在,就不会被调用,fragment有一个缓存机制在这里。那么如果我们一定要更新fragment,那么我们又该如何处理呢,我们就可以以其人之道,还治其人之身,我们可以通过tag标签找到我们相应的fragment,就可以对该fragment进行更新。那么我们现在就开始吧。

我们先来定义一个list<String> tagList 来存储一下tag

private List<String> tagList;

第二部重写instantiateItem方法,把fragment对应的标签存储在taglist集合里

    public Object instantiateItem(ViewGroup container, int position) {
        tagList.add(makeFragmentName(container.getId(), getItemId(position)));
        return super.instantiateItem(container, position);
    }  

makeFragmentName()是FragmentPageAdapter源码里打fragment标签的方法

public static String makeFragmentName(int viewId, int index) {
		return "android:switcher:" + viewId + ":" + index;
	}

第三步我们再adapter里自己写一个update()方法

	public void update(int item) {
			Fragment fragment = fm.findFragmentByTag(tagList.get(item));
			if (fragment != null) {
				switch (item) {
				case 0:

					break;
				case 1:
					((QueryFragment) fragment).update();
					break;
				case 2:

					break;
				default:
					break;
				}
			}
		}

我们可以发现在queryFragment里也有一个update()方法,这个方法呢就是接下来我们用接口回掉机制更新我们相应fragment的要使用的方法,方法里的内容根据自己的需要编译就可以了。

好的现在万事具备只要实现fragment的数据更新问题就可以了,通过接口回掉机制来实现。

首先我们定义一个接口,让我们的主Activity来实现

    public interface FragmentListener {  

        public void onFragmentClickListener(int item);
    }  

之后比如我们在A Fragment 里头插入了数据,需要BFragment对该数据进行显示,那么我们现在AFragment的onAttach方法中

    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            listener = (FragmentListener)activity;
        } catch (Exception e) {
            e.printStackTrace();  

        }
    }  

然后对数据更新的时候,我们就在Afragment调用这个接口

if (listener != null) {
							listener.onFragmentClickListener(1);
						}

然后我们回到Activity实现该接口里的方法,更新BFragment界面

public void onFragmentClickListener(int item) {
		adapter.update(item);
		adapter.update(item);
	}

大功告成了,贴一下完整的MainAcitivity代码吧!

package com.example.account.main;

import java.util.ArrayList;

import java.util.List;

import com.example.account.add.AddFragment;
import com.example.account.query.QueryFragment;
import com.example.account.setting.SettingFragment;
import com.example.account.utils.PagerSlidingTabStrip;
import com.melhc.xiji.R;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

import android.support.v4.view.ViewPager;

import android.util.DisplayMetrics;

import android.util.TypedValue;

import android.view.KeyEvent;
import android.view.ViewGroup;
import android.widget.Toast;

public class MainActivity extends FragmentActivity implements FragmentListener{
	private MyPagerAdapter adapter;
	private AddFragment addFragment;
	private List<String> tagList;
	private SettingFragment settingFragment;
	private boolean isExit;
	private QueryFragment queryFragment;
	private ViewPager pager;
	private PagerSlidingTabStrip tabs;
	private FragmentManager fm;
	private DisplayMetrics dm;
	private List<Fragment> list;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		pager = (ViewPager) findViewById(R.id.pager);
		tabs = (PagerSlidingTabStrip) findViewById(R.id.tabs);
		initFragment();
		fm = getSupportFragmentManager();
		tagList = new ArrayList<String>();
		adapter = new MyPagerAdapter(fm);
		pager.setAdapter(adapter);
		tabs.setViewPager(pager);

	}

	public void initFragment() {
		list = new ArrayList<Fragment>();
		addFragment = new AddFragment();
		queryFragment = new QueryFragment();
		settingFragment = new SettingFragment();
		list.add(addFragment);
		list.add(queryFragment);
		list.add(settingFragment);
	}

	public class MyPagerAdapter extends FragmentPagerAdapter {

		public MyPagerAdapter(FragmentManager fm) {

			super(fm);
		}

		private final String[] titles = { "1", "2", "3" };

		@Override
		public CharSequence getPageTitle(int position) {
			return titles[position];
		}

		@Override
		public int getCount() {
			return titles.length;
		}

		@Override
		public Fragment getItem(int position) {
			return list.get(position);
		}

		public Object instantiateItem(ViewGroup container, int position) {
			tagList.add(makeFragmentName(container.getId(),
					(int) getItemId(position)));
			return super.instantiateItem(container, position);
		}

		public void update(int item) {
			Fragment fragment = fm.findFragmentByTag(tagList.get(item));
			if (fragment != null) {
				switch (item) {
				case 0:

					break;
				case 1:
					((QueryFragment) fragment).update();
					break;
				case 2:

					break;
				default:
					break;
				}
			}
		}

	}

	public static String makeFragmentName(int viewId, int index) {
		return "android:switcher:" + viewId + ":" + index;
	}

	public void onFragmentClickListener(int item) {
		adapter.update(item);
		adapter.update(item);
	}

}

Viewpager+fragment数据更新问题解析

时间: 2024-07-29 13:21:10

Viewpager+fragment数据更新问题解析的相关文章

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+GridView的使用(与AndroidQuery框架结合)

最近看了一个AndroidQuery的框架,里面的Demo,有个界面,让博主很喜欢.左右滑动十分顺畅,手感很好,于是拿来和大家分享一下.先看一下效果图: 从图中可以看出,上面的布局是一个Layout里面嵌套有个ViewPager,ViewPager中包含着Fragment,Fragment的布局文件包含了一个简单的GridView,GridView的Item布局很简单,就是一个100*100大小的图片.好啦,先说这么多,然后咱们看代码吧. 最外层Activity的布局文件 <?xml versi

ViewPager+Fragment取消预加载(延迟加载)

在项目中,都或多或少地使用的Tab布局,所以大都会用到ViewPager+Fragment,但是Fragment有个不好或者太好的地方.例如你在ViewPager中添加了三个Fragment,当加载ViewPager中第一个Fragment时,它会默认帮你预先加载了第二个Fragment,当你加载第二个Fragment时,它会帮你加载第三个Fragment.这样虽然有时很好,但是用户只需看一个Fragment时,我们就做了一些多余工作加载了第二个Fragment.在这只需要取消Fragment的

ViewPager+Fragment基础

ViewPager+Fragment MainActivity.java package wuxiaocheng.cn.activity; import android.app.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.sup

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

解决 viewpager fragment 切换 Fragment被销毁的问题

当我们用FragmentViewPagerAdapter和ViewPager来完成滑动切换选项卡时,效果非常不错,但是后来遇到一个问题,FragmentA切换到FragmentB,再滑到FragmentC时,FragmentA的状态数据已经不予保存了,再次滑动到FragmentB时,FragmentA的oncreateView方法会重新调用,如果有网络请求,将会是非常蛋疼,在网上找了半天,最后看到viewpager中有个这样的方法setOffscreenPageLimit,设置为2,然后再一试,

android项目剖解之ViewPager+Fragment 实现tabhost效果

项目中需要用到底栏导航栏,滑动或者点击会切换上面的视图,如图: 这个效果使用Viewpager+Fragmen实现是主流方案,加入你之前对fragment不太了解,可以先看android之Fragment(官网资料翻译) 整个文件如下: 好了废话少说,先上布局文件:main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://sche

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

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