Android上层实现java代码实现,仅仅实现功能还不能体现实力,还要写出一手看起来优雅的代码,今天总结下java内部类如何可以优雅的实现Android Touch事件从源头传递给Activityf分发。
外围类的窗口及桥梁
我们从实际列子出发,看下Android源码中如何通过作为内部类实现Touch事件完整地传递由fromwork层到WMS到ViewRootImpl通过PhoneWindow联系到Activity再到布局View呢。
WindowManagerService通过代理对象(IWindow.Stub.Proxy)进程间通信方式Binder通知到远端IWindow.Stub对象,这个对象正好是ViewRootImpl的内部类W实例mWindow,因为W是其内部类,用来和远端进程通信,接受消息,作为一个接收端,收到消息之后并很轻松通知到外围类,可以就是一体的内部沟通,代码如下:详细推荐看一篇文章:http://blog.csdn.net/a992036795/article/details/51690303
我们可以把通过点击事件把touch事件的调用流程dump出来:
button1.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Thread.dumpStack();
return false;
}
});
打印出来结果如下:
08-15 20:15:09.628 16091-16091/com.yzf0813.test W/System.err: at cn.egame.terminal.paySdk.demo.MainActivity.access$100(MainActivity.java:65)
08-15 20:15:09.628 16091-16091/com.yzf0813.test W/System.err: at cn.egame.terminal.paySdk.demo.MainActivity$9.onTouch(MainActivity.java:579)
08-15 20:15:09.628 16091-16091/com.yzf0813.test W/System.err: at android.view.View.dispatchTouchEvent(View.java:9384)
08-15 20:15:09.628 16091-16091/com.yzf0813.test W/System.err: at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2555)
08-15 20:15:09.628 16091-16091/com.yzf0813.test W/System.err: at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2197)
08-15 20:15:09.628 16091-16091/com.yzf0813.test W/System.err: at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2555)
08-15 20:15:09.628 16091-16091/com.yzf0813.test W/System.err: at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2197)
08-15 20:15:09.628 16091-16091/com.yzf0813.test W/System.err: at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2555)
08-15 20:15:09.628 16091-16091/com.yzf0813.test W/System.err: at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2197)
08-15 20:15:09.628 16091-16091/com.yzf0813.test W/System.err: at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2555)
08-15 20:15:09.628 16091-16091/com.yzf0813.test W/System.err: at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2197)
08-15 20:15:09.628 16091-16091/com.yzf0813.test W/System.err: at com.android.internal.policy.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2461)
08-15 20:15:09.628 16091-16091/com.yzf0813.test W/System.err: at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1777)
08-15 20:15:09.628 16091-16091/com.yzf0813.test W/System.err: at android.app.Activity.dispatchTouchEvent(Activity.java:2865)
08-15 20:15:09.628 16091-16091/com.yzf0813.test W/System.err: at com.android.internal.policy.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2422)
08-15 20:15:09.628 16091-16091/com.yzf0813.test W/System.err: at android.view.View.dispatchPointerEvent(View.java:9610)
08-15 20:15:09.628 16091-16091/com.yzf0813.test W/System.err: at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4447)
08-15 20:15:09.628 16091-16091/com.yzf0813.test W/System.err: at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4313)
08-15 20:15:09.628 16091-16091/com.yzf0813.test W/System.err: at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3847)
08-15 20:15:09.629 16091-16091/com.yzf0813.test W/System.err: at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3900)
08-15 20:15:09.629 16091-16091/com.yzf0813.test W/System.err: at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3866)
08-15 20:15:09.629 16091-16091/com.yzf0813.test W/System.err: at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3992)
08-15 20:15:09.629 16091-16091/com.yzf0813.test W/System.err: at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3874)
08-15 20:15:09.629 16091-16091/com.yzf0813.test W/System.err: at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4049)
08-15 20:15:09.629 16091-16091/com.yzf0813.test W/System.err: at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3847)
08-15 20:15:09.629 16091-16091/com.yzf0813.test W/System.err: at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3900)
08-15 20:15:09.629 16091-16091/com.yzf0813.test W/System.err: at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3866)
08-15 20:15:09.629 16091-16091/com.yzf0813.test W/System.err: at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3874)
08-15 20:15:09.629 16091-16091/com.yzf0813.test W/System.err: at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3847)
08-15 20:15:09.629 16091-16091/com.yzf0813.test W/System.err: at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6146)
08-15 20:15:09.629 16091-16091/com.yzf0813.test W/System.err: at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6120)
08-15 20:15:09.629 16091-16091/com.yzf0813.test W/System.err: at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6081)
08-15 20:15:09.629 16091-16091/com.yzf0813.test W/System.err: at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6262)
08-15 20:15:09.629 16091-16091/com.yzf0813.test W/System.err: at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:192)
08-15 20:15:09.629 16091-16091/com.yzf0813.test W/System.err: at android.os.MessageQueue.nativePollOnce(Native Method)
08-15 20:15:09.629 16091-16091/com.yzf0813.test W/System.err: at android.os.MessageQueue.next(MessageQueue.java:330)
08-15 20:15:09.629 16091-16091/com.yzf0813.test W/System.err: at android.os.Looper.loop(Looper.java:137)
08-15 20:15:09.629 16091-16091/com.yzf0813.test W/System.err: at android.app.ActivityThread.main(ActivityThread.java:5621)
08-15 20:15:09.629 16091-16091/com.yzf0813.test W/System.err: at java.lang.reflect.Method.invoke(Native Method)
08-15 20:15:09.629 16091-16091/com.yzf0813.test W/System.err: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:794)
08-15 20:15:09.629 16091-16091/com.yzf0813.test W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:684)
通过上面整理流程可以看到ActivityThread中looper接收到event事件处理,整个入口开始处调用了InputEventReceiver.dispatchInputEvent(InputEventReceiver.java)这个是由底层调用到,WindowInputEventReceiver继承了InputEventReceiver,并且是ViewRootImpl的内部类,继而走到ViewRootImpl.enqueueInputEvent。在ViewRootImpl的内部类$ViewPostImeInputStage.processPointerEvent()来关联到mView,即在setView时传入的DecorView
private int processPointerEvent(QueuedInputEvent q) {
final MotionEvent event = (MotionEvent)q.mEvent;
mAttachInfo.mUnbufferedDispatchRequested = false;
boolean handled = mView.dispatchPointerEvent(event);
if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
mUnbufferedInputDispatch = true;
if (mConsumeBatchedInputScheduled) {
scheduleConsumeBatchedInputImmediately();
}
}
return handled ? FINISH_HANDLED : FORWARD;
}
在View的实现中,dispatchPointerEvent的逻辑如下,这样一来,点击事件就传递给了mView的dispatchTouchEvent方法。
public final boolean dispatchPointerEvent(MotionEvent event) {
if (event.isTouchEvent()) {
return dispatchTouchEvent(event);
} else {
return dispatchGenericMotionEvent(event);
}
}
mView是一个PhoneWindow.DecorView对象,其实现了dispatchTouchEvent(),DecorView是PhoneWindow的内部类,很方便的把事件通知到外围类,其dispatchTouchEvent实现
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
final Callback cb = getCallback();
return cb != null && mFeatureId < 0 ? cb.dispatchTouchEvent(ev) : super
.dispatchTouchEvent(ev);
}
getCallback()为外围类PhoneWindow的成员方法,Activity实现了Window.CallBack,在Activity.attach()方法内创建了PhoneWindow,并持有了Activity对象,其对CallBack的实现了。最后touch事件传递了Activity这层了,即Activity对dispatchTouchEvent的实现。
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
mWindow = new PhoneWindow(this, window);
mWindow.setWindowControllerCallback(this);
//this为当前Activity
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
/*****省略代码*****/
}
Activity类实现了Window.Callback这个接口
public class Activity extends ContextThemeWrapper implements LayoutInflater.Factory2, Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener, ComponentCallbacks2, Window.OnWindowDismissedCallback, WindowControllerCallback
setCallBack和getCallBack均为Window的成员方法
public abstract class Window {
*******
public void setCallback(Callback callback) {
mCallback = callback;
}
/** * Return the current Callback interface for this window. */
public final Callback getCallback() {
return mCallback;
}
********
}
总结发现通过内部类的方式可以暴露对外窗口,作为沟通的桥梁方便接受消息而来内部通知消息。用java中的内部类作用而言,即使内部类可以访问外网类PhoneWindow的private和protected的域权限,就像一个对外暴露的窗口并实现隐藏,那内部类其他作用设计:
1.内部类可以很好的实现隐藏
一般的非内部类,是不允许有 private 与protected权限的,但内部类可以
2.内部类拥有外围类的所有元素的访问权限
3.可是实现多重继承
用内部类来继承或实现接口从而达到扩展外网类的功能
4.可以避免修改接口而实现同一个类中两种同名方法的调用。
用内部类来实现接口从而避免同名方法,做到同时存在不影响各自。