FragmentPagerAdapter刷新fragment最完美解决方案

 

先感谢kingjxl2006的博客文章《Android FragmentPagerAdapter数据刷新notifyDataSetChanged没效果研究》http://blog.sina.com.cn/s/blog_783ede03010173b4.html,没有他的抛砖引玉,就没有这篇博文。

    好,切入正题,正如上文所说的那样,在fragmentpageadapter的instantiateItem方法里,他会先去FragmentManager里面去查找有没有相关的fragment如果有就直接使用如果没有才会触发fragmentpageadapter的getItem方法获取一个fragment。所以你更新fragments集合是没有作用的。引用kingjxl2006的文章里的代码如下:

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

kingjxl2006的办法是清除FragmentManager里面全部缓存的fragment。这很暴力我不赞同,全部清除会造成fragment重新加载,造成不必要的性能损失。

    
    这个方案还是在instantiateItem方法里作文章,代码如下:

@Override

public Object instantiateItem(ViewGroup container,int position) {

//得到缓存的fragment

Fragment fragment = (Fragment)super.instantiateItem(container,

position);

//得到tag ❶

String fragmentTag = fragment.getTag();

if (fragmentsUpdateFlag[position %fragmentsUpdateFlag.length]) {

//如果这个fragment需要更新

FragmentTransaction ft =fm.beginTransaction();

//移除旧的fragment

ft.remove(fragment);

//换成新的fragment

fragment =fragments[position %fragments.length];

//添加新fragment时必须用前面获得的tag ❶

ft.add(container.getId(), fragment, fragmentTag);

ft.attach(fragment);

ft.commit();

//复位更新标志

fragmentsUpdateFlag[position %fragmentsUpdateFlag.length] =false;

}

return fragment;

}

代码注释得很清楚了,主要思路就是用新的fragment替换FragmentManager里缓存的旧的fragment,重点解释❶的地方,看kingjxl2006文章里的两条代码:

        String name = makeFragmentName(container.getId(), position);
        Fragment fragment = mFragmentManager.findFragmentByTag(name);
   说明fragmentpageadapter内部是用tag识别fragment的,并且有它自己的一套算法用于生成tag,所以我们这里必须用它生成的tag来添加新的fragment,否则fragmentpageadapter就无法识别这个新的fragment。
    fragmentsUpdateFlag如其名,是一个用来标识哪个fragment需要更新的boolean类型的数组。
    很多网友提问fm是什么东西?其实就是一个FragmentManager,在构造的时候传入即可:
    class MyFragmentPagerAdapter extends FragmentPagerAdapter {
        FragmentManager fm;
        MyFragmentPagerAdapter(FragmentManager fm) {
               super(fm);
               this.fm = fm;
        }
        ……
 
    下面贴完整一点的代码,以照顾新同学们:
package com.example.mainframework03;

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.app.FragmentTransaction;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.Log;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.LinearLayout;

public class MainActivity extends FragmentActivity implements
FragmentEvent.OnEventListener {

ViewPager viewPager;
FragmentPagerAdapter adapter;

MainTab01 tab01 = new MainTab01();
MainTab02 tab02 = new MainTab02();
MainTab03 tab03 = new MainTab03();
MainTab04 tab04 = new MainTab04();
MainTab05 tab05 = new MainTab05();
Fragment[] fragments = { tab01, tab02, tab03, tab04 };
boolean[] fragmentsUpdateFlag = { false, false, false, false };

/**
* 底部四个按钮
*/
private LinearLayout tabBtnWeixin;
private LinearLayout tabBtnFrd;
private LinearLayout tabBtnAddress;
private LinearLayout tabBtnSettings;

Handler mainHandler = new Handler() {

/*
* (非 Javadoc)

* @see android.os.Handler#handleMessage(android.os.Message)
*/
@Override
public void handleMessage(Message msg) {
// TODO 自动生成的方法存根
super.handleMessage(msg);
switch (msg.what) {
case MSG.INTO_05:
fragments[3] = tab05;
fragmentsUpdateFlag[3] = true;
adapter.notifyDataSetChanged();
break;
default:
}
}
};

class MyFragmentPagerAdapter extends FragmentPagerAdapter {
FragmentManager fm;

MyFragmentPagerAdapter(FragmentManager fm) {
super(fm);
this.fm = fm;
}

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

@Override
public Fragment getItem(int position) {
Fragment fragment = fragments[position % fragments.length];
Log.i(Common.TAG, "getItem:position=" + position + ",fragment:"
+ fragment.getClass().getName() + ",fragment.tag="
+ fragment.getTag());
return fragments[position % fragments.length];
}

@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}

@Override
public Object instantiateItem(ViewGroup container, int position) {
//得到缓存的fragment
Fragment fragment = (Fragment) super.instantiateItem(container,
position);
//得到tag,这点很重要
String fragmentTag = fragment.getTag();

if (fragmentsUpdateFlag[position % fragmentsUpdateFlag.length]) {
//如果这个fragment需要更新

FragmentTransaction ft = fm.beginTransaction();
//移除旧的fragment
ft.remove(fragment);
//换成新的fragment
fragment = fragments[position % fragments.length];
//添加新fragment时必须用前面获得的tag,这点很重要
ft.add(container.getId(), fragment, fragmentTag);
ft.attach(fragment);
ft.commit();

//复位更新标志
fragmentsUpdateFlag[position % fragmentsUpdateFlag.length] = false;
}

return fragment;
}
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager) findViewById(R.id.id_viewpager);

tabBtnWeixin = (LinearLayout) findViewById(R.id.id_tab_bottom_weixin);
tabBtnFrd = (LinearLayout) findViewById(R.id.id_tab_bottom_friend);
tabBtnAddress = (LinearLayout) findViewById(R.id.id_tab_bottom_contact);
tabBtnSettings = (LinearLayout) findViewById(R.id.id_tab_bottom_setting);

adapter = new MyFragmentPagerAdapter(getSupportFragmentManager());

viewPager.setAdapter(adapter);

viewPager.setOnPageChangeListener(new OnPageChangeListener() {

private int currentIndex;

@Override
public void onPageSelected(int position) {
resetTabBtn();
switch (position) {
case 0:
((ImageButton) tabBtnWeixin
.findViewById(R.id.btn_tab_bottom_weixin))
.setImageResource(R.drawable.tab_weixin_pressed);
break;
case 1:
((ImageButton) tabBtnFrd
.findViewById(R.id.btn_tab_bottom_friend))
.setImageResource(R.drawable.tab_find_frd_pressed);
break;
case 2:
((ImageButton) tabBtnAddress
.findViewById(R.id.btn_tab_bottom_contact))
.setImageResource(R.drawable.tab_address_pressed);
break;
case 3:
((ImageButton) tabBtnSettings
.findViewById(R.id.btn_tab_bottom_setting))
.setImageResource(R.drawable.tab_settings_pressed);
break;
}

currentIndex = position;
}

@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {

}

@Override
public void onPageScrollStateChanged(int arg0) {
}
});

}

protected void resetTabBtn() {
((ImageButton) tabBtnWeixin.findViewById(R.id.btn_tab_bottom_weixin))
.setImageResource(R.drawable.tab_weixin_normal);
((ImageButton) tabBtnFrd.findViewById(R.id.btn_tab_bottom_friend))
.setImageResource(R.drawable.tab_find_frd_normal);
((ImageButton) tabBtnAddress.findViewById(R.id.btn_tab_bottom_contact))
.setImageResource(R.drawable.tab_address_normal);
((ImageButton) tabBtnSettings.findViewById(R.id.btn_tab_bottom_setting))
.setImageResource(R.drawable.tab_settings_normal);
}

@Override
public void onEvent(int what, Bundle data, Object object) {
// TODO 自动生成的方法存根
mainHandler.sendEmptyMessage(what);
}
}

 
    我的这个例程是在鸿洋_大大(http://blog.csdn.net/lmj623565791/article/details/24740977)的基础上改来的,再此感谢鸿洋_大大。
 

FragmentPagerAdapter刷新fragment最完美解决方案的更多相关文章

  1. Apache服务器网站访问伪静态内页出现No input file specified.的完美解决方案

    原文地址:Apache服务器网站访问伪静态内页出现No input file specified.的完美解决方案 启用REWRITE的伪静态功能的时候,首页可以访问,而访问内页的时候,就提示:&quo ...

  2. 关于Entity Framework中的Attached报错的完美解决方案终极版

    之前发表过一篇文章题为<关于Entity Framework中的Attached报错的完美解决方案>,那篇文章确实能解决单个实体在进行更新.删除时Attached的报错,注意我这里说的单个 ...

  3. No resource found that matches the given name 'Theme.AppCompat.Light 的完美解决方案

    No resource found that matches the given name 'Theme.AppCompat.Light 的完美解决方案 首先这个问题的产生是由于缺少Theme.App ...

  4. ecshop之transport和jquery冲突之完美解决方案

    众所周知:ecshop的transport.js文件和Jquery是冲突的,两个文件不能同时调用,现给出以下完美解决方案:原因分析:在transport.js文件中,大概 580行到590行之间,这个 ...

  5. Xcode6.1标准Framework静态库制作方法。工程转Framework,静态库加xib和图片。完美解决方案。

    http://www.cocoachina.com/bbs/read.php?tid-282490.html Xcode6.1标准Framework静态库制作方法.工程转Framework,静态库加x ...

  6. Safari 前端开发调试 iOS 完美解决方案

    转http://www.2cto.com/kf/201403/283404.html afari 前端开发调试 iOS 完美解决方案 2014-03-05      0个评论    来源:Safari ...

  7. C#多线程解决界面卡死问题的完美解决方案

    C#多线程解决界面卡死问题的完美解决方案 文章转自http://www.sufeinet.com/thread-3556-1-1.html 问题描述: 当我们的界面需要在程序运行中不断更新数据时, 当 ...

  8. 完美解决方案,可排除DATASET不支持System.Nullable错误

    完美解决方案,可排除DATASET不支持System.Nullable错误 using System; using System.Collections.Generic; using System.L ...

  9. Android消息推送完美解决方案全析

    推送功能在手机应用开发中越来越重要,已经成为手机开发的必须.在Android应用开发中,由于众所周知的原因,Android消息推送我们不得不大费周折.本文就是用来和大家共同探讨一种Android消息推 ...

随机推荐

  1. git学习基础教程

    分享一个git学习基础教程 http://pan.baidu.com/s/1o6ugkGE 具体在网盘里面的内容..需要的学习可以直接下.

  2. jbpmAPI-8

    8.1. Process Instance State jBPM允许某些信息的持久性存储.本章描述了这些不同类型的持久性,以及如何配置它们.存储的信息的一个例子是运行时状态的过程.存储过程运行时状态是 ...

  3. YII框架下实现密码修改

    YII2 实现修改密码功能 主要难点: 1.密码加密 YII2对密码加密生成的结果是不同的,即用相同的初始密码在不同时间得到的加密结果不同,所以我们不能用常用的方法去验证密码是否正确(将密码加密后与数 ...

  4. 数据库比对脚本(PHP版)

    $config = [ 'hotfix' => [ 'host'=>'', 'port'=>'', 'account'=>'', 'password'=>'', 'dat ...

  5. C语言(1)--准备

    经过很长一段时间的准备,终于重新弄懂了一些C语言的问题,再次熟悉了C语言的大致应用,对此略有体会,在此以博客记录于此! 准备工作: 运行平台:Linux 编辑工具:vim (还可以使用emac,ged ...

  6. (Problem 41)Pandigital prime

    We shall say that an n-digit number is pandigital if it makes use of all the digits 1 to n exactly o ...

  7. 调不尽的内存泄漏,用不完的Valgrind

    调不尽的内存泄漏,用不完的Valgrind Valgrind 安装 1. 到www.valgrind.org下载最新版valgrind-X.X.X.tar.bz2 2. 解压安装包:tar –jxvf ...

  8. setTimeout 虚假的“异步”

    看这篇http://www.laruence.com/2009/09/23/1089.html 所以实际上 setTimeout更像是任务按照队列执行  经过setTimeout设置后任务放在了队尾 ...

  9. 导出Ext.grid.Panel到excel

    1.客户端定义,基本的想法是form提交表格头定义,数据,以json方式传输 Ext.grid.Panel.addMembers({ exportExcel:function(options){ if ...

  10. 参照openRTSP写的一个RTSP client 加了一些注解

    #include "liveMedia.hh"  #include "BasicUsageEnvironment.hh"  #include "Gro ...