正确地让听众了解方向的变化



考虑以下场景:

  1. 我有一个带有UI元素的Activity,单击后会启动DialogFragment
  2. DialogFragment具有侦听器interfaceActivity提供了该侦听器的实现。例如,Activity是一个图像编辑器,DialogFragment选择对比度-对话框将有Activity实现的OnContrastChangedListener
  3. Activity已经实现了这个interface来更新其UI中的视图。继续图像编辑器的例子,Activity实现OnContrastChangedListener来更新其预览视图——类似于以下内容:

    contrastDialog.setOnContrastChangedListener(new OnContrastChangedListener {
        @Override
        public void OnContrastChanged(int newContrast) {
            getPreviewView().updateWithContrast(newContrast);            
        }
    });
    
  4. 方向被更改,所有内容都被重新创建,侦听器使用此处推荐的方法被正确保存和恢复(侦听器被保存在Fragment中,并在生命周期处于恢复状态时被恢复)。

问题是侦听器接口现在不起作用。函数getPreviewView()现在返回null,即使当调用Activity中的其他任何位置时,它返回正确的值

抱歉术语不好(我在编译和字节码方面的知识有限),但我能理解发生了什么。该接口是用getPreviewView()版本编译的,该版本返回了在方向更改时被破坏的预览视图,该视图已被释放/垃圾回收/现在是null

我的问题是,在Java中,是否有一种方法可以使接口编译时期望值/函数发生变化——就像C中的volatile关键字一样(我希望没有)?在这种情况下,避开这种情况的最佳方法是什么?我考虑了以下内容:

  • 在重新创建Activity时重新运行的代码中创建DialogFragment(及其interface)。这对于OnClickListenersButtons这样的东西来说很好,因为它们肯定是创建的。但这个DialogFragment只有在按下按钮时才会创建,因此这种方法意味着每次Activity时都会创建屏幕的每个对话框-这似乎是浪费,因为它们甚至可能无法运行
  • 每次为Activity创建所有可能的interfaces,并将其保存在成员变量中,然后在事件请求创建DialogFragments时使用这些interfaces。与上面相同的注释-创建所有可能的interface似乎很浪费,以防它被运行
  • 在"活动"中保留一些"打开对话框状态"的成员变量,以指导interfaces的重新创建。破解并在ActivityDialogFragment之间创建平局,这不是一个很好的实践

正如您所看到的,所有选项都涉及到在某种程度上是浪费的再创造——有没有一种方法可以重用现有的interface实现?

编辑:选项1和2不起作用,因为它们需要到现有Dialog的链接。这一切都是可行的,但它越来越倾向于使用"current Dialog"变量的组合选项,在活动重新启动时使用FragmentManager获取DialogFragment,根据"current对话框"变量适当地转换它,重新创建侦听器。有没有一种不那么混乱的方法?

onAttach onDetach方法很好,我喜欢使用它,有时,当我知道代码中会有更多的开发人员时,我甚至不会盲目地转换它,但我会做这样的检查:

if(activity instanceof MyInterface){
   interface = (MyInterface) activity;
} else{
   thrown new RuntimeException("Dear colleague, this fragment was meant to have the activity implementing MyInterface or else a bunch of other stuff won't work, please go back to your code and add the interface");
}

但作为另一种手段,您也可以在重新创建片段时重新设置接口。例如,在活动onCreate

if(savedInstanceState != null){
    mDialogFrag = getSupportFragmentManager().findFragmentByTag(MyDialogFrag.TAG);
    if(mDialogFrag != null)
       mDialogFrag.setListener(... the interface   ...);
}

我知道这也不是最好的对象分离,但事实是getPreviewView()需要当前活动才能正确操作,所以当每个人都被销毁和重建时,你需要再次传递这个引用。

这些只是不同的方法。

如果活动总是有接口的实现,是否可以在DialogFragment的onAttach()中设置侦听器?这将确保当它被销毁和重新创建时,它将拥有最新的参考,如:

public void onAttach(Activity activity) {
    super.onAttach(activity);
    contrastChangedListener = (OnContrastChangedListener)activity;
}
public void onDetach() {
    super.onDetach();
    contrastChangedListener = null;
}

最新更新