- 方式一:在布局文件的控件上设置onClick属性
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">
<Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="sayHello" android:text="HELLO"/>
</LinearLayout>
在源文件中绑定点击事件:
/** * ============================================================================= * Copyright (c) 2016 yuxin All rights reserved. * Packname work * Created by yuxin. * Created time 2016/9/21 0021 上午 8:38. * Version 1.0; * Describe : * History: * ============================================================================== */
public class LoginOkActivity2 extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dome);
}
public void doClick(View view) {
//do something
}
}
这种方式代码简洁,结构清晰,唯一的缺点是android:onClick注册在debug时能运行正常,切换成release版本时release版本通常会混淆代码,方法的名称就改变了,所以这种方式虽然简单,但是不推荐。
在介绍后面几种方法前我们先提下java中方法的回调,下面这图是我对回调的理解:
如果还没看懂或则觉得我的理解有问题的,可以baidu看下别人的解释
- 方式二:匿名内部类作为事件监听器类
/** * ============================================================================= * Copyright (c) 2016 yuxin All rights reserved. * Packname com.jju.yuxin.disanzhou * Created by yuxin. * Created time 2016/9/21 0021 上午 10:50. * Version 1.0; * Describe : * History: * ============================================================================== */
public class ClickDome extends Activity {
private Button bt_click;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_click);
bt_click = (Button) findViewById(R.id.bt_click);
bt_click.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//do something
}
});
}
}
很多监听事件只是临时的使用一次,或则有的一类监听操作只有一个控件执行,那么可以使用这种,也是使用比较广泛的一种监听方式,但是对于java来说,这种耦合有点紧,没有模块化的。
- 方式三:内部类作为监听器
public class ClickDome extends Activity {
private Button bt_click;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_click);
bt_click = (Button) findViewById(R.id.bt_click);
MyClickListener listtener = new MyClickListener():
bt_click.setOnClickListener(listtener);
}
private class MyClickListener implements View.OnClickListener {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt_click:
break;
default:
break;
}
}
}
}
当然也可以将内部类放置出来另写一个监听类,这种方式在java上符合单一职责原则,耦合度低,但是带来的确实更多的代码编写量,庆幸的是带来了可复用性,只要同一类监听操作我们都只传入一个监听类对象搞定,然后在switch中写上代码,但是记得的是,不同的activity千万别放在一个监听类里面操作,可能一时爽,痛苦起来会发疯。
- 方式四:Activity继承监听事件,Activity本身作为事件监听器
/** * ============================================================================= * Copyright (c) 2016 yuxin All rights reserved. * Packname com.jju.yuxin.disanzhou * Created by yuxin. * Created time 2016/9/21 0021 上午 10:50. * Version 1.0; * Describe : * History: * ============================================================================== */
public class ClickDome extends Activity implements View.OnClickListener {
private Button bt_click;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_click);
bt_click = (Button) findViewById(R.id.bt_click);
bt_click.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt_click:
//do something
break;
default:
break;
}
}
}
这种方法其实和上面的方式三差不多,在这种方式里,监听类的对象都不用new了,因为就是本身,传入一个this就行了,但是你不觉得Activity一个界面类来实现监听接口有点不伦不类嘛?
综合上面四种方式,各有各的优势与劣势,在实际场景中灵活运用才是正道。
这博客就写完了嘛??不不不,,本博主和哪些妖艳贱货不一样,肯定要写点其他的东西啊,不然前面的方法回调不是白白铺垫了嘛,我们仔细的看下后面三种方式,其实原理都一样,都是为了实现onClick()这个方法,我们来看下setOnClickListener();这个方法,因为Buttom是View的子类,我们看下View里面的setOnClickListener()方法,
/** * Register a callback to be invoked when this view is clicked. If this view is not * clickable, it becomes clickable. * * @param l The callback that will run * * @see #setClickable(boolean) */
public void setOnClickListener(@Nullable OnClickListener l) {
if (!isClickable()) {
setClickable(true);
}
getListenerInfo().mOnClickListener = l;
}
他就做了两件事情,一、把控件置为可点击的,二、将OnClickListener 对象赋值给getListenerInfo方法里面的mOnClickListener属性,我们看下这两个方法:
/**
* Enables or disables click events for this view. When a view
* is clickable it will change its state to "pressed" on every click.
* Subclasses should set the view clickable to visually react to
* user's clicks.
*
* @param clickable true to make the view clickable, false otherwise
*
* @see #isClickable()
* @attr ref android.R.styleable#View_clickable
*/
public void setClickable(boolean clickable) {
setFlags(clickable ? CLICKABLE : 0, CLICKABLE);
}
他在这里立了个flag
ListenerInfo getListenerInfo() {
if (mListenerInfo != null) {
return mListenerInfo;
}
mListenerInfo = new ListenerInfo();
return mListenerInfo;
}
这里也是非空判断下,返回个属性
这下我慌了,下一步它往哪里走呢??后来我看到了这个方法boolean performAccessibilityActionInternal(int action, Bundle arguments)
(名字有点长)
/** * @see #performAccessibilityAction(int, Bundle) * * Note: Called from the default {@link AccessibilityDelegate}. * * @hide */
public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
.
.
.
.
switch (action) {
case AccessibilityNodeInfo.ACTION_CLICK: {
if (isClickable()) {
performClick();
return true;
}
} break;
.
.
.
return false;
}
中间其他的我们都不关系,我们看下注释Note: Called from the default {@link AccessibilityDelegate}.大概意思就是说它会被另一个方法默认调用,我们看下switch
/** * Indicates whether this view reacts to click events or not. * * @return true if the view is clickable, false otherwise * * @see #setClickable(boolean) * @attr ref android.R.styleable#View_clickable */
@ViewDebug.ExportedProperty
public boolean isClickable() {
return (mViewFlags & CLICKABLE) == CLICKABLE;
}
这个isClickable()就是返回之前setClickable()的值,我记得方法一进来就设置为了true,那我们看下performClick();
/** * Call this view's OnClickListener, if it is defined. Performs all normal * actions associated with clicking: reporting accessibility event, playing * a sound, etc. * * @return True there was an assigned OnClickListener that was called, false * otherwise is returned. */
public boolean performClick() {
final boolean result;
final ListenerInfo li = mListenerInfo;
if (li != null && li.mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
li.mOnClickListener.onClick(this);
result = true;
} else {
result = false;
}
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
return result;
}
其他的都不重要。我们看到它通过各种传递和判断,将我们传进来的OnClickListener对象调用它的onClick()方法;。。而我们来看下onClick()
/** * Interface definition for a callback to be invoked when a view is clicked. */
public interface OnClickListener {
/** * Called when a view has been clicked. * * @param v The view that was clicked. */
void onClick(View v);
}
他是View类里面的OnClickListener接口的一个没有实现的方法,而这个方法就是我们在监听类里面实现的void onClick(View v)方法,结合之前的方法回调的图,这个应该知道工作模式了把!
关于绑定监听事件的原理应该是在LayoutInflater.from(this).inflate();实现,里面有对资源XML的解析生成View树图,但是原理我还没看,有兴趣的可以自己看下
我的博客网站http://huyuxin.top/欢迎大家访问!评论!