1.用 BottomNavigationView + Navigation 加载 fragment的情况
WorkFragment (默认显示)
HomeFragment
MineFragment
1.页面加载的时候会调用当前显示的fragment(WorkFragment )的
WorkFragment onCreateView
WorkFragment onActivityCreated
WorkFragment onStart
WorkFragment onResume
2.从当前的WorkFragment 切换到 HomeFragment 时:
HomeFragment onCreateView
HomeFragment onActivityCreated
HomeFragment onStart
HomeFragment onResume
WorkFragment onPause
WorkFragment onStop
WorkFragment onDestroyView
WorkFragment onDestroy
3.重新切换回WorkFragment时:
WorkFragment onCreateView
WorkFragment onActivityCreated
WorkFragment onStart
WorkFragment onResume
HomeFragment onPause
HomeFragment onStop
HomeFragment onDestroyView
HomeFragment onDestroy
4.当前页面(MineFragment )遇到关闭屏幕或按home按键时
MineFragment onPause
MineFragment onStop
5.回到程序时
MineFragment onStart
MineFragment onResume
结论: BottomNavigationView + Navigation 情况下,页面只有一个fragment是存活状态,且会根据当前activity的状态而调用相对应的生命周期方法。
我发现这种情况下,无论怎么样,都会销毁前一个fragment里的数据,这样的话就达不到我们的要求。大家要慎用。(google建议用 viewModel保存信息,回退的时候恢复,感觉太麻烦了)
2.用 ViewPager 加载 fragment的情况
<com.xx.base.ui.viewpager.CanNoScrollViewPager
android:id="@+id/viewPager"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/nav_view"
android:layout_width="match_parent"
android:layout_height="0dp"
/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/nav_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:labelVisibilityMode="labeled"
app:menu="@menu/main_bottom_nav_menu" />
public class DefaultPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> fragmentList;
public DefaultPagerAdapter(FragmentManager fm, List<Fragment> fragmentList) {
// 这个地方是关键, 保证了只有一个fragment显示(调用onResume方法)
super(fm,BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
this.fragmentList = fragmentList;
}
/**
* 得到每个页面
*/
@Override
public Fragment getItem(int arg0) {
return (fragmentList == null || fragmentList.size() == 0) ? null
: fragmentList.get(arg0);
}
/**
* 每个页面的title
*/
@Override
public CharSequence getPageTitle(int position) {
return null;
}
/**
* 页面的总个数
*/
@Override
public int getCount() {
return fragmentList == null ? 0 : fragmentList.size();
}
}
private fun initViewPager() {
viewPager.setNoScroll(false)
viewPager.offscreenPageLimit = fragmentList.size
viewPager.adapter = DefaultPagerAdapter(manager, fragmentList.toList())
}
private fun initNavigation() {
val states = Array(2) { IntArray(1) }
states[0][0] = -android.R.attr.state_checked
states[1][0] = android.R.attr.state_checked
val colors = IntArray(2)
colors[0] = ContextCompat.getColor(this, R.color.app_main_bottom_btn_default)
colors[1] = ContextCompat.getColor(this, R.color.app_main_bottom_btn_select)
val csl = ColorStateList(states, colors)
navView.itemTextColor = csl
navView.itemIconTintList = csl
navView.setOnNavigationItemReselectedListener { item ->
when (item.itemId) {
R.id.main_bottom_message -> {
//消息
viewPager.currentItem = 1
return@setOnNavigationItemReselectedListener
}
R.id.main_bottom_work -> {
//工作台
viewPager.currentItem = 0
return@setOnNavigationItemReselectedListener
}
R.id.main_bottom_action -> {
//应用
viewPager.currentItem = 2
return@setOnNavigationItemReselectedListener
}
R.id.main_bottom_mine -> {
//我的
viewPager.currentItem = 3
return@setOnNavigationItemReselectedListener
}
}
}
}
在这种模式下,我们假设只有当前的fragment才会调用 onResume方法,按照这个想法,我们定制一下 BaseFragment。(为什么是onResume而不是onStart呢,看到最后会告诉你的)
public abstract class BaseFragment extends Fragment {
private String tag;
protected View view = null;
protected Context baseContext = null;
protected int resId = 0;
protected BaseFragment(){
}
protected BaseFragment(@LayoutRes int resId){
this.resId = resId;
}
// 方便集成的子类传入 tag进行调试
protected BaseFragment(String tag){
this.tag = tag;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
baseContext = context;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
if (args != null) {
hasBundle(args);
}
}
protected void hasBundle(Bundle args){
}
public int getFragmentViewRes(){return 0;}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.i(tag,tag + " onCreateView");
if(null == view){
if(resId == 0){
resId = getFragmentViewRes();
}
view = inflater.inflate(resId,container,false);
isCreateView = true;
}
return view;
}
// 是否已经生成了View
protected boolean isCreateView;
protected boolean isFirstShow;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.i(tag,tag + " onActivityCreated");
initCreateView();
}
protected synchronized void initCreateView() {
}
protected void onShow(){}
protected void onHide(){}
// 第一次显示时初始化 view
protected abstract void firstInitViews(View view);
// 第一次显示
protected abstract void onFirstUserVisible();
// 第二次显示
protected abstract void onUserVisible();
protected abstract void onUserInvisible();
@Override
public void onStart() {
Log.i(tag,tag + " onStart");
super.onStart();
}
@Override
public void onResume() {
super.onResume();
Log.i(tag,tag + " onResume");
if(!isFirstShow && isCreateView){
isFirstShow = true;
Log.i(tag,tag + " firstInitViews");
firstInitViews(view);
Log.i(tag,tag + " onFirstUserVisible");
onFirstUserVisible();
}else{
Log.i(tag,tag + " onUserVisible");
onUserVisible();
}
Log.i(tag,tag + " onShow");
onShow();
}
@Override
public void onPause() {
super.onPause();
Log.i(tag,tag + " onPause");
Log.i(tag,tag + " onUserInvisible");
onUserInvisible();
Log.i(tag,tag + " onHide");
onHide();
}
@Override
public void onDestroyView() {
Log.i(tag,tag + " onDestroyView");
Log.i(tag,tag + " DetoryViewAndThing");
DetoryViewAndThing();
super.onDestroyView();
}
protected abstract void DetoryViewAndThing();
}
WorkFragment (默认显示)
MessageFragment
ActionFragment
MineFragment
都继承了 BaseFragment
1.页面加载的时候会调用当前显示的fragment(WorkFragment )的
WorkFragment onCreateView
WorkFragment onActivityCreated
WorkFragment onStart
MessageFragment onCreateView
MessageFragment: MessageFragment onActivityCreated
MessageFragment: MessageFragment onStart
ActionFragment onCreateView
ActionFragment onActivityCreated
ActionFragment onStart
MineFragment onCreateView
MineFragment onActivityCreated
MineFragment onStart
WorkFragment onResume
WorkFragment firstInitViews
WorkFragment onFirstUserVisible
WorkFragment onShow
(符合我们的假设)
2.从当前的WorkFragment 切换到 MessageFragment 时:
WorkFragment onPause
WorkFragment onUserInvisible
WorkFragment onHide
MessageFragment onResume
MessageFragment firstInitViews
MessageFragment onFirstUserVisible
MessageFragment onShow
(符合我们的假设)
3.重新切换回WorkFragment时:
MessageFragment onPause
MessageFragment onUserInvisible
MessageFragment onHide
WorkFragment onResume
WorkFragment onUserVisible
WorkFragment onShow
(符合我们的假设)
4.当前页面(WorkFragment)遇到关闭屏幕或按home按键时
WorkFragment onPause
WorkFragment onUserInvisible
WorkFragment onHide
5.回到程序时
WorkFragment onStart
MessageFragment onStart
ActionFragment onStart
MineFragment onStart
WorkFragment onResume
WorkFragment onUserVisible
WorkFragment onShow
发现什么了没有,重新回到程序的时候,所有的fragment都会调用 onStart方法,而只有当前显示的fragment才会调用 onResume以及其他方法。所以我们的判断一定要放在 onResume里。
这个模式下,BaseFragment完全可以满足我们懒加载的需求了。(当然还可以在onResume中加入停留时间判断,这样会更清晰更准确实现懒加载)