Java 在方向更改时正确保留侦听器
考虑以下场景:Java 在方向更改时正确保留侦听器,java,android,android-fragments,interface,android-orientation,Java,Android,Android Fragments,Interface,Android Orientation,考虑以下场景: 我有一个带有UI元素的活动,单击时会启动一个对话框片段 对话框片段有一个监听器接口,活动提供了该接口的实现。例如,活动是一个图像编辑器,对话框片段选择一个对比度-该对话框将有一个活动实现的OnContastChangedListener 活动已实现此界面,以更新其UI中的视图。继续图像编辑器示例,活动实现了OnContrast ChangedListener以更新其预览视图,如下所示: contrastDialog.setOnContrastChangedListener(new
活动
,单击时会启动一个对话框片段
对话框片段
有一个监听器接口
,活动
提供了该接口的实现。例如,活动
是一个图像编辑器,对话框片段
选择一个对比度-该对话框将有一个活动
实现的OnContastChangedListener
活动
已实现此界面
,以更新其UI中的视图。继续图像编辑器示例,活动
实现了OnContrast ChangedListener
以更新其预览视图,如下所示:
contrastDialog.setOnContrastChangedListener(new OnContrastChangedListener {
@Override
public void OnContrastChanged(int newContrast) {
getPreviewView().updateWithContrast(newContrast);
}
});
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");
}
片段中,并在生命周期处于还原状态时还原)
getPreviewView()
现在返回null
,即使在活动
中的任何其他地方调用它时返回正确的值
请原谅这个糟糕的术语(我在编译和字节码方面的知识是有限的),但我能理解发生了什么。该接口已使用getPreviewView()
版本编译,该版本返回了在方向更改时被破坏的预览视图,并且该视图已被发布/垃圾回收/现在为null
我的问题是,在Java中有没有一种方法可以让接口编译时期望值/函数发生变化,就像C中的volatile
关键字一样(我希望没有)?在这种情况下,解决这种情况的最佳方法是什么?我曾考虑过以下几点:
- 在重新创建
时重新运行的代码中创建活动
(及其对话框片段
)。这对于接口
forOnClickListeners
这样的东西很好,因为它们是绝对创建的。但是这个按钮
仅在按下按钮时创建,因此这种方法意味着每次对话框片段
启动时都会创建屏幕上的每个对话框,这似乎是浪费,因为它们甚至可能不会运行活动
- 每次为
创建所有可能的活动
,并将其保存在成员变量中,然后在事件请求创建接口
时使用这些对话框片段
接口。与上面的注释相同-创建每一个可能的
似乎是浪费,以防它运行李>接口
- 在活动中保留一些粗糙的“打开对话框状态”成员变量,用于指导
界面的重新创建。Hacky并在
和活动
之间建立了联系,这不是一个很好的实践对话框片段
- 在活动中保留一些粗糙的“打开对话框状态”成员变量,用于指导
接口实现
编辑:选项1和2不起作用,因为它们需要指向现有对话框的链接。这一切都是可行的,但它越来越倾向于“当前对话”变量的拼凑选项,当活动重新启动时,使用FragmentManager
获取DialogFragment
,根据“当前对话”变量适当地转换它,重新创建侦听器。是否有一种不那么凌乱的方式?如果活动始终具有接口的实现,是否可以在DialogFragment的onAttach()中设置侦听器?这将确保在销毁和重新创建时,它将具有最新的引用,如:
public void onAttach(Activity activity) {
super.onAttach(activity);
contrastChangedListener = (OnContrastChangedListener)activity;
}
public void onDetach() {
super.onDetach();
contrastChangedListener = null;
}
onAttach
onDetach
方法很好,我喜欢使用它,有时候,当我知道代码中会有更多的开发人员时,我甚至不会盲目地使用它,但我做了如下检查:
contrastDialog.setOnContrastChangedListener(new OnContrastChangedListener {
@Override
public void OnContrastChanged(int newContrast) {
getPreviewView().updateWithContrast(newContrast);
}
});
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()
需要当前活动才能正常运行,因此当所有人都被破坏或重建时,您需要再次传递此引用
这些只是不同的方法。哪里是getPreviewView()
implement?你能告诉我们这个方法吗?@Code学徒:这只是一个例子。例如,它的实现可以是return(PreviewView)findviewbyd(R.id.preview)
其中PreviewView
是一个自定义视图类,R.id.preview
是在XML布局中定义的id,这基本上只是选项2(看起来最有可能)。但是,这个答案不起作用有几个原因(将活动投射到侦听器:假设活动实现是一个错误的假设,如果另一个片段实现了侦听器会发生什么?)