【Android】论自定义View替代Fragment的可行性

Framgent


当今的Android开发都少不了对Fragment的使用,其具有很多优秀特性:

  • 分割复杂的UI
  • 可以自定义Toolbar
  • 具有生命周期回调
  • 更轻量的页面切换
  • 支持Backstack
  • 事务性提交
  • 配合ViewPager使用
  • 可在Activity重建时保存状态

但是,Fragment同样有很多缺点:

  • 通过FragmentManager事务性的更新页面听起来非常安全,实际使用我们发现除了徒增模板代码外没什么用
  • 虽然支持backstack,但是使用起来不够智能且容易出错
  • 生命周期相对于Activity更加复杂和难以理解
  • 状态管理过于复杂,核心类FragmentManagerImpl查过2K行,难以理解不易,发生问题不易排查
  • 扩展性差,例如FragmentPagerAdapter等。

以FragmentPagerAdapter为例,例如如下代码

@Override
public Object instantiateItem(View container, int position) {
    
    
  if (mCurTransaction == null) {
    
    
    mCurTransaction = mFragmentManager.beginTransaction();
  }

  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));
  }
  if (fragment != mCurrentPrimaryItem) {
    
    
      fragment.setMenuVisibility(false);
  }

  return fragment;
}

instantiateItem() 中开启一个事务后通过findFragmentByTag获取Fragment,如果获取失败,则通过getItem获取并添加到FragmentManager

由于mCurTransactionprivate的,所以难以重写instantiateItem实现自己的逻辑

private static String makeFragmentName(int viewId, int index) {
    
    
    return "android:switcher:" + viewId + ":" + index;
}

makeFragmentName也是private的无法直接调用。

总之想要在FragmentPagerAdapter中扩展自己的实现非常困难,其他Fragment相关的类也都有类似问题。


自定义View


使用Fragment有诸多限制,那么有没有替代方案呢?
Framgent实质就是带有生命周期的自定义View,所以使用自定义View可以在一定程度上替代Fragment的使用:

  • 分割复杂的UI;自定义Toolbar:
    自定义View天然支持UI的嵌套与分割

  • 具有生命周期回调:
    让自定义View实现LifecycleOwner接口,从而实现Lifecycle转发现在已经成为可能,Lifecycle已经并非Fragment的专利。

  • 事务性提交:
    鸡肋,不支持也能work

  • 配合ViewPager使用
    ViewPager天然支持自定义View

  • 可在Activity重建时保存状态:
    借助ViewModel也可以帮助自定义View实现Activity重建时的状态保存

  • 支持Backstack;页面切换:
    通过实现一个简单的Stack管理,完全可以实现页面的跳转与回退,例如:

// Simple stack implementation, works as expected every time
private Stack<NavItem> navigationStack = new Stack<>();

// ...

// Navigating to a new screen/item in the stack 
navigationStack.push(new NavItem(viewToBeAdded.getClass(), args));

// ...

// Navigating back using the stack
if (navigationStack.size() > 1) {
    
    
  navigationStack.pop();
  NavItem navItem = navigationStack.peek();
  CustomView customView = (CustomView) navItem.viewClass.getConstructor(Context.class).newInstance(this);
  container.removeAllViews();
  customView.setArgs(navItem.args);
  container.addView(customView);
} else {
    
    
  super.onBackPressed();
}

总结


借助Lifecycle以及ViewModel等Support库,自定义View可以替代Fragment的常用功能,并且可以更自由的扩展和定制。

猜你喜欢

转载自blog.csdn.net/vitaviva/article/details/109268142
今日推荐