【问题标题】:OnClick callback of destroyed activity is called销毁活动的 OnClick 回调被调用
【发布时间】:2017-09-17 17:01:55
【问题描述】:

首先 - 背景:

在我的应用程序中,我有两个非常相似的活动。它们都是通过 RecyclerView 显示的相同卡片的列表。不同之处在于不同的 onClick/onLongClick 侦听器以及其中一个侦听器缺少上下文操作模式。

我通过创建两个子类来实现它们,其中一个父类容纳所有常见代码,两个抽象方法用于设置 onClick 和 onLongClick 侦听器。

因此,两个活动都使用相同的数据和资源,主要区别在于可能的操作集。

问题:

孩子 A 开始了。在我有可能执行子 B 的地方调用了其他活动。此时一切都按预期工作:

A -> X -> B

当我使用后退按钮从子 B 导航回子 A 时出现问题:

A X B

在调试器中我看到 RecyclerView 中的一些卡片属于此时已销毁的活动 B。由于两个活动都显示相同的数据 - UI 看起来不错,但这样做的逻辑结果是从活动 A 调用活动 B 的 onClick 回调,这不是我想要的。

代码:

父类构造函数和回调:

@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 中的回收站视图:

<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">

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 有可能调用活动 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;
        [...]
    }

最后,B 类有自己的回调,在这个阶段什么都不做:

@Override
public void onClick(View view) {
    return;
}

@Override
public boolean onLongClick(View view) {
    return true;
}

A 和 B 都没有定义构造函数(它们使用父类之一)。 有人可以解释一下导致这种行为的原因吗?

【问题讨论】:

  • 请添加完整代码
  • @nomag,我添加了更多代码。希望这就足够了(我真的怀疑其他部分是否重要,不想发布太多分散注意力的细节)

标签: android android-recyclerview onclicklistener activity-lifecycle


【解决方案1】:

我的问题的答案似乎在此处未发布的代码中。 在 web ViewHolder 提供的教程中,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)我们回到A。适配器没有重新创建,因为A的onCreate没有被调用,它运行良好,有一点:静态 onClick回调在B创建后没有改变。这就是为什么不同的适配器实例使用相同的回调。

相当愚蠢的错误已通过从 ViewHolder 和适配器中的回调成员中删除“静态”来修复。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-20
    • 2022-12-06
    • 1970-01-01
    • 2018-01-24
    相关资源
    最近更新 更多