[Android] On the feasibility of replacing Fragment with custom View

Forward


The use of Fragment is indispensable in today's Android development, which has many excellent features:

  • Segment complex UI
  • Toolbar can be customized
  • Has a life cycle callback
  • Lighter page switching
  • Support Backstack
  • Transactional commit
  • Use with ViewPager
  • State can be saved when Activity is rebuilt

However, Fragment also has many disadvantages:

  • It sounds very safe to update the page transactionally through FragmentManager. In actual use, we found that it was useless except for adding template code.
  • Although it supports backstack, it is not smart enough to use and error-prone
  • The life cycle is more complicated and difficult to understand than Activity
  • The state management is too complicated. The core class has FragmentManagerImplchecked 2K rows, which is difficult to understand and difficult to troubleshoot.
  • Poor scalability, for example, FragmentPagerAdapteretc.

Take FragmentPagerAdapter as an example, for example, the following code

@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()After opening a transaction in, findFragmentByTagget the Fragment, if the get fails, get it via getItem and add it toFragmentManager

Because it mCurTransactionis private, it is difficult to rewrite instantiateItem to implement your own logic

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

makeFragmentNameIt is also private and cannot be called directly.

In short, it is very difficult to extend your own implementation in FragmentPagerAdapter, and other Fragment-related classes have similar problems.


Custom View


There are many limitations to using Fragment, so is there an alternative?
Framgent is essentially a custom View with a life cycle, so using a custom View can replace the use of Fragment to a certain extent:

  • Segment complex UI; Custom Toolbar:
    Custom View naturally supports UI nesting and segmentation

  • With life cycle callback:
    Let the custom View implement the LifecycleOwner interface, so as to realize Lifecycle forwarding is now possible. Lifecycle is no longer a Fragment patent.

  • Transactional commit:
    tasteless, work without support

  • Use ViewPager with
    ViewPager to naturally support custom View

  • State
    can be saved when Activity is rebuilt: With the help of ViewModel, you can also help custom View to achieve state preservation when Activity is rebuilt

  • Support Backstack; Page switching:
    By implementing a simple Stack management, page jump and rollback can be realized, for example:

// 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();
}

to sum up


With support libraries such as Lifecycle and ViewModel, custom View can replace the common functions of Fragment, and can be expanded and customized more freely.

Guess you like

Origin blog.csdn.net/vitaviva/article/details/109268142