美文网首页
Activity对DialogFragment的管理

Activity对DialogFragment的管理

作者: Fakecoder_Sunis | 来源:发表于2020-04-09 10:42 被阅读0次

    Activity 专题- Activity 如何托管 Fragment 的生命周期解析
    或者你使用过 DialogFragment,DialogFragment 是一种特殊的 Fragment ,这里简单介绍下原理,其实就是 Fragment 里面封装了一个 Dialog,

    public class DialogFragment extends Fragment
    implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener {
    Dialog mDialog;
    FragmentHostCallback mHost;

    //显示这个 Fragment 调用这个方法
    public void show(FragmentManager manager, String tag) {
        mDismissed = false;
        mShownByMe = true;
        FragmentTransaction ft = manager.beginTransaction();
        ft.add(this, tag);
        ft.commit();
    }
    // 这里会创建一个默认的 dialog
    @override
    public LayoutInflater getLayoutInflater(Bundle savedInstanceState) {
        if (!mShowsDialog) {//如果不显示 dialog,则走普通 Fragment 流程
            return super.getLayoutInflater(savedInstanceState);
        }
    
        //以下是创建 dialog 的代码
        mDialog = onCreateDialog(savedInstanceState);
        switch (mStyle) {
        case STYLE_NO_INPUT:
            mDialog.getWindow().addFlags(
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
            // fall through...
        case STYLE_NO_FRAME:
        case STYLE_NO_TITLE:
            mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        }
        if (mDialog != null) {
            return (LayoutInflater)mDialog.getContext().getSystemService(
                       Context.LAYOUT_INFLATER_SERVICE);
        }
        //这里的 mHost 对象就是 Fragment 宿主的 Activity
        return (LayoutInflater) mHost.getContext().getSystemService(
                   Context.LAYOUT_INFLATER_SERVICE);
    }
    
    //这里会对 Dialog 进行 setContentView() 操作,设置视图,getView() 方法返回的就是 你实现的 onCreateView() 返回的View
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    
        if (!mShowsDialog) {
            return;
        }
    
        View view = getView();
        if (view != null) {
            if (view.getParent() != null) {
                throw new IllegalStateException(
                    "DialogFragment can not be attached to a container view");
            }
            mDialog.setContentView(view);
        }
        final Activity activity = getActivity();
        if (activity != null) {
            mDialog.setOwnerActivity(activity);
        }
        mDialog.setCancelable(mCancelable);
        if (!mDialog.takeCancelAndDismissListeners("DialogFragment", this, this)) {
            throw new IllegalStateException(
                "You can not set Dialog's OnCancelListener or OnDismissListener");
        }
        if (savedInstanceState != null) {
            Bundle dialogState = savedInstanceState.getBundle(SAVED_DIALOG_STATE_TAG);
            if (dialogState != null) {
                mDialog.onRestoreInstanceState(dialogState);
            }
        }
    }
    
    // onStar() 时会调用 Dialog.show(),也就是 Activity.onStart() 的时候
    @Override
    public void onStart() {
        super.onStart();
        if (mDialog != null) {
            mViewDestroyed = false;
            mDialog.show();
        }
    }
    
    // onStop() 的时候会关闭 Dialog
    @Override
    public void onStop() {
        super.onStop();
        if (mDialog != null) {
            mDialog.hide();
        }
    }
    

    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    大致的流程如下:

    DialogFragment 内部在 getLayoutInflater() 方法的时候会创建一个 Dialog,也就是 Fragment 初始化的时候。
    DialogFragment 在 onActivityCreated() 的时候,会给 Dailog 设置视图,调用了 getView() 方法,也就是返回 onCreateView() 的返回值。
    onStart() 的时候会调用 dialog.show()
    onStop() 的时候会调用 dialog.hide()
    还可以通过重写 onCreateDialog() ,可以实现展示自定义的 Dialog.

    public Dialog onCreateDialog(Bundle savedInstanceState) {
    return super.onCreateDialog(savedInstanceState);
    }
    1
    2
    3
    这种 Dialog 的好处就是,能够通过 Fragment 监听到 Activity 的生命周期回调,从而保证,在 Activity 关闭的时候,能够确保 Dialog 是关闭的,而不会造成因 Dialog 未关闭,导致 Activity 泄漏。

    Activity 如何托管 Fragment 的生命周期
    除了上面提到的,DialogFragment,同样在 Glide 框架里面,也是巧妙的用了这一个原理,使得基于 Activity Context 的 Rquest 能够自动伴随 Activity 的生命周期取消,从而提高了执行效率。

    这里主要通过 FragmentHostCallback 实现 Fragment 追随Activity 的生命周期,同时也是实现了 Activity 调度 Fragment 的生命周期。

    先来看看这个类:

    /**

    • Integration points with the Fragment host.

    • <p>

    • Fragments may be hosted by any object; such as an {@link Activity}. In order to

    • host fragments, implement {@link FragmentHostCallback}, overriding the methods

    • applicable to the host.
      /
      public abstract class FragmentHostCallback<E> extends FragmentContainer {
      /
      *
      * Called when a {@link Fragment} is being attached to this host, immediately
      * after the call to its {@link Fragment#onAttach(Context)} method and before
      * {@link Fragment#onCreate(Bundle)}.
      */
      public void onAttachFragment(Fragment fragment) {
      }

      /**

      • Return a {@link LayoutInflater}.
      • See {@link Activity#getLayoutInflater()}.
        */
        public LayoutInflater onGetLayoutInflater() {
        return (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        }

      void doLoaderStart() {
      if (mLoadersStarted) {
      return;
      }
      mLoadersStarted = true;

       if (mLoaderManager != null) {
           mLoaderManager.doStart();
       } else if (!mCheckedForLoaderManager) {
           mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false);
       }
       mCheckedForLoaderManager = true;
      

      }

    void doLoaderStop(boolean retain) {
        mRetainLoaders = retain;
    
        if (mLoaderManager == null) {
            return;
        }
    
        if (!mLoadersStarted) {
            return;
        }
        mLoadersStarted = false;
    
        if (retain) {
            mLoaderManager.doRetain();
        } else {
            mLoaderManager.doStop();
        }
    }
    
    void doLoaderDestroy() {
        if (mLoaderManager == null) {
            return;
        }
        mLoaderManager.doDestroy();
    }
    }
    

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    这个类的官方 API 解释就是,Fragment 可以寄宿在任何对象上,例如 Activity。为了管理 Fragment,需要实现 FragmentHostCallback 方法,重载一些关键的方法,实现对 Fragment 的管理。

    这里列举一些关键的方法,具体的细节可以自行查看源码。

    然后在 Activity 中,我们可以看到这样一些代码:

    public class Activity {
    final FragmentController mFragments = FragmentController.createController(new HostCallbacks());

    @CallSuper
    protected void onStart() {
        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStart " + this);
        mCalled = true;
    
        mFragments.doLoaderStart();
    
        getApplication().dispatchActivityStarted(this);
    }
    
    public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
        if (!"fragment".equals(name)) {
            return onCreateView(name, context, attrs);
        }
    
        return mFragments.onCreateView(parent, name, context, attrs);
    }
    
    final void performDestroy() {
        mDestroyed = true;
        mWindow.destroy();
        mFragments.dispatchDestroy();
        onDestroy();
        mFragments.doLoaderDestroy();
        if (mVoiceInteractor != null) {
            mVoiceInteractor.detachActivity();
        }
    }
    
    class HostCallbacks extends FragmentHostCallback<Activity> {
        public HostCallbacks() {
            super(Activity.this /*activity*/);
        }
    
        @Override
        public void onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
            Activity.this.dump(prefix, fd, writer, args);
        }
    
        @Override
        public boolean onShouldSaveFragmentState(Fragment fragment) {
            return !isFinishing();
        }
    
        @Override
        public LayoutInflater onGetLayoutInflater() {
            final LayoutInflater result = Activity.this.getLayoutInflater();
            if (onUseFragmentManagerInflaterFactory()) {
                return result.cloneInContext(Activity.this);
            }
            return result;
        }
    
        @Override
        public boolean onUseFragmentManagerInflaterFactory() {
            // Newer platform versions use the child fragment manager's LayoutInflaterFactory.
            return getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP;
        }
    
        @Override
        public Activity onGetHost() {
            return Activity.this;
        }
    
        @Override
        public void onInvalidateOptionsMenu() {
            Activity.this.invalidateOptionsMenu();
        }
    
        @Override
        public void onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode,
                                                Bundle options) {
            Activity.this.startActivityFromFragment(fragment, intent, requestCode, options);
        }
    
        @Override
        public void onStartIntentSenderFromFragment(Fragment fragment, IntentSender intent,
                int requestCode, @Nullable Intent fillInIntent, int flagsMask, int flagsValues,
                int extraFlags, Bundle options) throws IntentSender.SendIntentException {
            if (mParent == null) {
                startIntentSenderForResultInner(intent, fragment.mWho, requestCode, fillInIntent,
                flagsMask, flagsValues, options);
            } else if (options != null) {
                mParent.startIntentSenderFromChildFragment(fragment, intent, requestCode,
                fillInIntent, flagsMask, flagsValues, extraFlags, options);
            }
        }
    
        @Override
        public void onRequestPermissionsFromFragment(Fragment fragment, String[] permissions,
                int requestCode) {
            String who = REQUEST_PERMISSIONS_WHO_PREFIX + fragment.mWho;
            Intent intent = getPackageManager().buildRequestPermissionsIntent(permissions);
            startActivityForResult(who, intent, requestCode, null);
        }
    
        @Override
        public boolean onHasWindowAnimations() {
            return getWindow() != null;
        }
    
        @Override
        public int onGetWindowAnimations() {
            final Window w = getWindow();
            return (w == null) ? 0 : w.getAttributes().windowAnimations;
        }
    
        @Override
        public void onAttachFragment(Fragment fragment) {
            Activity.this.onAttachFragment(fragment);
        }
    
        @Nullable
        @Override
        public View onFindViewById(int id) {
            return Activity.this.findViewById(id);
        }
    
        @Override
        public boolean onHasView() {
            final Window w = getWindow();
            return (w != null && w.peekDecorView() != null);
        }
    }
    

    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    也就是 Activity 中的内部类HostCallbacks 继承了 FragmentHostCallback ,实现了一些关键的方法,用于在 Activity 的生命周期中,回调Fragment 中对应的方法。

    最终会通过 FragmentController 分发给 Fragment,我们以 onDestory() 行为为例子,进行分析:

    step1:

    Activity.performDestory()

    final void performDestroy() {
    mDestroyed = true;
    mWindow.destroy();
    mFragments.dispatchDestroy();
    onDestroy();
    mFragments.doLoaderDestroy();
    if (mVoiceInteractor != null) {
    mVoiceInteractor.detachActivity();
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    step2:

    FragmentController.dispatchDestory()

    public void dispatchDestroy() {
    mHost.mFragmentManager.dispatchDestroy();
    }
    1
    2
    3
    也就是会回调 Host 的 FragmentManager 里的方法,那么 Activity 里面的 FragmentManager 对象,其实就是 FragmentManagerImpl 类。

    step3:

    FragmentManagerImpl.dispatchDestory()

    public void dispatchDestroy() {
    mDestroyed = true;
    execPendingActions();
    mExecutingActions = true;
    moveToState(Fragment.INITIALIZING, false);
    mExecutingActions = false;
    mHost = null;
    mContainer = null;
    mParent = null;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    这里进行一系列标记清楚,并且把 mHost 等引用置为 null,解除了和 Activity 之间的引用,里面还调用了 moveToState() 方法,这里对 Fragment 的状态等进行了重置,具体细节比较复杂,就不进行分析,可以理解的是,这是 Fragment 回到了,还没创建的状态。

    相关文章

      网友评论

          本文标题:Activity对DialogFragment的管理

          本文链接:https://www.haomeiwen.com/subject/mqmqmhtx.html