【问题标题】:Call Activity method from adapter从适配器调用 Activity 方法
【发布时间】:2012-08-21 22:58:28
【问题描述】:

是否可以从ListAdapter调用Activity中定义的方法?

(我想在list's 行中创建一个Button,当单击此按钮时,它应该执行相应活动中定义的方法。我试图在我的ListAdapter 中设置onClickListener 但是这个方法我不知道怎么调用,它的路径是什么……)

当我使用Activity.this.method() 时出现以下错误:

No enclosing instance of the type Activity is accessible in scope

有什么想法吗?

【问题讨论】:

  • 您不能在其他类中调用activity.this,除非它是该活动的内部类。按照@Eldhose M Babu 解决您的案例

标签: android list adapter addressing


【解决方案1】:

是的,你可以。

在适配器中添加一个新字段:

private Context mContext;

在适配器构造函数中添加以下代码:

public AdapterName(......, Context context) {
  //your code.
  this.mContext = context;
}

在Adapter的getView(...)中:

Button btn = (Button) convertView.findViewById(yourButtonId);
btn.setOnClickListener(new Button.OnClickListener() {
  @Override
  public void onClick(View v) {
    if (mContext instanceof YourActivityName) {
      ((YourActivityName)mContext).yourDesiredMethod();
    }
  }
});

在您看到代码、活动等的地方替换为您自己的类名。

如果您需要将同一个适配器用于多个活动,那么:

创建接口

public interface IMethodCaller {
    void yourDesiredMethod();
}

在需要此方法调用功能的活动中实现此接口。

然后在Adapter getView()中,调用如下:

Button btn = (Button) convertView.findViewById(yourButtonId);
btn.setOnClickListener(new Button.OnClickListener() {
    @Override
    public void onClick(View v) {
        if (mContext instanceof IMethodCaller) {
            ((IMethodCaller) mContext).yourDesiredMethod();
        }
    }
});

你已经完成了。如果您需要将此适配器用于不需要此调用机制的活动,则代码将不会执行(如果检查失败)。

【讨论】:

  • 由于这是一个热门问题,我强烈建议不要使用此解决方案。您应该避免在这里进行类转换,因为这可能会导致运行时异常。
  • Eldhose 兄弟,我对你没有意见,但下面的回答是最佳做法。您甚至可以在 cmets 中阅读。您不应该将 mContext 强制转换为您的 Activity,因为您避免重复使用代码。现在这个适配器只能在你已经将你的 mContext 变量转换到的 Activity 中使用,如果你定义了一个监听器,那么你可以在另一个 Activity 中重用相同的适配器。相信我,我已经在行业中度过了足够的时间,我只是想在这里为您提供帮助,请不要将其视为个人。
  • 这个解决方案是我在 SO 上找到的最好的解决方案之一。非常感谢巴布先生。通过这种方式调用 Activity 的方法,使整个应用程序的性能提升 500% -> 我不需要在适配器中重新加载数据库,我需要访问它。我不关心“行业年限”,我正在寻找稳定且有效的解决方案,我很确定,我不会找到更好的访问方式。也许我可以将数据库设置为单例,但这不是我想要“解构”我的项目的方式。
  • @RAM 如果您需要在多个活动中调用相同的方法,则需要使用该方法名称创建一个接口。然后在您需要使用方法调用的所有活动中实现该接口。然后在点击监听器中,检查你的接口实例而不是使用活动名称。
  • 绝妙的答案。竖起大拇指
【解决方案2】:

你可以这样做:

声明接口:

public interface MyInterface{
    public void foo();
}

让你的 Activity 实现它:

    public class MyActivity extends Activity implements MyInterface{
        public void foo(){
            //do stuff
        }
        
        public onCreate(){
            //your code
            MyAdapter adapter = new MyAdapter(this); //this will work as your 
                                                     //MyInterface listener
        }
    }

然后将您的活动传递给 ListAdater:

public MyAdapter extends BaseAdater{
    private MyInterface listener;

    public MyAdapter(MyInterface listener){
        this.listener = listener;
    }
}

在适配器中的某个地方,当您需要调用该 Activity 方法时:

listener.foo();

【讨论】:

  • 我首先想到了上面的方法,就像你对片段一样,但这是最好的解决方案!
  • 我的 InterfaceListener 是什么?如何初始化它? public MyAdapter(MyInterface listener){ this.listener = listener; }
  • 你如何将接口传递给适配器(来自 Activity)
  • @Brandon ,只需添加 'this' 将接口传递给适配器 myAdapter = new MyAdapter(this);
  • 我的适配器中的 NullPointerException 扩展了 RealmBaseAdapter
【解决方案3】:

原文:

我了解当前的答案,但需要一个更清晰的示例。这是我使用 Adapter(RecyclerView.Adapter) 和 Activity 的示例。

在您的活动中:

这将实现我们在Adapter 中的interface。在这个例子中,当用户点击RecyclerView中的一个项目时,它会被调用。

public class MyActivity extends Activity implements AdapterCallback {

    private MyAdapter myAdapter;

    @Override
    public void onMethodCallback() {
       // do something
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        myAdapter = new MyAdapter(this);
    }
}

在您的适配器中:

Activity 中,我们启动了Adapter 并将其作为参数传递给构造函数。这将为我们的回调方法启动我们的interface。您可以看到我们使用我们的回调方法进行用户点击。

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {

    private AdapterCallback adapterCallback;

    public MyAdapter(Context context) {
        try {
            adapterCallback = ((AdapterCallback) context);
        } catch (ClassCastException e) {
            throw new ClassCastException("Activity must implement AdapterCallback.", e);
        }
    }

    @Override
    public void onBindViewHolder(MyAdapter.ViewHolder viewHolder, int position) {
        // simple example, call interface here
        // not complete
        viewHolder.itemView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                try {
                    adapterCallback.onMethodCallback();
                } catch (ClassCastException e) {
                   // do something
                }
            }
        });
    }

    public static interface AdapterCallback {
        void onMethodCallback();
    }
}

【讨论】:

  • 感谢您,这正是我想要的。投票赞成
  • 这对我有用! imo,迄今为止最完整的工作代码!
  • 感谢您的解决方案
  • 这个答案应该有更多的支持,这是一个干净而完美的解决方案。
  • 嗨@Jared - 你能按照你的建议用EventBus 修正同一个样本吗?
【解决方案4】:

基本而简单。

在您的适配器中简单地使用它。

((YourParentClass) context).functionToRun();

【讨论】:

  • 这不是一个好习惯,因为您将类限制为仅使用 YourParentClass 类型而不是任何类,但如果您不关心重用它,如果您还重命名一个类,代码就会中断.. .
【解决方案5】:

对于 Kotlin:

在您的适配器中,只需调用

(context as Your_Activity_Name).yourMethod()

【讨论】:

    【解决方案6】:

    另一种方法是::

    在你的适配器中写一个方法让我们说 public void callBack(){}。

    现在在为活动中的适配器创建对象时覆盖此方法。 调用adapter中的方法时会调用override方法。

    Myadapter adapter = new Myadapter() {
      @Override
      public void callBack() {
        // dosomething
      }
    };
    

    【讨论】:

      【解决方案7】:

      在 Kotlin 中,现在有一种更简洁的方式,即使用 lambda 函数,无需接口:

      class MyAdapter(val adapterOnClick: (Any) -> Unit) {
          fun setItem(item: Any) {
              myButton.setOnClickListener { adapterOnClick(item) }
          }
      }
      
      class MyActivity {
          override fun onCreate(savedInstanceState: Bundle?) {
              var myAdapter = MyAdapter { item -> doOnClick(item) }
          }
      
      
          fun doOnClick(item: Any) {
      
          }
      }
      

      【讨论】:

        【解决方案8】:
        if (parent.getContext() instanceof yourActivity) {
          //execute code
        }
        

        如果具有 GroupView 的 Activity 从您的 adaptergetView() 方法请求视图的 Activity 是 yourActivity,则此条件将使您能够执行某些操作。

        注意:parent 是 GroupView

        【讨论】:

        • 这个 GroupView 在调用 getView() 方法时向适配器请求视图.....所以我们得到那个 GroupView 的上下文,并通过上面的条件检查它
        【解决方案9】:

        对于 kotlin,您可以执行以下操作:

        if(context is MainActivity){ context.functionToCall(values) }

        【讨论】:

          猜你喜欢
          • 2015-03-16
          • 2021-06-08
          • 2021-12-01
          • 2021-07-16
          • 1970-01-01
          • 1970-01-01
          • 2018-11-07
          • 1970-01-01
          相关资源
          最近更新 更多