android实际上使用了大量的obverser 模式,最简单的就是onclicklistener,但是与一般的observer模式不同的是,view中定义了很多接口,如下所示:
/**
* Interface definition for a callback to be invoked when a touch event is
* dispatched to this view. The callback will be invoked before the touch
* event is given to the view.
*/
public interface OnTouchListener {
/**
* Called when a touch event is dispatched to a view. This allows listeners to
* get a chance to respond before the target view.
*
* @param v The view the touch event has been dispatched to.
* @param event The MotionEvent object containing full information about
* the event.
* @return True if the listener has consumed the event, false otherwise.
*/
boolean onTouch(View v, MotionEvent event);
}
/**
* Interface definition for a callback to be invoked when a view has been clicked and held.
*/
public interface OnLongClickListener {
/**
* Called when a view has been clicked and held.
*
* @param v The view that was clicked and held.
*
* return True if the callback consumed the long click, false otherwise
*/
boolean onLongClick(View v);
}
/**
* Interface definition for a callback to be invoked when the focus state of
* a view changed.
*/
public interface OnFocusChangeListener {
/**
* Called when the focus state of a view has changed.
*
* @param v The view whose state has changed.
* @param hasFocus The new focus state of v.
*/
void onFocusChange(View v, boolean hasFocus);
}
/**
* 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);
}
/**
* Interface definition for a callback to be invoked when the context menu
* for this view is being built.
*/
public interface OnCreateContextMenuListener {
/**
* Called when the context menu for this view is being built. It is not
* safe to hold onto the menu after this method returns.
*
* @param menu The context menu that is being built
* @param v The view for which the context menu is being built
* @param menuInfo Extra information about the item for which the
* context menu should be shown. This information will vary
* depending on the class of v.
*/
void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo);
}
每个接口执行不同的操作。
下面是一个相关的例子:
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.widget.Button;
public class Observer extends Activity implements OnClickListener ,OnFocusChangeListener{
public static final String TITLE = "title";
@Override
public void setTitle(int titleId) {
super.setTitle(titleId);
}
private Button btnMM;
private Button btnMS;
private Button btnSM;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.entry);
findComponent();
setOnClickListener();
setOnFocusChangeListener();
}
private void setOnClickListener() {
btnMM.setOnClickListener(this);
btnMS.setOnClickListener(this);
btnSM.setOnClickListener(this);
}
private void setOnFocusChangeListener() {
btnMM.setOnFocusChangeListener(this);
btnMS.setOnFocusChangeListener(this);
btnSM.setOnFocusChangeListener(this);
}
private void findComponent() {
btnMM = (Button) this.findViewById(R.id.btn_mm);
btnMS = (Button) this.findViewById(R.id.btn_ms);
btnSM = (Button) this.findViewById(R.id.btn_sm);
}
@Override
public void onClick(View v) {
int id = v.getId();
switch (id) {
case R.id.btn_mm:
DebugLog.log("btnMM onclick");
break;
case R.id.btn_ms:
DebugLog.log("btnMS onclick");
break;
case R.id.btn_sm:
DebugLog.log("btnSM onclick");
break;
default:
break;
}
}
@Override
public void onFocusChange(View v, boolean hasFocus) {
int id = v.getId();
switch (id) {
case R.id.btn_mm:
DebugLog.log("btnMM onFocusChange");
break;
case R.id.btn_ms:
DebugLog.log("btnMS onFocusChange");
break;
case R.id.btn_sm:
DebugLog.log("btnSM onFocusChange");
break;
default:
break;
}
}
}
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import android.util.Log;
public class DebugLog {
public final static boolean DEBUG = true;
public static void log(String message) {
if (DEBUG) {
String fullClassName = Thread.currentThread().getStackTrace()[3].getClassName();
String className = fullClassName.substring(fullClassName.lastIndexOf(".") + 1);
String methodName = Thread.currentThread().getStackTrace()[3].getMethodName();
int lineNumber = Thread.currentThread().getStackTrace()[3].getLineNumber();
Log.d(className + "." + methodName + "():" + lineNumber, message);
}
}
public static void printThreadId(String message) {
if (DEBUG) {
Log.d(message, String.valueOf(Thread.currentThread().getId()));
}
}
public static void log(String tag, String message) {
if (DEBUG) {
String methodName = Thread.currentThread().getStackTrace()[3].getMethodName();
int lineNumber = Thread.currentThread().getStackTrace()[3].getLineNumber();
Log.d(tag + "." + methodName + "():" + lineNumber, message);
}
}
public static void printTrace(String message) {
if (DEBUG) {
printIllegalArgumentException("", message);
}
}
public static String getStackTrace(Throwable throwable) {
Writer writer = new StringWriter();
PrintWriter printWriter = new PrintWriter(writer);
throwable.printStackTrace(printWriter);
return writer.toString();
}
public static void printIllegalArgumentException(String tag, String arg) {
if (DEBUG) {
final Throwable throwable = new IllegalArgumentException(arg);
Log.w(tag, arg, throwable);
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.fp.app.looper" android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".Observer" android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<Button android:id="@+id/btn_mm"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="main thread to main thread" />
<Button android:id="@+id/btn_ms"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="main thread to sub thread" />
<Button android:id="@+id/btn_sm"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="sub thread to main thread" />
</LinearLayout>