Distributing source flow from the event-clicked screen to event-handling events
Let's get a picture first.
How to print it, code first.
Thread.dumpstack ();
Execute this method in the Dispatchtouchevent (Motionevent event) method
Through the above methods, you can print out from the click Screen to execute Dispatchtouchevent (Motionevent event) of the implementation process, feeling after the analysis no longer need to go to a way to find a direct according to the flow of the
Welcome to the bottom of the big guy hit the bottom of the face of New me
The first execution is Zygoteinit's main () method feels like it's time to start learning Java, and the Android system starts with the main method.
Always thought there was no main method in the Android world.
Zygoteinit
public static void Main (String argv[]) {
try {
...
} catch (Methodandargscaller caller) {
caller.run (); c4/>} catch (RuntimeException ex) {
closeserversocket ();
Throw ex;
}
}
The bottom of the thing dare not speak, we look directly at the process
Zygoteinit$methodandargscaller.run
public void Run () {
try {
mmethod.invoke (null, new object[] {Margs}),
catch (Illegalaccessexception ex) { C3/>throw new RuntimeException (ex);
} catch (InvocationTargetException ex) {
throwable cause = Ex.getcause ();
if (cause instanceof runtimeexception) {
throw (runtimeexception) cause;
} else if (cause instanceof Error) {
throw (Error) cause;
}
throw new RuntimeException (ex);
}
This executes the Mmethod method, which passes the assignment through the construction method Mmethod
New Zygoteinit.methodandargscaller (M, argv);
Method M;
try {
m = Cl.getmethod ("main", new class[] {string[].class});
\ catch (Nosuchmethodexception ex) {
throw new RuntimeException (
"Missing static main on" + ClassName, ex);
} catch (SecurityException ex) {
throw new RuntimeException (
"Problem getting static main on" + ClassName, ex);
}
The Mthread here executes the main method, which is the main method of Activitythread
Activitythread
public static void Main (string[] args) {
samplingprofilerintegration.start ();
Closeguard.setenabled (false);
Environment.initforcurrentuser ();
Eventlogger.setreporter (New Eventloggingreporter ());
Security.addprovider (New Androidkeystoreprovider ());
Process.setargv0 ("<pre-initialized>");
Mainthread do not use their own prepare ()
looper.preparemainlooper ();
Incredibly new self
activitythread thread = new Activitythread ();
Thread.attach (false);
if (Smainthreadhandler = = null) {
Smainthreadhandler = Thread.gethandler ();
}
Asynctask.init ();
if (false) {
looper.mylooper (). setmessagelogging (New
Logprinter (Log.debug, "Activitythread"));
Handler Looper cycle
looper.loop ();
throw new RuntimeException ("Main thread loop unexpectedly exited");
}
Next is the execution of the MessageQueue, followed by the execution of Dispatchinputevent ()
Inputeventreceiver
Called from native code.
private void dispatchinputevent (int seq, inputevent event) {
mseqmap.put (event.getsequencenumber (), seq);
Oninputevent (event);
}
This is the way out of the bottom, finally pleasing to the eye
This method is to handle the distribution input event
public void Oninputevent (InputEvent event) {
Finishinputevent (event, false);
}
This method is invoked when there is an input event, which does not execute the Finishinputevent () method and executes the Viewrootimpl in the
The Oninputevent () of the Windowinputeventreceiver class;
Windowinputeventreceiver inherited the Inputeventreceiver.
Viewrootimpl$windowinputeventreceiver
Final class Windowinputeventreceiver extends Inputeventreceiver {public
windowinputeventreceiver (inputchannel Inputchannel, Looper looper) {
super (Inputchannel, Looper);
}
@Override public
void Oninputevent (InputEvent event) {
enqueueinputevent (event, this, 0, true);
@Override public
void Onbatchedinputeventpending () {
scheduleconsumebatchedinput ();
}
@Override public
void Dispose () {
unscheduleconsumebatchedinput ();
Super.dispose ();
}
Then execute enqueueinpoutevent ()
Viewrootimpl
void Enqueueinputevent (InputEvent event,
inputeventreceiver receiver, int flags, Boolean processimmediately) {
queuedinputevent q = obtainqueuedinputevent (event, receiver, flags);
Queuedinputevent last = Mpendinginputeventtail;
if (last = = null) {
mpendinginputeventhead = q;
Mpendinginputeventtail = q;
} else {
last.mnext = q;
Mpendinginputeventtail = q;
}
Mpendinginputeventcount + 1;
Trace.tracecounter (Trace.trace_tag_input, Mpendinginputeventqueuelengthcountername,
Mpendinginputeventcount);
Whether if
(processimmediately) {
doprocessinputevents () is executed immediately;
} else {
scheduleprocessinputevents ();
}
}
Then Doprocessinputevents ();
void Doprocessinputevents () {
//Deliver all pending input events in the queue.
while (Mpendinginputeventhead!= null) {
queuedinputevent q = mpendinginputeventhead;
Mpendinginputeventhead = Q.mnext;
if (Mpendinginputeventhead = = null) {
mpendinginputeventtail = null;
}
Q.mnext = null;
Mpendinginputeventcount-= 1;
Trace.tracecounter (Trace.trace_tag_input, Mpendinginputeventqueuelengthcountername,
Mpendinginputeventcount);
Delivery processing input Event
deliverinputevent (q);
}
Complete processing of all input events clear Flag
if (mprocessinputeventsscheduled) {
mprocessinputeventsscheduled = false;
Mhandler.removemessages (msg_process_input_events);
}
Then Deliverinputevent ();
private void Deliverinputevent (Queuedinputevent q) {
trace.tracebegin (Trace.trace_tag_view, "Deliverinputevent" );
try {
if (minputeventconsistencyverifier!= null) {
minputeventconsistencyverifier.oninputevent (q.mEvent, 0) ;
}
The stage base class for processing input events
inputstage stage = Q.shouldskipime ()? mfirstpostimeinputstage:mfirstinputstage;
if (stage!= null) {
//input phase Delivery processing
stage.deliver (q);
} else {
finishinputevent (q);
}
} finally {
trace.traceend (Trace.trace_tag_view);
}
}
Viewrootimpl$inputstage
Deliver the event to be processed public
final void deliver (Queuedinputevent q) {
if (Q.mflags & Queuedinputevent.flag_ Finished)!= 0) {
forward (q);
} else if (Shoulddropinputevent (q)) {
finish (q, False);
} else {
Apply (q, onprocess (q));
}
then apply ();
Applies the event to the specified event
protected void apply (queuedinputevent q, int result) {
if (result = = FORWARD) {
FORWARD (q);
} else if (result = = finish_handled) {
finish (q, True);
} else if (result = = finish_not_handled) {
finish (q), FALSE);
else {
throw new illegalargumentexception ("Invalid Result:" + result);
}
Then forward (q);
Throws the event down one stage
protected void forward (Queuedinputevent q) {
ondelivertonext (q);
}
Then Ondelivertonext ();
protected void Ondelivertonext (Queuedinputevent q) {
if (mnext!= null) {
//Next stage followed by
Mnext.deliver (q); c21/>} else {
finishinputevent (q);
}
}
Then deliver the processing deliver (q), execute the Apply () method, where apply () is a subclass of the method
Viewrootimpl$asyncinputstage
Asyncinputstage enables asynchronous processing of events as well as base classes for sequential processing stages
@Override
protected void apply (queuedinputevent q, int result) {
if (result = = DEFER) {
DEFER (q);
} else {
super.apply (q, result);
}
Then it executes the Apply method of the parent class, inputstage apply (), and executes the asyncinputstage forward ()
@Override protected void Forward (Queuedinputevent q) {//Clear delay flag q.mflags &= ~queuedinputevent.flag
_deferred;
If the queue is empty, then queuedinputevent curr = Mqueuehead;
if (Curr = = null) {Super.forward (q);
Return
//Determine if the event is serialized before passing to the next stage final int deviceId = Q.mevent.getdeviceid ();
Queuedinputevent prev = null;
Boolean blocked = false;
while (Curr!= null && curr!= q) {if (!blocked && deviceId = = Curr.mEvent.getDeviceId ()) {
blocked = true;
} prev = Curr;
Curr = Curr.mnext; //If blocked will be placed in the queue for later processing, if the delay may not be placed in the queue if (blocked) {if (Curr = null) {Enqueue
(q);
} return;
}//event does not prevent immediate handover processing if (Curr!= null) {Curr = Curr.mnext;
Dequeue (q, prev); } super.forward (q); while (Curr!= null) {if (deviceId = = Curr.mEvent.getDeviceId ()) {if (Curr.mflags & Que
uedinputevent.flag_deferred)!= 0) {break;
} queuedinputevent next = Curr.mnext;
Dequeue (Curr, prev);
Super.forward (Curr);
Curr = Next;
else {prev = Curr;
Curr = Curr.mnext;
}
}
}
The forward () method of the parent class is then executed, followed by the Ondelivertonext (), Deliver () of the parent class, and the final execution of Viewpostimeinputstage.onprocess (), Viewpostimeinputstage also inherited Inputstage.
Viewrootimpl$viewpostimeinputstage
@Override
protected int onprocess (queuedinputevent q) {
if (q.mevent instanceof keyevent) {
return Processkeyevent (q);
} else {
//If a new Non-key event is delivered, make sure window is now allowed to update
handledispatchdoneanimating ();
Final int source = Q.mevent.getsource ();
if ((Source & Inputdevice.source_class_pointer)!= 0) {return
processpointerevent (q);
} else if ((source &am P Inputdevice.source_class_trackball)!= 0) {return
processtrackballevent (q);
} else {
return Processgenericmotionevent (q);}}
Then Processpointerevent (q) starts processing the event distribution
private int processpointerevent (queuedinputevent q) {
final motionevent event = (motionevent) q.mevent;
The Mview here is Decorview, which is assigned in the Setview of Viewrootimpl.
Understanding the source knows that the Makevisible method in the activity's series process in Windowmangerglobal will be new Viewrootimpl and will call Setview method
if ( Mview.dispatchpointerevent (Event)) {return
finish_handled;
}
return FORWARD;
}
Then execute the view's Dispatchpointerevent ()
View
Public Final Boolean dispatchpointerevent (Motionevent event) {
//whether to touch event
if (Event.istouchevent ()) {
Return Dispatchtouchevent (event);
} else {return
dispatchgenericmotionevent (event);
}
}
followed by the execution of the Decorview dispatchtouchevent ()
Phonewindow$decorview
@Override Public
Boolean dispatchtouchevent (motionevent ev) {
//This performs the callback of the Dispatchtouchevent ()
final Callback cb = Getcallback ();
Return CB!= NULL &&!isdestroyed () && Mfeatureid < 0? Cb.dispatchtouchevent (EV)
: super.dispatchtouchevent (EV);
The callback here is the window's callback interface, and activitiy implements the window's callback interface, which cb.dispatchtouchevent () The dispatchtouchevent of the activity is carried out ()
Activity
This is also the dispatchtoucheveent () public
boolean dispatchtouchevent (motionevent ev) {if () that we use in the activity.
Ev.getaction () = = Motionevent.action_down) {
onuserinteraction ();
}
if (GetWindow (). superdispatchtouchevent (EV)) {return
true;
}
return ontouchevent (EV);
}
Then GetWindow () superdispatchtouchevent () was executed.
Window is an interface, and its implementation class is Phonewindow
Phonewindow
@Override Public
Boolean superdispatchtouchevent (Motionevent event) {
//again handed to Decorview
return Mdecor.superdispatchtouchevent (event);
}
Phonewindw$decorview
public boolean superdispatchtouchevent (Motionevent event) {return
super.dispatchtouchevent (event);
}
ViewGroup
Handling the distribution of the event public
Boolean dispatchtouchevent (Motionevent event) {
//Check the Touch event
( Minputeventconsistencyverifier!= null) {
minputeventconsistencyverifier.ontouchevent (event, 0);
}
if (onfiltertoucheventforsecurity (event)) {
//noinspection simplifiableifstatement
listenerinfo li = Mlistenerinfo;
Ontouchlistener level is higher than ontouchevent ()
if (Li!= null && li.montouchlistener!= null && (Mviewflags & Amp Enabled_mask = = ENABLED
&& li.mOnTouchListener.onTouch (this, event)) {return
true;
}
if (Ontouchevent (event)) {return
true;
}
}
if (minputeventconsistencyverifier!= null) {
minputeventconsistencyverifier.onunhandledevent (event, 0);
} return
false;
Then Dispatchtransformedtouchevent ()
Private Boolean dispatchtransformedtouchevent (Motionevent event, Boolean cancel, View child, int desiredpointeridb
Its) {final boolean handled;
To get the action, the important thing is the action, not the content final int oldaction = Event.getaction ();
if (Cancel | | oldaction = = motionevent.action_cancel) {event.setaction (motionevent.action_cancel);
If the subclass is empty, the dispatchhtouchevent if (child = = NULL) {handled = Super.dispatchtouchevent (event) of the parent class is executed;
} else {handled = Child.dispatchtouchevent (event) that is not an empty execution subclass;
} event.setaction (Oldaction);
return handled;
Final int oldpointeridbits = Event.getpointeridbits ();
Final int newpointeridbits = oldpointeridbits & desiredpointeridbits;
For some reason the event does not have pointer if (newpointeridbits = = 0) {return false;
Final Motionevent transformedevent; if (newpointeridbits = = oldpointeridbits) {if (child = = NULL | | Child.hasidentitymatrix ()) {
if (child = = NULL) {handled = Super.dispatchtouchevent (event);
else {final float OffsetX = mscrollx-child.mleft;
Final float OffsetY = mscrolly-child.mtop;
Event.offsetlocation (OffsetX, OffsetY);
handled = Child.dispatchtouchevent (event);
Event.offsetlocation (-offsetx,-offsety);
return handled;
} transformedevent = Motionevent.obtain (event);
else {transformedevent = Event.split (newpointeridbits);
} if (child = = NULL) {handled = Super.dispatchtouchevent (transformedevent);
else {final float OffsetX = mscrollx-child.mleft;
Final float OffsetY = mscrolly-child.mtop;
Transformedevent.offsetlocation (OffsetX, OffsetY);
if (! Child.hasidentitymatrix ()) {Transformedevent.transform (Child.getinversematrix ()); } handled = CHIld.dispatchtouchevent (transformedevent);
} transformedevent.recycle ();
return handled;
}
The process ends here, until the event is processed.
To sum up,
1. From the bottom of the trigger to pass to Mainthread, Mainthread handed to viewrootimpl inputstage processing distribution input Events
2.->view.dispatchpointerevent
3.->phonewindow.decorview.dispatchtouchevent ()
4.->activity.dispatchtouchevent ()
5.->phonewindow.superdispatchtouchevent ()
6.->phonewindow.decorview.superdispatchtouchevent ()
7.->viewgroup.dispatchtouchevent ()