从适配器调用 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 从您的 adapter
的 getView()
方法请求视图的 Activity 是 yourActivity
,则此条件将使您能够执行某些操作。
注意:parent
是 GroupView
【讨论】:
这个 GroupView 在调用getView()
方法时向适配器请求视图.....所以我们得到那个 GroupView 的上下文,并通过上面的条件检查它【参考方案9】:
对于 kotlin,您可以执行以下操作:
if(context is MainActivity) context.functionToCall(values)
【讨论】:
以上是关于从适配器调用 Activity 方法的主要内容,如果未能解决你的问题,请参考以下文章
如何从android中的自定义适配器调用Activity asynctask
获取错误:为viewPager适配器执行notifyDataSetChanged时出现“java.lang.IllegalStateException:Activity已被销毁”