您的位置:首页 > 移动开发 > Android开发

Android应用ViewPager和TabLayout动态加载Fragment,并实现view和tab动态刷新。

2016-12-01 23:35 1416 查看
Android应用ViewPager和TabLayout动态加载Fragment

 

1 应用背景和目的

项目中需要实现根据服务器端返回的主题模块加载相应的主题内容,其中有三个主题模块为默认加载,该应用程序启动时手机端需加载出来,其余主题模块根据网络请求服务器端返回的主题进行加载。达到由服务器端自动配置主题,推送给手机用户动态加载相应主题内容的效果。

下图为模拟示例,其中tab0、tab1、tab2为默认主题,tab3、tab4、tab5为网络端推动过来的主题模块,并且加载插入的位置在tab0与tab1之间。



2 实现框架

Android端app利用ViewPager和TabLayout的方式实现相应主题内容Fragment的动态加载。示例程序app name为VFTest,运用这个方式,动态加载fragment之后,切换tab,会出现程序崩溃,如下图所示。



查看崩溃得logcat日志如下图所示:



崩溃得原因是Can't change tag of fragment CommonFragment{44d090b0#1 id=0x7f0c0071 android:switcher:2131492977:1}。分析知FragmentPagerAdapter为之前加载好的Fragment设置的tag,由于在原有位置插入了一个新的Fragment,导致两个tag不一致,switcher在切换时出错抛出的异常。

3 解决方案

         根据问题,拟解决方案是,当在原有位置加载新的Fragment时,重新调用FragmentPagerAdapter的instantiateItem接口,刷新adapter的中fragment。查看instantiateItem源码,

@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;
}

其中final long itemId = getItemId(position);决定是否重新加载新的Fragment,于是需要在自定的FragmentPagerAdapter中重写getItemId,得到不同的itemId,即:

@Override
public long getItemId(int position) {
    super.getItemId(position);
    if (fragments != null) {
        if (position < fragments.size()) {
            return fragments.get(position).hashCode();       //important
        }
    }
    return super.getItemId(position);
}

不同的Fragment分配的HashCode不同,从而实现刷新adapter中的fragment。

 

当然可能还遇到另一个问题,就是加载的Fragment的内容没有来得及刷新,这里在动态加载之后,还需要记录当前ViewPager的Item的位置,动态加载之后,需要跳到其对应的原有Fragment重置之后的位置,才能即时刷新Fragment内容。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息