OnClickListener 在 onPause 之后触发?
OnClickListener fired after onPause?
我正在工作的项目使用视图呈现器抽象。
这里是所有主要的简化版本类。
抽象activity(连线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();
}
}
从 MyPresenter.onButtonPressed()
方法调用时,getView().redirect();
触发了 "IllegalStateException: Presenter view is null"
问题。
这对我来说没有任何意义,因为如果侦听器被解雇,视图应该始终不为空。如果仅从 MvpActivity.onPause()
调用的 MvpPresenter.onPause()
被执行,则视图仅设置为 null。发生这种情况后我不希望收到任何点击事件,那么我在这里错过了什么?
遗憾的是,我无法通过手动测试应用程序来重现此问题。这些报告来自 Crashlytics。
注意:retrolambda 用于按钮点击侦听器
2017 年 10 月 7 日更新
解决此问题的一些方法:
-
https://developer.android.com/reference/android/view/View.html#cancelPendingInputEvents()
简短回答:不要那样做。
不幸的是,您依赖于未定义的事件顺序。 Activity 生命周期事件和 Window 事件是两个不同的事物,尽管它们通常密切相关。当 activity 因任何原因暂停时,您将获得 onPause()。但是在视图的 window 失去焦点之前,视图触摸事件不会解除。
activity 在其 window 失去焦点时暂停是很常见的——例如,当屏幕被锁定或另一个 activity 启动时。但是正如您所见,您可以在没有焦点改变的情况下获得暂停,并且可以在没有暂停的情况下获得焦点改变。即使两个事件同时发生,也有很短的 window 时间调用 onPause() 但 window 输入处理程序仍处于活动状态。
与任何未定义的行为一样,您看到的实际结果将因 OS 版本和硬件类型而异。
如果您需要确保在 onPause 后不会收到 View 消息,您应该在 onPause 中取消挂钩您的处理程序。
我正在工作的项目使用视图呈现器抽象。 这里是所有主要的简化版本类。
抽象activity(连线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();
}
}
从 MyPresenter.onButtonPressed()
方法调用时,getView().redirect();
触发了 "IllegalStateException: Presenter view is null"
问题。
这对我来说没有任何意义,因为如果侦听器被解雇,视图应该始终不为空。如果仅从 MvpActivity.onPause()
调用的 MvpPresenter.onPause()
被执行,则视图仅设置为 null。发生这种情况后我不希望收到任何点击事件,那么我在这里错过了什么?
遗憾的是,我无法通过手动测试应用程序来重现此问题。这些报告来自 Crashlytics。
注意:retrolambda 用于按钮点击侦听器
2017 年 10 月 7 日更新
解决此问题的一些方法:
- https://developer.android.com/reference/android/view/View.html#cancelPendingInputEvents()
简短回答:不要那样做。
不幸的是,您依赖于未定义的事件顺序。 Activity 生命周期事件和 Window 事件是两个不同的事物,尽管它们通常密切相关。当 activity 因任何原因暂停时,您将获得 onPause()。但是在视图的 window 失去焦点之前,视图触摸事件不会解除。
activity 在其 window 失去焦点时暂停是很常见的——例如,当屏幕被锁定或另一个 activity 启动时。但是正如您所见,您可以在没有焦点改变的情况下获得暂停,并且可以在没有暂停的情况下获得焦点改变。即使两个事件同时发生,也有很短的 window 时间调用 onPause() 但 window 输入处理程序仍处于活动状态。
与任何未定义的行为一样,您看到的实际结果将因 OS 版本和硬件类型而异。
如果您需要确保在 onPause 后不会收到 View 消息,您应该在 onPause 中取消挂钩您的处理程序。