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

来源:互联网 发布:勒索病毒源码 编辑:程序博客网 时间:2024/05/29 18:04

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源码,
@Overridepublic 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,即:
@Overridepublic 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内容。

0 0
原创粉丝点击