In fact, I made an open source project (^__^), take it out for everyone to appreciate, welcome your comments project: github.com/xuyt11/andr… Welcome to star. Function: a tool to control the rollback of Android views (Activities and Fragments). Tip: This is a rollback tool, not a jump tool

Today’s development students should have a lot of experience on the needs of the product, that is, a good business process, after many editions, from the tree to the network, even if it is written by yourself, as long as a long time has passed, also need to carefully read the code, to carefully modify again.

The pain point right now

The rollback function of business processes:

  • You need to finish ahead of time or finish several pages.
  • When making logical decisions, set state values and finish multiple pages with setResult. .

Various multi-view fallbacks create complex view jump logic. This results in stateful judgment logic for multiple views during the rollback process. So, having a tool that allows us to go back to the target view when we need to would reduce the complexity of our code and speed up our development.

solution

  1. We mainly use startActivityForResult, onActivityResult, setResult and Finish (Activity) to implement the original rollback view function.
    • So, if we call the startActivityForResult method every time instead of startActivity, we can use onActivityResult, setResult, and Finish (Activity), Let’s do the chained view rollback!
  2. How to fall back to the specified activity or fragment!

    We know the class types of activities and fragments that are being rolled back, so as long as we can determine the current activity and the fragments managed in it from the onActivityResult method of the activity, You can stop executing the Finish method on the specified view so that the specified view is displayed
    • Activity judgment:
      • In the Activity onActivityResult method, we can determine the Class type of the current Activity;
    • Fragment in an activity
      • In the Activity’s onActivityResult method, we can pass the getSupportFragmentManager () getFragments () method, fragments could access to management, To determine the fragment’s Class type;
    • Fragments in fragments
      • These fragments can also be retrieved using the getChildFragmentManager().getFragments() method.
  3. In a fixed sequence of business processes, I want to follow the position on the activity interface to perform the rollback. In a fixed order business process, each activity has a fixed position, so just by calculating the difference of position (backActivityCount), we can use the onActivityResult method, BackActivityCount (backActivityCount).

How to exit App gracefully? Exit the App so gracefully!

BackFlow.finishTask(activity | fragment)
Copy the code

There are limits, of course. The man. Just exit the current task!

Here’s a closer look at androidBackFlow

Introduction to the

  1. This is a tool for chain-back multi-layer views.
  2. This is a tool for use in the single Task && Single Process environment.
  3. If the app has more than one task or process, it can only be used in the task or process and cannot exceed the scope of any one of them.
  4. Task to task, task to process, and rollback between processes need to be controlled by yourself or the system.
  5. BackFlow is disabled if the onActivityResult method is consumed in a task. (#backflow can’t be used or can’t backflow back to target position)

Quick to use

  1. Before use:
    • Inherit all activities and Fragments in App from two base classes (BaseBackFlowActivity and BaseBackFlowFragment)
    • Or extend the base class of app from two base classes (BaseBackFlowActivity and BaseBackFlowFragment)
    • Or on the basis of their class @ override startActivity and onActivityResult, and add startActivity4NonBackFlow method;
  2. End the task to which the activity belongs:
    • If the App is a single task, finish all activities in the App.
    • If the target is not matched throughout the rollback process, it is equivalent to the finish_task function.
    • If an onActivityResult method is consumed in the middle, it stays on the last activity consumed (because setResult is invalid).
    • code
    BackFlow.finishTask(activity | fragment)
    
    or
    
    BackFlow.build(BackFlowType.finish_task, activity | fragment).create().request()
    Copy the code
    • The effect

  3. Returns to the specified activity (back to the specified activity). If there are multiple activity instances, only the first match is returned.
    • code
    BackFlow.request(activity | fragment, @NonNull Class<? extends Activity> atyClass) or BackFlow.build(BackFlowType.back_to_activity, activity | fragment).... create().request()Copy the code
  4. Return to the specified fragment column (returning to the first activity matching the fragment order will call the onActivityResult of the last fragment in fragments)
    • code
    BackFlow.request(activity | fragment, @NonNull Class<? extends Fragment>... fragmentClazzs) or BackFlow.build(BackFlowType.back_to_fragments, activity | fragment).... create().request()Copy the code
    • The effect

  5. Return to the activity with the same fragment column as the activity in the fragment order. OnActivityResult of the last fragment in fragments is called.)
    • code
    BackFlow.request(activity | fragment, @NonNull Class<? extends Activity> atyClass, @NonNull Class<? extends Fragment>... fragmentClazzs) or BackFlow.build(BackFlowType.back_to_activity_fragments, activity | fragment).... create().request()Copy the code
    • The effect

  6. The number of backActivityCount activities is rolled back
    • code
    BackFlow.request(activity | fragment, backActivityCount) or BackFlow.build(BackFlowType.back_activity_count, activity | fragment).setBackActivityCount(...) .create().request()Copy the code
  7. If you have additional arguments, you can use the Request method with the Bundle argument
    • Passing extra parameters
    BackFlow.request(activity | fragment, @NonNull Bundle extra, @NonNull Class<? extends Activity> atyClass)
    Copy the code
    • Determines whether there are additional arguments
    BackFlow.hasExtra(Intent data)
    Copy the code
    • Get additional parameters
    BackFlow.getExtra(Intent data)
    Copy the code
  8. You can also use Builder to build BackFlow request
    • code
    BackFlow.builder(BackFlowType.back_to_fragments, activity | fragment).... create().request()Copy the code

tip

  • The Sub FragmentManager for fragments must be getChildFragmentManager
  • Fragments within the BackFlow support – in v4, if the app is not used in the android. Support. The v4. App. Fragments, you can replace it with your own type of fragments
  • If you have multiple fragments inside the base type (android. Support. The v4. App. Fragments, android. The app. The fragments), that you need to be unified
  • If the jump target View is a Fragment, the ParentFragment of that Fragment will not call the onActivityResult method

Internal implementation

  1. Use startActivityForResult, onActivityResult, setResult and Finish (activity)4 four methods, to achieve;
  2. You need two base classes: BaseBackFlowActivity and BaseBackFlowFragment. All activities and Fragments need to inherit from them.
  3. The startActivity method of the BaseBackFlowActivity and BaseBackFlowFragment classes in @Override App is required.
    • The startActivityForResult method is called in the internal implementation so that the BackFlow operation can be successively chained back.
    @Override
    public void startActivity(Intent intent) {
       startActivityForResult(intent, BackFlow.REQUEST_CODE);
    }
    Copy the code
  4. Override onActivityResult(requestCode, resultCode, data); Backflow. handle(this, resultCode, data) is called internally to manage the rollback operation, and the onActivityResult method is called after the end of the target position.
    • Tip: You do not need @Override BaseBackFlowFragment
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
       if (BackFlow.handle(this, getSupportFragmentManager().getFragments(), requestCode, resultCode, data)) {
           return;
       }
       super.onActivityResult(requestCode, resultCode, data);
    }
    Copy the code
  5. Call the BackFlow method to perform the rollback.
    • The BackFlow operation internally calls the setResult and Finish (Activity) methods, which are used to chain back.
    static void request(@NonNull Activity activity, @NonNull Intent backFlowData) {
        activity.setResult(RESULT_CODE, backFlowData);
        activity.finish();
    }
    Copy the code
    • For example, exit the task to which the current activity belongs (finish all activities in that task).
      • # BackFlow can’t be used or BackFlow can’t be backflowed to target position.
    BackFlow.finishTask(activity | fragment)
    Copy the code

Introduction of code

  1. Main function: BackFlowType
    • There are five categories: error, finish_task, back_to_activity, back_to_fragments, and back_to_activity_fragments
      • finish_task
        • Finish all activities in the App if the App is a single task.
        • If the target is not matched throughout the rollback process, it is equivalent to the finish_task function.
        • If an onActivityResult method is consumed in the middle, it stays on the last activity consumed (because setResult is invalid).
      • back_to_activity
        • Returns to the specified activity (back to the specified activity). If there are multiple activity instances, only the first match is returned.
      • back_to_fragments
        • Return to the specified fragment column (back to the first activity matching the fragment order)
      • back_to_activity_fragments
        • Return to the same activity as the fragment column (back to the activity containing the fragment sequence)
      • back_activity_count
        • The number of backActivityCount activities is rolled back
        • Applicable to business processes in a fixed order, each activity interface can have a fixed position
        • BackActivityCount Is the difference between two activity positions
      • Error: indicates an exception
        • Data. getIntExtra(BACK_FLOW_TYPE, ERROR_BACK_FLOW_TYPE) in the onActivityResult method parameter data, which is returned by the exception type and directly throws an exception.
  2. Call class: BackFlow
    • BackFlowType class request execution and processing wrapper, easy to use
    • The default RESULT_CODE value is set (integer.max_value);
      • This is the core structure of the rollback function, so the resultCode of other business operations cannot be the same, otherwise there will be errors.
    • The default REQUEST_CODE value is set (0x0000FFFF);
      • Called when the Override startActivity method fails to trigger the onActivityResult method
      • Other RequestCodes cannot be the same as this one; otherwise, an exception may occur in the internal business logic of the App
      • tip: Can only use lower 16 bits for requestCode
    • Request Back flow: method group for performing BackFlow operations
    • Builder Request Param and Get Extra: Builder BackFlow operates with BackFlow for extra data
    • Handle back flow: Checks and processes BackFlow operations
    • back flow log
      • Print Intent data
      • Provides an external log interface
      • You can use “BackFlow–>” to filter logs and view data flows in BackFlow
      • You can also set a unified log switch to enable or disable BackFlow logs
  3. Base classes: BaseBackFlowActivity and BaseBackFlowFragment
    • All activities and fragments need to inherit from them;
    • Or implement the functionality of two classes:
      • Override the startActivity(Intent) method of both classes, and call the startActivityForResult(Intent, requestCode) method in the internal implementation, so that the BackFlow operation can be serial BackFlow;
      startActivityForResult(intent, BackFlow.REQUEST_CODE);
      Copy the code
      • Override BaseBackFlowActivity onActivityResult(requestCode, resultCode, data) method
        • And in internal call BackFlow. Handle (this, getSupportFragmentManager () getFragments (), requestCode, the resultCode, data) for the management of the fallback,
        • And continue calling backflow. request(Activity, data) at the destination.
  4. BackFlow parameter class: BackFlowParam
    • Parameter class that performs the BackFlow operation. There are six parameters
      • BackFlowType Type: indicates the BackFlow type. There are five types of BackFlow. Error type cannot be used
      • The Activity and backFlowData (Intent) :
        • These two parameters are required when BackFlow is executed
        public void request() {
            BackFlow.request(activity, backFlowData);
        }
        Copy the code
        • Activity: Required when BackFlow is executed
        static void request(@NonNull Activity activity, @NonNull Intent backFlowData) {
            activity.setResult(RESULT_CODE, backFlowData);
            activity.finish();
        }
        Copy the code
        • BackFlowData (Intent) : Data to perform BackFlow, consisting of four parameters
          • Type, atyClass, fragmentClazzs, Extra
      • Class<? extends Activity> atyClass
        • BackFlow The target activity of the rollback
      • List<Class<? extends Fragment>> fragmentClazzs
        • Step back to the fragment order list, target fragment(last fragment) in the fragment order column
      • backActivityCount
        • The number of activities to back, each time –backActivityCount,
        • When currbackActivityCount is 0(ACTIVITY_COUNT_OF_STOP_BACK_FLOW), no rollback is performed
        • If backActivityCount is set to 1, only the current activity is finished
      • Bundle extra: Additional data
    • Builder: Builder mode to reduce the complexity of creating backFlowData
  5. BackFlowIntent Tool class: BackFlowIntent
    • The utility class that assembles and parses the BackFlow Intent has four parameters. Other keys in the app cannot be the same as their keys
      • BACK_FLOW_TYPE: type of the rollback function (backflowtype.type)
        • type is int
        • ERROR_BACK_FLOW_TYPE: Type value of the error type (backflowtype.error.type)
        • Check whether it is BackFlow onActivityResult
        private static boolean canHandle(int resultCode, Intent data) {
            return resultCode == RESULT_CODE && BackFlowType.isBackFlowType(data);
        }
        Copy the code
      • BACK_FLOW_ACTIVITY: the activity specified in the rollback function
        • type is String
      • BACK_FLOW_FRAGMENTS: Fragments specified in the rollback function
        • type is String
        • Use JSON for formatting
      • BACK_ACTIVITY_COUNT: indicates the number of activities to be rolled back
        • type is int
        • Each rollback will be backActivityCount. When currBackActivityCount is 0, the rollback will not be performed
        • If set to 1, just finish the current activity
      • BACK_FLOW_EXTRA: indicates the extra data brought by the user in the rollback function
        • type is String
        • You can bring extra data to a target Activity or Fragment
    • Builder: Reduces the complexity of creating BackFlow intents
  6. BackFlowView utility class: BackFlowViewHelper
    • The tool class that matches the target Activity and Fragment in BackFlow
    • IsTargetActivity method: Whether it is the target activity for the rollback function
    • FindTargetFragment method: Find the target fragment(the last fragment) in the sequence column of fragments in the rollback function
    • Tip: The Sub FragmentManager of a Fragment must be getChildFragmentManager

BackFlow is not available or cannot be returned to the target location

  1. If any of the xxxActivities in the middle of the rollback chain consume the onActivityResult method, the XXXActivity is stuck and the rollback cannot continue
    • Because the entire rollback function relies on the setResult method to chain back data to the previous activity’s onActivityResult method, after the activity consumes the onActivityResult method, This method will not be called again.
  2. Examples of cases that consume the onActivityResult method are as follows:
    • Switch the task;
    • Switching process;
    • In startActivity, intent.setflags (intent.flag_activity_new_task) is called;
  3. launchMode
    • Different versions of Android have different differences; 4.4 will consume, 5.0.2 and 6.0 will not
    • singleInstance
      • A new stack structure is enabled, Acitvity is placed in the new stack structure, and no other Activity instances are allowed to enter
      • 4.4 Tasks will be switched
      • 5.0.2 and 6.0 startActivityForResult do not switch tasks, so they can still be used, but launchMode becomes standard
    • singleTask
      • 4.4 consumes the onActivityResult method
      • 5.0.2 and 6.0 startActivityForResult will not call onActivityResult, so it can still be used, but the startActivityForResult method, At this point launchMode will become standard

Tips and Limitations

  1. LaunchMode: startActivityForResult Launches XXXActivity for singleTop, singleTask, and singleInstance
    • After 5.0, XXXActivity’s launchMode setting becomes invalid and changes to Standard launchMode
    • For systems prior to 5.0, only singleTop mode was disabled
    • So, if you have any requirements, you can use startActivity4NonBackFlow method, BackFlow will fail, but this time will stay here no longer back
  2. StartActivityForResult + Intent.flag_activity_new_task + singleInstance will start a new task, so BackFlow will be invalidated and will remain there