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. MATLAB - 为什么imshow(g,[])可以正常显示,而imshow(g)却显示空白图像?

    Q:为什么imshow(g,[])可以正常显示,而imshow(g)却显示空白图像? A:数据类型如果是double,imshow的处理范围是0-1数据类型如果是uint8,imshow的处理范围是0 ...

  2. Visual format language

    所谓的VFL语言其实就是Visual format language 的缩写,是一种使用代码添加约束的方式,类似于Masonry  SDAutolayout的效果,但是操作起来可能要相对简单.一行代码 ...

  3. 五毛的cocos2d-x学习笔记06-处理用户交互

    前几篇感觉自己在写教育文章,╮(╯▽╰)╭.今天换成开发者的口吻,毕竟我也是在边学边写博客. 处理用户交互包括:单点触摸.多点触摸.事件传递.传感器.物理按键等部分. 单点触摸: 触摸事件传递顺序 o ...

  4. bzoj 1007 : [HNOI2008]水平可见直线 计算几何

    题目链接 给出n条直线, 问从y轴上方向下看, 能看到哪些直线, 输出这些直线的编号. 首先我们按斜率排序, 然后依次加入一个栈里面, 如果刚加入的直线, 和之前的那条直线斜率相等, 那么显然之前的会 ...

  5. codeforces 609E. Minimum spanning tree for each edge 树链剖分

    题目链接 给一个n个节点m条边的树, 每条边有权值, 输出m个数, 每个数代表包含这条边的最小生成树的值. 先将最小生成树求出来, 把树边都标记. 然后对标记的边的两个端点, 我们add(u, v), ...

  6. nrf51 SDK自带例程的解读

    简单的pwm电机控制示例 simple_pwm_motor_control_example 其实就是pwm控制led的亮度 1.首先设置gpiote 设置初始为高电平2.接着设置ppi 定时器time ...

  7. mybatis一对一关联表查询

    先创建一个表 CREATE TABLE teacher( t_id INT PRIMARY KEY AUTO_INCREMENT, t_name ) ); CREATE TABLE class( c_ ...

  8. 我被SQL注入撞了一下腰

    网站的注入漏洞,应该说绝大多数做web开发的人都知道的事情.可是没想到从事6,7年开发工作的我,却会在这上栽了跟头,真是郁闷啊.心情很纠结,按照老婆的话,怎么感觉我像失恋了一样. 事情的起因还是在几个 ...

  9. RFID标签天线的三种制作方法

    在RFID标签中,天线层是主要的功能层,其目标是传输最大的能量进出标签芯片.RFID天线是按照射频识别所要求的功能而设计的电子线路,将导电银浆或导电碳浆网印在PVC.PC或PET上,再与面层.保护层和 ...

  10. 如何使用 Barracuda 防火墙设置/保护 Azure 应用程序

     如果某企业在 Windows Azure 上托管某个应用程序,该应用程序会在某个特定时间暴露到 Internet,以用于商业用途.公共 Internet 带来 客户的同时也带来了攻击者. Tim ...