拉项目--球球世道的总结-解决了viewpager+fragment+tablayout 两个bug
Posted 童政通
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了拉项目--球球世道的总结-解决了viewpager+fragment+tablayout 两个bug相关的知识,希望对你有一定的参考价值。
一:立项
1,创新新的项目
2,引入module (这些都是我自己项目整的)
-----fragmentation
-----fragmentation_swipeback
-----uibase
注意:所有的module的gradle文件引用的三方库文件必须和---主---项目的版本一只(重要哦)
注意:除了四个主界面的额fragmentation extends BaseLazyMainFragment
其他子fragment的 extends BaseBackFragment
二:遇到的问题
TabLayout+ViewPager+Fragment 实现效果
问题一:
1) ViewPager预加载问题,所有我们需要懒加载解决
第一步:封装一个BaseFragment
第二步:子Fragment集成BaseFragment
第三步:子Frament中使用
package com.yun.yunball.base;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.View;
/**
* Created by Lovelin on 2019/3/15
* <p>
* Describe: 解决预加载问题----懒加载
*/
public abstract class BaseFragment extends Fragment
private static final String TAG = BaseFragment.class.getSimpleName();
private boolean isFragmentVisible;
private boolean isReuseView;
private boolean isFirstVisible;
private View rootView;
//setUserVisibleHint()在Fragment创建时会先被调用一次,传入isVisibleToUser = false
//如果当前Fragment可见,那么setUserVisibleHint()会再次被调用一次,传入isVisibleToUser = true
//如果Fragment从可见->不可见,那么setUserVisibleHint()也会被调用,传入isVisibleToUser = false
//总结:setUserVisibleHint()除了Fragment的可见状态发生变化时会被回调外,在new Fragment()时也会被回调
//如果我们需要在 Fragment 可见与不可见时干点事,用这个的话就会有多余的回调了,那么就需要重新封装一个
@Override
public void setUserVisibleHint(boolean isVisibleToUser)
super.setUserVisibleHint(isVisibleToUser);
//setUserVisibleHint()有可能在fragment的生命周期外被调用
if (rootView == null)
return;
if (isFirstVisible && isVisibleToUser)
onFragmentFirstVisible();
isFirstVisible = false;
if (isVisibleToUser)
onFragmentVisibleChange(true);
isFragmentVisible = true;
return;
if (isFragmentVisible)
isFragmentVisible = false;
onFragmentVisibleChange(false);
@Override
public void onCreate(@Nullable Bundle savedInstanceState)
super.onCreate(savedInstanceState);
initVariable();
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState)
//如果setUserVisibleHint()在rootView创建前调用时,那么
//就等到rootView创建完后才回调onFragmentVisibleChange(true)
//保证onFragmentVisibleChange()的回调发生在rootView创建完成之后,以便支持ui操作
if (rootView == null)
rootView = view;
if (getUserVisibleHint())
if (isFirstVisible)
onFragmentFirstVisible();
isFirstVisible = false;
onFragmentVisibleChange(true);
isFragmentVisible = true;
super.onViewCreated(isReuseView ? rootView : view, savedInstanceState);
@Override
public void onDestroyView()
super.onDestroyView();
@Override
public void onDestroy()
super.onDestroy();
initVariable();
private void initVariable()
isFirstVisible = true;
isFragmentVisible = false;
rootView = null;
isReuseView = true;
/**
* 设置是否使用 view 的复用,默认开启
* view 的复用是指,ViewPager 在销毁和重建 Fragment 时会不断调用 onCreateView() -> onDestroyView()
* 之间的生命函数,这样可能会出现重复创建 view 的情况,导致界面上显示多个相同的 Fragment
* view 的复用其实就是指保存第一次创建的 view,后面再 onCreateView() 时直接返回第一次创建的 view
*
* @param isReuse
*/
protected void reuseView(boolean isReuse)
isReuseView = isReuse;
/**
* 去除setUserVisibleHint()多余的回调场景,保证只有当fragment可见状态发生变化时才回调
* 回调时机在view创建完后,所以支持ui操作,解决在setUserVisibleHint()里进行ui操作有可能报null异常的问题
*
* 可在该回调方法里进行一些ui显示与隐藏,比如加载框的显示和隐藏
*
* @param isVisible true 不可见 -> 可见
* false 可见 -> 不可见
*/
protected void onFragmentVisibleChange(boolean isVisible)
/**
* 在fragment首次可见时回调,可在这里进行加载数据,保证只在第一次打开Fragment时才会加载数据,
* 这样就可以防止每次进入都重复加载数据
* 该方法会在 onFragmentVisibleChange() 之前调用,所以第一次打开时,可以用一个全局变量表示数据下载状态,
* 然后在该方法内将状态设置为下载状态,接着去执行下载的任务
* 最后在 onFragmentVisibleChange() 里根据数据下载状态来控制下载进度ui控件的显示与隐藏
*/
protected void onFragmentFirstVisible()
protected boolean isFragmentVisible()
return isFragmentVisible;
package com.yun.yunball.base;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.View;
/**
* Created by Lovelin on 2019/3/15
* <p>
* Describe: 解决预加载问题----懒加载
*/
public abstract class BaseFragment extends Fragment
private static final String TAG = BaseFragment.class.getSimpleName();
private boolean isFragmentVisible;
private boolean isReuseView;
private boolean isFirstVisible;
private View rootView;
//setUserVisibleHint()在Fragment创建时会先被调用一次,传入isVisibleToUser = false
//如果当前Fragment可见,那么setUserVisibleHint()会再次被调用一次,传入isVisibleToUser = true
//如果Fragment从可见->不可见,那么setUserVisibleHint()也会被调用,传入isVisibleToUser = false
//总结:setUserVisibleHint()除了Fragment的可见状态发生变化时会被回调外,在new Fragment()时也会被回调
//如果我们需要在 Fragment 可见与不可见时干点事,用这个的话就会有多余的回调了,那么就需要重新封装一个
@Override
public void setUserVisibleHint(boolean isVisibleToUser)
super.setUserVisibleHint(isVisibleToUser);
//setUserVisibleHint()有可能在fragment的生命周期外被调用
if (rootView == null)
return;
if (isFirstVisible && isVisibleToUser)
onFragmentFirstVisible();
isFirstVisible = false;
if (isVisibleToUser)
onFragmentVisibleChange(true);
isFragmentVisible = true;
return;
if (isFragmentVisible)
isFragmentVisible = false;
onFragmentVisibleChange(false);
@Override
public void onCreate(@Nullable Bundle savedInstanceState)
super.onCreate(savedInstanceState);
initVariable();
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState)
//如果setUserVisibleHint()在rootView创建前调用时,那么
//就等到rootView创建完后才回调onFragmentVisibleChange(true)
//保证onFragmentVisibleChange()的回调发生在rootView创建完成之后,以便支持ui操作
if (rootView == null)
rootView = view;
if (getUserVisibleHint())
if (isFirstVisible)
onFragmentFirstVisible();
isFirstVisible = false;
onFragmentVisibleChange(true);
isFragmentVisible = true;
super.onViewCreated(isReuseView ? rootView : view, savedInstanceState);
@Override
public void onDestroyView()
super.onDestroyView();
@Override
public void onDestroy()
super.onDestroy();
initVariable();
private void initVariable()
isFirstVisible = true;
isFragmentVisible = false;
rootView = null;
isReuseView = true;
/**
* 设置是否使用 view 的复用,默认开启
* view 的复用是指,ViewPager 在销毁和重建 Fragment 时会不断调用 onCreateView() -> onDestroyView()
* 之间的生命函数,这样可能会出现重复创建 view 的情况,导致界面上显示多个相同的 Fragment
* view 的复用其实就是指保存第一次创建的 view,后面再 onCreateView() 时直接返回第一次创建的 view
*
* @param isReuse
*/
protected void reuseView(boolean isReuse)
isReuseView = isReuse;
/**
* 去除setUserVisibleHint()多余的回调场景,保证只有当fragment可见状态发生变化时才回调
* 回调时机在view创建完后,所以支持ui操作,解决在setUserVisibleHint()里进行ui操作有可能报null异常的问题
*
* 可在该回调方法里进行一些ui显示与隐藏,比如加载框的显示和隐藏
*
* @param isVisible true 不可见 -> 可见
* false 可见 -> 不可见
*/
protected void onFragmentVisibleChange(boolean isVisible)
/**
* 在fragment首次可见时回调,可在这里进行加载数据,保证只在第一次打开Fragment时才会加载数据,
* 这样就可以防止每次进入都重复加载数据
* 该方法会在 onFragmentVisibleChange() 之前调用,所以第一次打开时,可以用一个全局变量表示数据下载状态,
* 然后在该方法内将状态设置为下载状态,接着去执行下载的任务
* 最后在 onFragmentVisibleChange() 里根据数据下载状态来控制下载进度ui控件的显示与隐藏
*/
protected void onFragmentFirstVisible()
protected boolean isFragmentVisible()
return isFragmentVisible;
package com.yun.yunball.base;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.View;
/**
* Created by Lovelin on 2019/3/15
* <p>
* Describe: 解决预加载问题----懒加载
*/
public abstract class BaseFragment extends Fragment
private static final String TAG = BaseFragment.class.getSimpleName();
private boolean isFragmentVisible;
private boolean isReuseView;
private boolean isFirstVisible;
private View rootView;
//setUserVisibleHint()在Fragment创建时会先被调用一次,传入isVisibleToUser = false
//如果当前Fragment可见,那么setUserVisibleHint()会再次被调用一次,传入isVisibleToUser = true
//如果Fragment从可见->不可见,那么setUserVisibleHint()也会被调用,传入isVisibleToUser = false
//总结:setUserVisibleHint()除了Fragment的可见状态发生变化时会被回调外,在new Fragment()时也会被回调
//如果我们需要在 Fragment 可见与不可见时干点事,用这个的话就会有多余的回调了,那么就需要重新封装一个
@Override
public void setUserVisibleHint(boolean isVisibleToUser)
super.setUserVisibleHint(isVisibleToUser);
//setUserVisibleHint()有可能在fragment的生命周期外被调用
if (rootView == null)
return;
if (isFirstVisible && isVisibleToUser)
onFragmentFirstVisible();
isFirstVisible = false;
if (isVisibleToUser)
onFragmentVisibleChange(true);
isFragmentVisible = true;
return;
if (isFragmentVisible)
isFragmentVisible = false;
onFragmentVisibleChange(false);
@Override
public void onCreate(@Nullable Bundle savedInstanceState)
super.onCreate(savedInstanceState);
initVariable();
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState)
//如果setUserVisibleHint()在rootView创建前调用时,那么
//就等到rootView创建完后才回调onFragmentVisibleChange(true)
//保证onFragmentVisibleChange()的回调发生在rootView创建完成之后,以便支持ui操作
if (rootView == null)
rootView = view;
if (getUserVisibleHint())
if (isFirstVisible)
onFragmentFirstVisible();
isFirstVisible = false;
onFragmentVisibleChange(true);
isFragmentVisible = true;
super.onViewCreated(isReuseView ? rootView : view, savedInstanceState);
@Override
public void onDestroyView()
super.onDestroyView();
@Override
public void onDestroy()
super.onDestroy();
initVariable();
private void initVariable()
isFirstVisible = true;
isFragmentVisible = false;
rootView = null;
isReuseView = true;
/**
* 设置是否使用 view 的复用,默认开启
* view 的复用是指,ViewPager 在销毁和重建 Fragment 时会不断调用 onCreateView() -> onDestroyView()
* 之间的生命函数,这样可能会出现重复创建 view 的情况,导致界面上显示多个相同的 Fragment
* view 的复用其实就是指保存第一次创建的 view,后面再 onCreateView() 时直接返回第一次创建的 view
*
* @param isReuse
*/
protected void reuseView(boolean isReuse)
isReuseView = isReuse;
/**
* 去除setUserVisibleHint()多余的回调场景,保证只有当fragment可见状态发生变化时才回调
* 回调时机在view创建完后,所以支持ui操作,解决在setUserVisibleHint()里进行ui操作有可能报null异常的问题
*
* 可在该回调方法里进行一些ui显示与隐藏,比如加载框的显示和隐藏
*
* @param isVisible true 不可见 -> 可见
* false 可见 -> 不可见
*/
protected void onFragmentVisibleChange(boolean isVisible)
/**
* 在fragment首次可见时回调,可在这里进行加载数据,保证只在第一次打开Fragment时才会加载数据,
* 这样就可以防止每次进入都重复加载数据
* 该方法会在 onFragmentVisibleChange() 之前调用,所以第一次打开时,可以用一个全局变量表示数据下载状态,
* 然后在该方法内将状态设置为下载状态,接着去执行下载的任务
* 最后在 onFragmentVisibleChange() 里根据数据下载状态来控制下载进度ui控件的显示与隐藏
*/
protected void onFragmentFirstVisible()
protected boolean isFragmentVisible()
return isFragmentVisible;
子类使用
/ 取消预加载的回调
@Override
protected void onFragmentVisibleChange(boolean isVisible)
Log.e("TEXT", "01--足球--isVisible====" + isVisible);
if (isVisible)
responseListener();
@Override
protected void onFragmentFirstVisible()
Log.e("TEXT", "01--足球--===onFragmentFirstVisible=");
responseListener();
问题二:TabLayout 间隔tab点击 数据不刷新问题
使用EventBus3解决即可
第一步:在tablayout的addOnTabSelectedListener监听中的
onTabSelected中(事先注册FootBallTabEvent)
EventBus.getDefault().post(new FootBallTabEvent(tab.getPosition())); //数据更新
第二步:在需要刷新的---子Fragment中的onCreate和onDestroy中注册和销毁再注册监听---搞定
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(FootBallTabEvent event)
Log.e("TEXT", "01--篮球--===onMessageEvent=======onMessageEvent==");
if (0== event.getType())
Log.e("TEXT", "01--篮球--===onMessageEvent=======走进来了==");
responseListener();
问题三:如图---足球---篮球--下分别是两组tablayout+viewpager+fragment,嵌套的时候会出现点击--篮球--或者足球,tab数据不刷新问题,还有不在第一个子fragment的时候点击篮球足球数据也不刷新问题
解决方法:
我们在足球和篮球的点击事件上,每次去new Adapter,然后重新设置或者请求数据,代码如下
private void showBasketballViewPager()
//每次new出来 解决数据不显示问题
mBasketBallAdapter = new BasketBallAdapter(getChildFragmentManager(), tabBasketball);
mFootTabLayout.setVisibility(View.GONE);
mFootBallViewPager.setVisibility(View.GONE);
mBasketTabLayout.setVisibility(View.VISIBLE);
mBasketBallViewPager.setVisibility(View.VISIBLE);
mBasketBallViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(mBasketTabLayout));
mBasketBallViewPager.setAdapter(mBasketBallAdapter);
mBasketTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener()
@Override
public void onTabSelected(TabLayout.Tab tab)
mBasketBallViewPager.setCurrentItem(tab.getPosition());
EventBus.getDefault().post(new FootBallTabEvent(tab.getPosition())); //数据更新
Log.e("TEXT", "篮球===tab===Position=====" + tab.getPosition());
@Override
public void onTabUnselected(TabLayout.Tab tab)
@Override
public void onTabReselected(TabLayout.Tab tab)
);
以上是关于拉项目--球球世道的总结-解决了viewpager+fragment+tablayout 两个bug的主要内容,如果未能解决你的问题,请参考以下文章