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); }
每个接口执行不同的操作。
下面是一个相关的例子:
package com.fp.app.looper; import com.fp.app.debug.DebugLog; 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; } } }
package com.fp.app.debug; 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>