从适配器调用 Activity 方法

Posted

技术标签:

【中文标题】从适配器调用 Activity 方法【英文标题】:Call Activity method from adapter 【发布时间】: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 解决您的案例 【参考方案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)

【讨论】:

以上是关于从适配器调用 Activity 方法的主要内容,如果未能解决你的问题,请参考以下文章

如何从android中的自定义适配器调用Activity asynctask

从适配器中的片段调用元素

ListView优化总结--Android

Android 暗黑模式快速适配

从 Fragment 获取 Activity 中的适配器

获取错误:为viewPager适配器执行notifyDataSetChanged时出现“java.lang.IllegalStateException:Activity已被销毁”