调用销毁 activity 的 OnClick 回调
OnClick callback of destroyed activity is called
首先-背景:
在我的应用程序中,我有两个非常相似的活动。它们都是通过 RecyclerView 显示的相同卡片的列表。区别在于不同的 onClick/onLongClick 侦听器和其中一个缺少上下文操作模式。
我通过制作两个 child 和一个 parent class 来实现它们,以容纳所有通用代码和两个用于设置 onClick 和 onLongClick 侦听器的抽象方法。
因此,这两个活动使用相同的数据和资源,主要区别在于可能的操作集。
问题:
ChildA开始了。来自 A other activity 在我有可能执行 child B 的地方被调用。此时一切都按预期工作:
A -> X -> B
当我使用后退按钮从 child B 导航回 child A 时出现问题:
A <- X <- B
在调试器中我看到了
一些 RecyclerView 中的卡片属于activity B,此时已经被销毁。由于这两个活动显示相同的数据 -
UI 看起来不错,但逻辑结果是 activity B 从 activity A 调用 onClick 回调,这不是我想要的。
代码:
Parent class 构造函数和回调:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
dbClass_ = new DBClass(this);
rv_ = (RecyclerView) findViewById(R.id.entity_list);
rv_.setLayoutManager(new LinearLayoutManager(this));
ListedEntityAdapter entityAdapter = new ListedEntityAdapter(this, dbClass_, this, this);
rv_.setAdapter(entityAdapter);
}
@Override
abstract public void onClick(View view);
@Override
abstract public boolean onLongClick(View view);
xml 中的 Recyclerview:
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:id="@+id/entity_list"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:showIn="@layout/activity_main">
class A:
的 OnClick 侦听器
@Override
public void onClick(View view) {
if ( contextHandler_.isActive() )
{
contextHandler_.setSelected( view );
} else {
TextView tv = (TextView)view.findViewById( R.id.listed_entity_name );
ShowDetailsActivity( (Long) tv.getTag( R.string.item_id_tag ), (Integer)tv.getTag( R.string.item_pos_tag ));
}
}
@Override
public boolean onLongClick(View view) {
startActionMode(contextHandler_);
contextHandler_.setSelected( view );
return true;
}
ShowDetailsActivity 有可能调用 activity B:
@Override
public void onClick(View view) {
int id = view.getId();
switch ( id )
{
[...]
case R.id.item_path:
Intent itemList = new Intent( this, B.class );
startActivityForResult( itemList, B.CONTAINER_CHOICE );
break;
[...]
}
最后 class B 有自己的回调,在这个阶段什么都不做:
@Override
public void onClick(View view) {
return;
}
@Override
public boolean onLongClick(View view) {
return true;
}
A 和 B 都没有定义构造函数(它们使用 parentclass 之一)。
谁能解释一下是什么原因导致了这种行为?
我的问题的答案似乎是在此处未发布的代码中。
在 Web ViewHolder 中可用的教程中,经常将其声明为静态的,我也这样做过。这是我的错误。
A 和 B 具有同一适配器的不同实例,该适配器引用了来自调用者的 onClick 回调。由于此引用是静态的 - 回调对所有实例都是通用的:
class ListedEntityAdapter extends
RecyclerView.Adapter<ListedEntityAdapter.ViewHolder> {
private static View.OnLongClickListener onLongCardClick;
private static View.OnClickListener onCardClick;
[...]
public ListedEntityAdapter(Context ctx, DBClass db, View.OnClickListener onClick, View.OnLongClickListener onLongClick ) {
onCardClick = onClick;
onLongCardClick = onLongClick;
[...]
}
public static class ViewHolder extends RecyclerView.ViewHolder {
[...]
private ViewHolder(View itemView) {
super(itemView);
itemView.setOnLongClickListener( onLongCardClick );
itemView.setOnClickListener( onCardClick );
[...]
}
}
}
这里的结果是发生了什么:
1) A创建并启动,适配器初始化参考A的回调
2) B activity 创建后启动,适配器初始化参考B的回调
3) 我们 return 到 A。由于未调用 A 的 onCreate,因此不会重新创建适配器,它运行良好,但需要注意一点:static onClick 回调不是B创建后改变。这就是为什么不同的适配器实例使用相同的回调。
相当愚蠢的错误已通过从适配器中的 ViewHolder 和回调成员中删除 'static' 得到修复。
首先-背景:
在我的应用程序中,我有两个非常相似的活动。它们都是通过 RecyclerView 显示的相同卡片的列表。区别在于不同的 onClick/onLongClick 侦听器和其中一个缺少上下文操作模式。
我通过制作两个 child 和一个 parent class 来实现它们,以容纳所有通用代码和两个用于设置 onClick 和 onLongClick 侦听器的抽象方法。
因此,这两个活动使用相同的数据和资源,主要区别在于可能的操作集。
问题:
ChildA开始了。来自 A other activity 在我有可能执行 child B 的地方被调用。此时一切都按预期工作:
A -> X -> B
当我使用后退按钮从 child B 导航回 child A 时出现问题:
A <- X <- B
在调试器中我看到了 一些 RecyclerView 中的卡片属于activity B,此时已经被销毁。由于这两个活动显示相同的数据 - UI 看起来不错,但逻辑结果是 activity B 从 activity A 调用 onClick 回调,这不是我想要的。
代码:
Parent class 构造函数和回调:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
dbClass_ = new DBClass(this);
rv_ = (RecyclerView) findViewById(R.id.entity_list);
rv_.setLayoutManager(new LinearLayoutManager(this));
ListedEntityAdapter entityAdapter = new ListedEntityAdapter(this, dbClass_, this, this);
rv_.setAdapter(entityAdapter);
}
@Override
abstract public void onClick(View view);
@Override
abstract public boolean onLongClick(View view);
xml 中的 Recyclerview:
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:id="@+id/entity_list"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:showIn="@layout/activity_main">
class A:
的 OnClick 侦听器@Override
public void onClick(View view) {
if ( contextHandler_.isActive() )
{
contextHandler_.setSelected( view );
} else {
TextView tv = (TextView)view.findViewById( R.id.listed_entity_name );
ShowDetailsActivity( (Long) tv.getTag( R.string.item_id_tag ), (Integer)tv.getTag( R.string.item_pos_tag ));
}
}
@Override
public boolean onLongClick(View view) {
startActionMode(contextHandler_);
contextHandler_.setSelected( view );
return true;
}
ShowDetailsActivity 有可能调用 activity B:
@Override
public void onClick(View view) {
int id = view.getId();
switch ( id )
{
[...]
case R.id.item_path:
Intent itemList = new Intent( this, B.class );
startActivityForResult( itemList, B.CONTAINER_CHOICE );
break;
[...]
}
最后 class B 有自己的回调,在这个阶段什么都不做:
@Override
public void onClick(View view) {
return;
}
@Override
public boolean onLongClick(View view) {
return true;
}
A 和 B 都没有定义构造函数(它们使用 parentclass 之一)。 谁能解释一下是什么原因导致了这种行为?
我的问题的答案似乎是在此处未发布的代码中。 在 Web ViewHolder 中可用的教程中,经常将其声明为静态的,我也这样做过。这是我的错误。
A 和 B 具有同一适配器的不同实例,该适配器引用了来自调用者的 onClick 回调。由于此引用是静态的 - 回调对所有实例都是通用的:
class ListedEntityAdapter extends
RecyclerView.Adapter<ListedEntityAdapter.ViewHolder> {
private static View.OnLongClickListener onLongCardClick;
private static View.OnClickListener onCardClick;
[...]
public ListedEntityAdapter(Context ctx, DBClass db, View.OnClickListener onClick, View.OnLongClickListener onLongClick ) {
onCardClick = onClick;
onLongCardClick = onLongClick;
[...]
}
public static class ViewHolder extends RecyclerView.ViewHolder {
[...]
private ViewHolder(View itemView) {
super(itemView);
itemView.setOnLongClickListener( onLongCardClick );
itemView.setOnClickListener( onCardClick );
[...]
}
}
}
这里的结果是发生了什么:
1) A创建并启动,适配器初始化参考A的回调
2) B activity 创建后启动,适配器初始化参考B的回调
3) 我们 return 到 A。由于未调用 A 的 onCreate,因此不会重新创建适配器,它运行良好,但需要注意一点:static onClick 回调不是B创建后改变。这就是为什么不同的适配器实例使用相同的回调。
相当愚蠢的错误已通过从适配器中的 ViewHolder 和回调成员中删除 'static' 得到修复。