在 show() 之前获取 DialogFragment 子类中的父活动

Posted

技术标签:

【中文标题】在 show() 之前获取 DialogFragment 子类中的父活动【英文标题】:Get parent activity in DialogFragment subclass before show() 【发布时间】:2019-01-17 07:57:29 【问题描述】:

我正在开发一个带有许多对话框的 android 应用程序,所有这些对话框都扩展了一个名为“DialogFragmentBase”的自定义类,该类扩展了库的“DialogFragment”。所有活动都使用在 DialogFragmentBase 中重写的 show() 方法。

如果父活动是后台的(如接听电话),我想阻止显示对话框,因为这会导致非法状态异常,但同时我不想保护每个 show() 调用应用程序:

if(getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED))

所以我想在 DialogFragmentBase 中做这样的事情:

@Override
public void show(FragmentManager manager, String tag)

    List<Fragment> fragments = manager.getFragments();
    if(fragments != null && fragments.size() > 0)
        FragmentActivity activity = fragments.get(fragments.size()-1).getActivity();
        if(activity != null && activity.getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED))
            super.show(manager, tag);
        
    

所以我的问题是:像这样访问上一个片段是否被认为是一种不好的做法?它确实有效......但我记得在某个地方读到片段不应该相互交流。如果这确实是一种不好的做法,那么可以在 DialogFragmentBase 中实现的更好的解决方案是什么(以避免在任何地方添加警卫)。

注意:我尝试了here 中描述的 onSaveInstanceState 解决方案,但由于尚未显示 DialogFragment,因此此时不需要调用 onSaveInstanceState。 getActivity() 也返回 null,因为此时尚未调用 onAttach。

谢谢!

【问题讨论】:

【参考方案1】:

support library FragmentManager 有一个isStateSaved() method。根据您的具体要求,您可以利用它来检查显示对话框是否“安全”:

@Override
public void show(FragmentManager manager, String tag) 
    if (!manager.isStateSaved()) 
        super.show(manager, tag);
    

请注意,上面的实现与使用commitAllowingStateLoss() 比较相似,因为在某些情况下您会默默地无法显示您的对话框。但也许这符合您的要求。

【讨论】:

isStateSaved() 会返回 false,即使父活动已经在后台。我开始认为commitAllowingStateLoss() 可能不是一个糟糕的方法(至少在我的情况下,因为如果应用程序在后台,我想向用户显示的对话框是无用的)。 一般来说,如果父activity在后台但是状态还没有被保存,那是显示对话框的好时机。当用户返回应用程序时,对话框将可见。 真的吗?这不是我所看到的,我得到的是illegalStateException 可能是因为我使用的是show() 而不是commitNow(),所以到节目安排的时候,状态已经被保存了? 假设你得到的异常是can not be performed after onSaveInstanceState() 一个,那么是的。重要的是片段管理器是否保存了它的状态;如果没有,那么任何交易都是安全的。但你是对的,我相信在某些情况下可以将事务添加到队列中,然后让片段管理器在处理该事务之前保存其状态。 所以我设法让它通过这样做: if(!manager.isStateSaved() && !savedInstanceStateDone) transaction.commitNow(); 这看起来好吗?【参考方案2】:

也许您可以在对话框基类中创建一个新方法:

public void showIfResumed(FragmentActivity activity, String tag) 
    if (/* your check here, e.g. activity.getLifecycle()...  */) 
        show(activity.getSupportFragmentManager(), tag);
    

然后,在您的活动中,您可以调用showIfResumed(this, TAG),而不是调用show(getSupportFragmentManager(), TAG)。您仍然需要将每次调用 show() 更改为调用 showIfResumed(),但这会大大减少代码重复。

【讨论】:

谢谢这是我的下一个选择,但访问片段列表的解决方案是一种不好的做法吗?因为它允许我不更改 DialogFragmentBase 中的任何内容。虽然使用您的解决方案,但我必须进行很多更改,我希望有一个可以轻松实施的解决方案,而不是依赖开发人员调用不直观的 showIfResumed。 @MennaMostafa 我会说是的,您在问题中发布的内容是一种不好的做法。为什么您的片段向片段管理器询问正在管理的其他片段?如果没有“前一个”片段会发生什么?如果“前一个”片段未附加到活动会发生什么?等等。您可能会更改基类中现有的show() 方法以抛出UnsupportedOperationException,这样任何使用它的人都会立即看到他们不应该这样做。

以上是关于在 show() 之前获取 DialogFragment 子类中的父活动的主要内容,如果未能解决你的问题,请参考以下文章

页面已修改值,但是后台获取还是修改之前的值

python datetime获取几分钟小时天之前的时间

Android应用开发提高篇-----获取本地IP

python学习第11天

python学习第11天

使用Python的正则表达式.match()方法获取下划线之前和之后的字符串