我工作的项目使用视图展示器抽象。 这是所有主要类的简化版本。
抽象活动(Wire Presenter实例,带有View)
teardown_module()
视图界面
public abstract class MvpActivity<Presenter extends MvpPresenter>
extends ActionBarActivity {
protected Presenter mPresenter;
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPresenter = getPresenterInstance();
}
@Override protected void onResume() {
super.onResume();
mPresenter.onResume(this);
}
@Override protected void onPause() {
mPresenter.onPause();
super.onPause();
}
}
视图实现
public interface MyView {
void redirect();
}
抽象主持人
public class MyActivity
extends MvpActivity<MyPresenter>
implements MyView {
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_view);
Button myButton = (Button)findViewById(R.id.my_button);
myButton.setOnClickListener(v -> mPresenter.onButtonPressed());
}
@Override protected MyPresenter getPresenterInstance() {
return new MyPresenter();
}
@Override void redirect(){
startActivity(new Intent(this, MyOtherActivity.class));
}
演示者实施
public abstract class MvpPresenter<ViewType> {
private ViewType mView;
public void onResume(ViewType view) {
mView = view;
}
public void onPause() {
mView = null;
}
protected ViewType getView() {
if (mView == null) {
throw new IllegalStateException("Presenter view is null");
}
return mView;
}
}
当从public class MyPresenter extends MvpPresenter<MyView> {
@Override public void onResume(MyView myView){
super.onResume(myView);
Log.("MyPresenter", "Presenter resumed");
}
@Override public void onPause(){
super.onPause()
Log.("MyPresenter", "Presenter paused");
}
public void onButtonPressed(){
getView().redirect();
}
}
方法调用"IllegalStateException: Presenter view is null"
时,问题出现getView().redirect();
。
这对我没有任何意义,因为如果侦听器被触发,视图应始终不为null。如果执行MyPresenter.onButtonPressed()
仅从MvpPresenter.onPause()
调用,则视图仅设置为null。发生这种情况后,我不希望收到任何点击事件,所以我在这里缺少什么?
可悲的是,我无法通过手动测试应用程序来重现此问题。报告来自Crashlytics。
注意:retrolambda用于按钮单击侦听器
解决此问题的一些方法:
- https://developer.android.com/reference/android/view/View.html#cancelPendingInputEvents()
答案 0 :(得分:10)
简短的回答:不要这样做。
不幸的是,您依赖于未定义的事件顺序。活动生命周期事件和窗口事件是两个不同的事情,即使它们经常密切相关。当活动因任何原因暂停时,您将获得onPause()。但在View窗口失去焦点之前,View触摸事件不会被取消。
当一个活动在窗口失去焦点时暂停,例如,当屏幕被锁定或启动另一个活动时,这种情况非常常见。但是,正如您所见,您可以在没有焦点更改的情况下暂停,并且可以不停顿地进行焦点更改。即使两个事件一起发生,当调用onPause()但窗口输入处理程序仍处于活动状态时,会有一个狭窄的时间窗口。
与任何未定义的行为一样,您看到的实际结果会因操作系统版本和硬件类型而异。
如果你需要确保在onPause之后没有收到查看邮件,你应该在onPause中取消挂钩处理程序。