这是所有主要类的简化版本.
抽象活动(Wire Presenter实例,带View)
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(); } }
问题出现在getView()触发的“IllegalStateException:Presenter视图为空”.redirect();从MyPresenter.onButtonPressed()方法调用时.
这对我没有任何意义,因为如果侦听器被触发,视图应始终不为null.如果执行仅从MvpActivity.onPause()调用的MvpPresenter.onPause(),则视图仅设置为null.发生这种情况后,我不希望收到任何点击事件,所以我在这里缺少什么?
遗憾的是,我无法通过手动测试应用程序来重现此问题.这些报道来自Crashlytics.
注意:retrolambda用于按钮单击侦听器
更新10/07/2017
–
https://developer.android.com/reference/android/view/View.html#cancelPendingInputEvents()
解决方法
不幸的是,您依赖的是未定义的事件顺序.活动生命周期事件和窗口事件是两个不同的事情,即使它们通常密切相关.当活动因任何原因暂停时,您将获得onPause().但View视图窗口失去焦点后,View触摸事件不会被取消.
当一个活动窗口失去焦点时,例如当屏幕被锁定或启动另一个活动时,它就会非常常见.但正如您所见,您可以在没有焦点变化的情况下暂停,并且可以不停顿地进行焦点更改.即使两个事件一起发生,当调用onPause()但窗口输入处理程序仍处于活动状态时,会有一个很窄的时间窗口.
与任何未定义的行为一样,您看到的实际结果将因操作系统版本和硬件类型而异.
如果您需要确保在onPause之后没有收到View消息,则应该在onPause中取消挂钩处理程序.