假设我们有一个活动,其中有很多关于OnClickListener
要注册的观点。
实现这一点的最常用方法是让Activity-Subclass实现OnClickListener,如下所示:
public class ActivityMain extends Activity implements View.OnClickListener
{
@Override
public void onClick(View view)
{
switch (view.getId())
{
//handle multiple view click events
}
}
}
我喜欢实现它的方法是在Activity-Subclass中创建一个私有类,然后让它成为内部类 实现OnClickListener:
public class ActivityMain extends Activity implements View.OnClickListener
{
private class ClickListener implements View.OnClickListener
{
@Override
public void onClick(View view)
{
switch (view.getId())
{
//handle multiple view click events
}
}
}
}
这样代码看起来更有条理,易于维护。
此外,谈论" Is-a"," Has-a"关系,后者似乎是一个很好的实践,因为现在 Activity-Subclass会有一个" Has-a"与ClickListener的关系。 在前一种方法中,我们会说我们的活动 - 子类" Is-a" ClickListener,它不完全正确。
请注意,我并不关心后者会导致的内存开销。
另外,在xml中添加onClick标记是完全不可能的。
那么,实现ClickListener的最佳方法是什么?
请不要建议像RoboGuice或ButterKnife等图书馆。
更新
我想分享一下我最终采用的方法。
我在Activity / Fragment中直接实现了监听器。
就OOP设计而言。 " HAS-A" 方法不会带来任何实际好处,甚至会占用更多内存。考虑到我们将为我们实现的每个类似侦听器创建的嵌套类的数量(以及内存开销),应该明确避免这种方法。
答案 0 :(得分:44)
首先,Android没有定义关于注册点击侦听器的最佳实践。这完全取决于您的使用案例。
实现Activity的View.OnClickListener
接口是可行的方法。因为Android强烈推荐一遍又一遍地实现接口实现,无论它是Activity还是Fragment。
现在如你所述:
public class ActivityMain extends Activity implements View.OnClickListener
{
private class ClickListener implements View.OnClickListener
{
@Override
public void onClick(View view)
{
switch (view.getId())
{
//handle multiple view click events
}
}
}
}
这是你的方法。现在这是你的实现方式,如果你不关心内存开销,这没有什么不妥。但是如果您可以在主类中实现它,那么创建内部类和实现View.OnClickListener
的好处是什么,这也可以导致代码清晰度和简单性。
所以这只是一个讨论,而不是获得实现 View.OnClickListener 的最佳解决方案,因为如果你按照每个人的实际观点,你将寻求一个简单且内存有效的解决方案
所以我更喜欢传统方式。它使事情变得简单而有效。检查以下代码:
@Override
public void onClick(View view)
{
switch (view.getId())
{
//handle multiple view click events
}
}
P.S:你的方法肯定会增加代码行数:P;)
答案 1 :(得分:8)
首先让我们清楚地了解基础知识..
通过实现一个接口,你的课程不会变成那样......就像你说的那样:
“我们的活动 - 子类”是一个“ClickListener,这不完全正确。”
如果您的课程延伸,则该课程只能具有“Is-a”关系,在本例中为Func fn=new Func(Fn); // hidden by syntactic sugar
。实现接口意味着它可以像接口设置合同一样。
一个例子:
班彼得延伸人类..意味着彼得是人类......
彼得班也可以实现程序员,音乐家,丈夫等 意味着彼得可以表现得如上所述。至于最佳实践,你可以创建一个完全独立的类来实现Activity
,如下所示:
OnClickListener
在您的主class MyListener implements View.OnClickListener{
@Override
public void onClick(View view) {
// do whatever you want here based on the view being passed
}
}
中,您可以实例化Activity
并致电MyListener
并传递您的观点:
onClick()
答案 2 :(得分:6)
我在我的<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@color/background_material_light"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="@+id/toolbar_actionbar"
layout="@layout/toolbar_default"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/toolbar_actionbar">
<view
android:layout_width="match_parent"
android:layout_height="match_parent"
class="it.gmariotti.cardslib.library.recyclerview.view.CardRecyclerView"
android:id="@+id/recycler" />
</android.support.v4.widget.SwipeRefreshLayout>
</RelativeLayout>
button.setOnClickListener(this);
中使用Activity
,然后在单独的方法中获取implements View.OnClickListener
的ID。请参阅下面的示例:
Button
答案 3 :(得分:5)
在这里你可以创建一个btnClickListner对象,然后在你想要为按钮执行onCLieck操作时调用那个btnCLickLisner对象。
让我们假设,在我的活动中,我有一个5到10个按钮,每个按钮单独写一个onclick listner是个坏主意。所以要过来这个,我们可以像下面这样使用..
注册您的按钮
Button button1 = (Button)findViewById(R.id.button1);
Button button2 = (Button)findViewById(R.id.button2);
Button button3 = (Button)findViewById(R.id.button3);
Button button4 = (Button)findViewById(R.id.button4);
Button button5 = (Button)findViewById(R.id.button5);
这里我点击了
后将onclick listner设置为我的按钮button1.setOnClickListener(btnClickListner);
button2.setOnClickListener(btnClickListner);
button3.setOnClickListener(btnClickListner);
button4.setOnClickListener(btnClickListner);
button5.setOnClickListener(btnClickListner);
这是btnClick Listner实现
View.OnClickListener btnClickListner = new OnClickListener()
{
@Override
public void onClick( View v )
{
// TODO Auto-generated method stub
if( button1.getId() == v.getId() )
{
//Do Button1 click operations here
}
else if( button2.getId() == v.getId() )
{
// Do Button2 click operations here
}
else if( button3.getId() == v.getId() )
{
// Do Button3 click operations here
}
else if( button4.getId() == v.getId() )
{
// Do Button4 click operations here
}
else if( button5.getId() == v.getId() )
{
// Do Button5 click operations here
}
}
}
答案 4 :(得分:4)
我发现使用Butterknife制作干净的代码。而且因为它使用代码生成(而不是反射),所以它几乎没有性能开销。
public class ActivityMain extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.inject(this);
}
@OnClick(R.id.button_foo)
void onFoodClicked() {
// Do some foo
}
@OnClick(R.id.button_bar)
void onBarClicked() {
// do some bar
}
}
答案 5 :(得分:2)
您的$('.button').click(function (event) {
$(window).bind("scroll", someFunction);
}
someFunction = function() {
//do stuff
$(window).unbind("scroll"); // remove scroll listener
}
是一个内部非静态类,此'has-a'的耦合与您的类ClickListener
实现Activity
的情况没有什么不同。这是因为您的内部View.OnClickListener
需要ClickListener
的实例,并且实际上无法重复使用。我认为你过度工程,实际上并没有获得任何东西。
编辑:要回答您的问题,我希望每个小部件都有匿名ActivityMain
。我认为这创造了最好的逻辑分离。我也有类似View.OnClickListener
的方法,我把所有逻辑都放在那个小部件上。
答案 6 :(得分:2)
第一种方法比另一种更好,因为View.OnClickListener
为Interface
而不是abstract class
。除了后者可能在各种情况下泄漏,因为你使用的是非静态内部类。
答案 7 :(得分:2)
对此的一点点评论,也许是一些话题。
什么,如果我们不只是实现OnClickListener,我们有一堆其他的Listeners / Callback来实现。在我的意见中,在类中实现所有这些而不是使用匿名类/ lambda将变得混乱。很难记住哪个方法属于哪个接口。
因此,如果我们必须多次实现一个接口(在本例中为OnClickListener),那么在类基础上实现并使用switch / case是一个很好的解决方案。
但是如果我们必须实现多个接口,那么使用匿名类/ lambda
可能是一个很好的解决方案答案 8 :(得分:1)
对于这种特殊情况,我会说维护OnClickListener的单个实例是最适合您的方法。您将拥有“Has-a”关系,因为您使用onClick(View view)
回调中的视图ID处理行为,所以不需要创建多个实例。
public class ActivityMain extends Activity implements View.OnClickListener {
private View.OnClickListener mClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
switch (view.getId()) {
//handle multiple view click events
}
}
};
}
答案 9 :(得分:1)
只是你使用like not implements子类或不处理click事件就像这样做。
android.view.View.OnClickListener method_name = new android.view.View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
// put your code .
}
};
并将点击事件处理为按钮ya任何类型的点击事件,如
button_name.setOnClickListener(method_name);
它的工作非常简单 感谢
答案 10 :(得分:0)
It really depends on what you want to achieve. If you have e.g. a complex functionality with threading, dependencies, etc., I personally like to decouple it completely from the Activity into a separate class themeProvider.reload($injector);
, that does the heavy stuff, knows about certain XyzAction
s and returns them results, if needed. My Invoker
s are basically objects, that implement Invoker
/OnClick
/etc.OnTouch
s and bind themselves to needed actions. E.g. there could be a Listener
implementing LoginInvoker
for a OnClickListener
and an Button
and also a generic ImageView
that gets invoked when a ActionListener
is clicked. The MenuItem
has update methods for showing progress to the user and the result of the bound action. The action posts updates to its Invoker
s and can be garbage collected, if all of them die, because it has no connection to the UI.
For less complex actions, I couple them directly to the Android component (i.e. Invoker
/Activity
/Feagment
) and also call them View
, with the big difference of them implementing the UI callbacks directly.
In both cases I declare the actions as members, so I can see on a quick glance what specific actions the Android component supports.
If there's something trivial like "show a Toast if button is pressed", I use anonymous inner classes for the UI callbacks, because you normally don't care that much about them with regards to maintainability.
答案 11 :(得分:0)
public class ProfileDetail extends AppCompatActivity implements View.OnClickListener {
TextView tv_address, tv_plan;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile_detail);
tv_address = findViewById(R.id.tv_address);
tv_plan = findViewById(R.id.tv_plan);
tv_address.setOnClickListener(this);
tv_plan.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.tv_plan:
startActivity(new Intent(getApplicationContext(),PlanActivity.class));
break;
case R.id.tv_address:
startActivity(new Intent(getApplicationContext(),AddressActivity.class));
break;
}
}
}
答案 12 :(得分:0)
swap(1, 2)
答案 13 :(得分:0)
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Chronometer chronometer;
private Button startButton;
private Button stopButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
chronometer = findViewById(R.id.chronometer);
startButton =findViewById(R.id.startBtn);
stopButton = findViewById(R.id.stopBtn);
startButton.setOnClickListener(this);
stopButton.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.startBtn:
chronometer.start();
break;
case R.id.stopBtn:`
chronometer.stop();
break;
}
}
}