#Button使用
平时,我们开发,Button控件一般就是如下使用:
先在布局文件中定义Button控件:
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TestButton" />
再在java文件中使用此Button控件:
//定义Button
private Button button = null;
//定义接口OnClickListener
private View.OnClickListener onClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i(TAG,"View.OnClickListener--onClick");
}
};
//获取button对象
button = (Button)findViewById(R.id.button);
//设置button点击事件监听接口
button.setOnClickListener(onClickListener);
执行程序,当button点击时,执行接口OnClickListener中的onClick方法,打印Log:
View.OnClickListener--onClick
#android是怎么样设计此功能的
我们查看源码—View.java
OnClickListener 接口定义:
因此,响应点击Button后的操作,各个控件,各个场景都不一样,是一个可变的动作,所以android定义了一个接口OnClickListener来应对这个可变的因素:
public interface OnClickListener {
/**
* Called when a view has been clicked.
*
* @param v The view that was clicked.
*/
void onClick(View v);
}
定义内部的OnClickListener变量mOnClickListener:
/**
* Listener used to dispatch click events.
* This field should be made private, so it is hidden from the SDK.
* {@hide}
*/
public OnClickListener mOnClickListener;
setOnClickListener方法:
public void setOnClickListener(OnClickListener l) {
if (!isClickable()) {
setClickable(true);
}
//给mOnClickListener变量赋值
getListenerInfo().mOnClickListener = l;
}
执行click的方法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);
//执行点击的回调方法onClick
li.mOnClickListener.onClick(this);
result = true;
} else {
result = false;
}
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
return result;
}
执行click的方法callOnClick:
/**
* Directly call any attached OnClickListener. Unlike {@link #performClick()},
* this only calls the listener, and does not do any associated clicking
* actions like reporting an accessibility event.
*
* @return True there was an assigned OnClickListener that was called, false
* otherwise is returned.
*/
public boolean callOnClick() {
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnClickListener != null) {
//执行点击的回调方法onClick
li.mOnClickListener.onClick(this);
return true;
}
return false;
}
点击button是在什么时候点击监听回调接口:
boolean performAccessibilityActionInternal(int action, Bundle arguments) {
switch (action) {
//ACTION_CLICK 点击Button
case AccessibilityNodeInfo.ACTION_CLICK: {
if (isClickable()) {
//执行点击button监听接口
performClick();
return true;
}
} break;
......
......
public boolean onTouchEvent(MotionEvent event) {
......
//可以点击
if (((viewFlags & CLICKABLE) == CLICKABLE ||
(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
switch (event.getAction()) {
//button ACTION_UP
case MotionEvent.ACTION_UP:
......
if (mPerformClick == null) {
mPerformClick = new PerformClick();
}
if (!post(mPerformClick)) {
//执行点击button监听接口
performClick();
}
......
#再修改Button使用方法:
我们为了让大家真正看明白android为什么如此设计Button是这样响应点击事件,我们再定义一个MyButtonOnClickListener类:
//类MyButtonOnClickListener实现接口View.OnClickListener,实现方法onClick:
public class MyButtonOnClickListener implements View.OnClickListener {
public static final String TAG = "MyButtonOnClickListener";
@Override
public void onClick(View v) {
Log.i(TAG,"MyButtonOnClickListener--onClick");
}
}
然后,我们再实现点击Button代码:
//定义Button
private Button button = null;
//定义MyButtonOnClickListener
private MyButtonOnClickListener myButtonOnClickListener = new MyButtonOnClickListener();
//获取button对象
button = (Button)findViewById(R.id.button);
//设置button点击事件监听接口myButtonOnClickListener
button.setOnClickListener(myButtonOnClickListener);
现在,我们列出uml类图:
大家看类图,应该是不是觉得有一点眼熟呢?是不是和策略模式的类图相似呢?
对,这就是一个最简单的策略模式。
#接口在android开发中的样例
android开发笔记之监听者模式—http://blog.youkuaiyun.com/hfreeman2008/article/details/37568615
这是我以前写的一篇文章,非常好的应用了接口。
#接口在java开发中的样例
定义接口:
接口IListener:
public interface IListener {
public void run();
}
定义一个Body类:
public class Body {
//定义一个IListener类型的变量listener
private IListener listener = null;
//设置Listener
public void setListener(IListener listener){
this.listener = listener;
}
//执行方法
public void dosomething(){
System.out.println("Body--dosomething()--before");
if(listener != null){
//这才是接口方法的调用的地方,也是用于后面的地方实现的地方
listener.run();
}
System.out.println("Body--dosomething()--after");
}
}
我们再定义一个接口实现类ListenerTest01:
public class ListenerTest01 implements IListener {
//ListenerTest01实现接口IListener中run方法
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("ListenerTest01---run()");
}
}
我们在Client中使用:
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
//定义一个对象listener,大家常用这一种方式,实现接口IListener中run方法
IListener listener = new IListener() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("listener---run()");
}
};
//定义一个对象listenerTest01
IListener listenerTest01 = new ListenerTest01();
//我们没有设置Listener
System.out.println("---------------------");
Body body = new Body();
body.dosomething();
//我们设置Listener为listener
System.out.println("---------------------");
body.setListener(listener);
body.dosomething();
//我们设置Listener为listenerTest01
System.out.println("---------------------");
body.setListener(listenerTest01);
body.dosomething();
}
}
输出结果:
---------------------
Body--dosomething()--before
Body--dosomething()--after
---------------------
Body--dosomething()--before
listener---run()
Body--dosomething()--after
---------------------
Body--dosomething()--before
ListenerTest01---run()
Body--dosomething()--after
从输出结果,我们可以看到:
如果不设置Listener,就直接执行对象的dosomething方法,而不执行listener.run()方法。
如果我们设置Listener为listener,则执行listener—run()方法。
如果我们设置Listener为ListenerTest01,则执行ListenerTest01—run()方法。
接口是将一个行为操作的实现放到后面具体类,具体位置来实现,并且此行为操作还可以改变。
常见的邮箱登录Demo
定义一个Email类,login时监听是登录成功还是失败,从而调用对应的接口:
public class Email {
private String name = "test";
private String passord = "test";
private OnLoginListener onLoginListener;
public boolean login(String name,String passord){
if(this.name.equals(name) && this.passord.equals(passord)){
if(onLoginListener != null){
onLoginListener.onLoginSucess();
}
return true;
}else{
if(onLoginListener != null){
onLoginListener.onLoginFail();
}
return false;
}
}
public OnLoginListener getOnLoginListener() {
return onLoginListener;
}
public void setOnLoginListener(OnLoginListener onLoginListener) {
this.onLoginListener = onLoginListener;
}
public interface OnLoginListener {
void onLoginSucess();
void onLoginFail();
}
}
具体的实现:
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private String TAG = "InterfaceDemo";
private Button button;
private Email email;
private boolean flag = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init() {
email = new Email();
email.setOnLoginListener(new Email.OnLoginListener() {
@Override
public void onLoginSucess() {
Log.i(TAG,"onLoginSucess");
}
@Override
public void onLoginFail() {
Log.i(TAG,"onLoginFail");
}
});
button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i(TAG,"onclick");
if(flag){
email.login("test01","test01");
flag = false;
}else{
email.login("test","test");
flag = true;
}
}
});
}
}
点击Button,模拟登录操作:
18871 18871 I InterfaceDemo: onclick
18871 18871 I InterfaceDemo: onLoginSucess
18871 18871 I InterfaceDemo: onclick
18871 18871 I InterfaceDemo: onLoginFail