考虑以下场景:
- 我有一个带有UI元素的
Activity
,单击后会启动DialogFragment
DialogFragment
具有侦听器interface
,Activity
提供了该侦听器的实现。例如,Activity
是一个图像编辑器,DialogFragment
选择对比度-对话框将有Activity
实现的OnContrastChangedListener
-
Activity
已经实现了这个interface
来更新其UI中的视图。继续图像编辑器的例子,Activity
实现OnContrastChangedListener
来更新其预览视图——类似于以下内容:contrastDialog.setOnContrastChangedListener(new OnContrastChangedListener { @Override public void OnContrastChanged(int newContrast) { getPreviewView().updateWithContrast(newContrast); } });
-
方向被更改,所有内容都被重新创建,侦听器使用此处推荐的方法被正确保存和恢复(侦听器被保存在
Fragment
中,并在生命周期处于恢复状态时被恢复)。
问题是侦听器接口现在不起作用。函数getPreviewView()
现在返回null
,即使当调用Activity
中的其他任何位置时,它返回正确的值
抱歉术语不好(我在编译和字节码方面的知识有限),但我能理解发生了什么。该接口是用getPreviewView()
版本编译的,该版本返回了在方向更改时被破坏的预览视图,该视图已被释放/垃圾回收/现在是null
。
我的问题是,在Java中,是否有一种方法可以使接口编译时期望值/函数发生变化——就像C中的volatile
关键字一样(我希望没有)?在这种情况下,避开这种情况的最佳方法是什么?我考虑了以下内容:
-
在重新创建Activity
时重新运行的代码中创建DialogFragment
(及其interface
)。这对于OnClickListeners
和Buttons
这样的东西来说很好,因为它们肯定是创建的。但这个DialogFragment
只有在按下按钮时才会创建,因此这种方法意味着每次Activity
时都会创建屏幕的每个对话框-这似乎是浪费,因为它们甚至可能无法运行 -
每次为Activity
创建所有可能的interfaces
,并将其保存在成员变量中,然后在事件请求创建DialogFragments
时使用这些interfaces
。与上面相同的注释-创建所有可能的interface
似乎很浪费,以防它被运行 - 在"活动"中保留一些"打开对话框状态"的成员变量,以指导
interfaces
的重新创建。破解并在Activity
和DialogFragment
之间创建平局,这不是一个很好的实践
正如您所看到的,所有选项都涉及到在某种程度上是浪费的再创造——有没有一种方法可以重用现有的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;
}