从适配器调用活动方法


119

是否可以调用Activityfrom中定义的方法ListAdapter

(我想打一个Buttonlist's行单击此按钮时,它应该执行的方法,即在相应的活动定义。我试图设置onClickListener在我ListAdapter,但我不知道该怎么称呼这种方法,什么是它的路径。 ..)

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

No enclosing instance of the type Activity is accessible in scope

任何想法 ?


您不能在其他类中调用activity.this,除非它是该活动的内部类。按照您的情况使用@Eldhose M Babu解决方案
Archie.bpgc 2012年

Answers:


306

是的你可以。

在适配器中添加新字段:

private Context mContext;

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

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

在适配器的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();
        }
    }
});

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


29
由于这是一个很普遍的问题,因此我强烈建议不要使用此解决方案。您应该避免在此进行类转换,因为这可能会导致运行时异常。
Igor Filippov 2014年

3
Eldhose兄弟,我没有反对您的意见,但以下答案是最佳做法。您甚至可以阅读评论。为避免重复使用代码,请勿将mContext强制转换为Activity。现在,此适配器只能在将mContext变量强制转换到的Activity内使用,如果定义了侦听器,则可以在另一个Activity中重用同一适配器。相信我,我已经在行业中花费了足够的时间,我只是想在这里为您提供帮助,请不要个人对待。
Varundroid 2014年

2
该解决方案是我在SO上找到的最好的解决方案之一。非常感谢Babu先生。通过这样调用Activity的方法,可使整个应用程序的性能提高500%->我不需要在适配器中重新加载数据库,而我需要访问该数据库。我不在乎“行业多年”,我正在寻找稳定且可行的解决方案,并且我很确定,我不会找到更好的访问方式。也许我可以将数据库设置为单例,但这不是我要“取消组织”项目的方式。
Martin Pfeffer

2
@RAM如果您需要在多个活动中调用同一方法,则需要使用该方法名称创建一个接口。然后在需要使用方法调用的所有活动中实现该接口。然后在点击监听器中,检查界面实例,而不使用活动名称。
Eldhose M Babu 2015年

1
极好的答案。竖起大拇指
Alok Rajasukumaran

126

您可以这样操作:

声明界面:

public interface MyInterface{
    public void foo();
}

让您的活动实现它:

public class MyActivity extends Activity implements MyInterface{
    public void foo(){
        //do stuff
    }
}

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

public MyAdapter extends BaseAdater{
    private MyInterface listener;

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

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

listener.foo();

5
我首先想到了上面的方法,就像处理碎片一样,但这是最好的解决方案!
brux

1
我的InterfaceListener是什么?怎么初始化呢?public MyAdapter(MyInterface listener){this.listener = listener; }
Gilberto Ibarra 2014年

6
您如何通过接口将接口传递给适配器(来自“活动”)
Brandon 2015年

1
@Brandon您可以传递它是适配器中的构造函数参数。
伊戈尔·菲利波夫

5
@Brandon,只需添加'this'即可将接口传递给适配器myAdapter = new MyAdapter(this);
ajinkya '16

67

原版的:

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

在您的活动中:

这将实现interface我们在中具有的Adapter。在此示例中,当用户单击中的项目时,将调用它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();
    }
}

6
谢谢,这正是我想要的。投票
Nactus

这对我有用!imo,到目前为止最完整的工作代码!
publicknowledge

2
感谢您的解决方案
史蒂夫(Steve)

4
这个答案应该有更多的支持,这是一个干净而完美的解决方案。
Opiatefuchs

嗨,@ Jared-您可以EventBus按照您的建议修改相同的样本吗?
Tohid

14

基本而简单。

在您的适配器中,只需使用它。

((YourParentClass) context).functionToRun();


4
这不是一个好习惯,因为您将类限制为只能与YourParentClass类型一起使用,而不是与任何类一起使用,但是如果您不关心重用它,则可以工作,如果您还重命名了一个类,代码就会中断...
Gustavo Baiocchi Costa

7

另一种方法是:

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

现在,在活动中为适配器创建对象时,请覆盖此方法。当您在适配器中调用该方法时,将调用Override方法。

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

5

对于Kotlin:

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

(context as Your_Activity_Name).yourMethod()

0
if (parent.getContext() instanceof yourActivity) {
  //execute code
}

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

注意:parent是GroupView


该GroupView在调用getView()方法时从适配器请求视图.....,因此我们获取了该GroupView的上下文,并通过上述条件对其进行了检查
Abd Salam Baker

0

在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) {

    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.