代码之家  ›  专栏  ›  技术社区  ›  George Keeper

调用已销毁活动的OnClick回调

  •  0
  • George Keeper  · 技术社区  · 7 年前

    首先-背景:

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

    我通过制作两个child来实现它们,其中一个父类包含所有通用代码和两个抽象方法,用于设置onClick和onLongClick侦听器。

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

    问题:

    子A已启动。从另一个名为“我有可能执行子B”的活动开始。此时,一切都按预期进行:

    A->X->B

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

    十、 <-

    在调试器中我看到了 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);
    

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

    OnClick A级听众:

    @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都没有定义构造函数(它们使用父类之一)。 有人能解释一下是什么导致了这种行为吗?

    1 回复  |  直到 7 年前
        1
  •  0
  •   George Keeper    7 年前

    我的问题的答案似乎是用代码写的,但并没有贴在这里。 在web上提供的教程中,ViewHolder经常被声明为静态的,我也这么做了。这是我的错误。

    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) 一个已创建并启动的适配器已初始化,它引用了的回调。

    3) 我们返回到A。由于未调用A的创建,因此未重新创建适配器,它运行良好,只需一句话: 静止的

    这是一个相当愚蠢的错误,通过在适配器中从ViewHolder和回调成员中删除“static”来修复。