Implementación del código fuente de Toast
Entrada de tostadas
Cuando usamos las indicaciones de tostadas en la aplicación, generalmente hacemos una llamada de código simple, como se muestra a continuación:
[Java] Ver PlainCopyPrint?
Toast.maketext (context, msg, toast.length_short) .show ();
Maketext es la entrada de Toast. El código fuente es el siguiente (Frameworks/Base/Core/Java/Android/Widget/Toast.java):
Public Static Toast Maketext (contexto de contexto, texto de caracteres, int duración) {toast result = new toast (context); Internet.R.Layout.Transient_Notification, NULL); Duración;Desde el código fuente de Maketext, podemos ver que el archivo de diseño de Toast es transient_notification.xml, ubicado en Frameworks/Base/Core/Res/Layout/Transition_Notification.xml:
<? Xml versión = "1.0" coding = "utf-8"?> <LinearLayout xmlns: android = "http://schemas.android.com/apk/android" android: lazout_width = "match_parent" android: el flout_height = " Match_parent "Android: Orientation =" Vertical "Android: Background ="? "Wrap_Content" Android: Layout_weight = "1" Android: Layout_Gravity = "Center_Horizontal" Android: TextApperance = "@style/textaperance.toast" "Android: textcolor ="@color/bright_foreground_dark "android: shadowcolor ="#bb000000 "android:: Shadowradius = "2.75" /> < /linealLayout>
El archivo de diseño de la tostada del sistema es muy simple, es decir, una vista text se coloca en el diseño lineal del diseño vertical. A continuación, continuamos siguiendo el método show () para estudiar la implementación del código de visualización después de que se forme el diseño:
public void show () {if (mNExtView == null) {throw new runtimeException ("SetView debe haber sido llamado"); ; Try {Service.enqueUetoast (PKG, TN, MDuration);} Catch (RemoteException e) {// vacío}} Hay dos puntos en el método de espectáculo al que debemos prestar atención. (1) ¿Qué es TN? (2) El papel del servicio InotificationManager. Con estos dos problemas, continúe con nuestro código fuente de tostadas.
Código fuente de TN
Muchas preguntas pueden encontrar la respuesta a través del código fuente. La implementación del MTN en el constructor de Toast, el código fuente es el siguiente:
Public toast (contexto contexto) {Mcontext = contexto; () .getInteger (com.android.internal.r.iinteger.config_toastdefaultgravity);}A continuación, comenzamos desde el código fuente de la clase TN para explorar el papel de TN. El código fuente TN es el siguiente:
La clase estática privada TN extiende iTransitenotification.stub {final runnable mshow = new Runnable () {@Override public void run () {manyless ();}; (); ; Apropiadamente. WindowManager.LayOutParams.type_toast; Params.privateflags = windowManager.layoutparams.private_flag_for_all_users; .post (mshow);} / ** * Programe HandleHide Insto el hilo derecho * / @Override public void hide () {if (lochoLogv) log.v (etiqueta (etiqueta "escondite:" + this); mhandler.post ( mhide);} public void handleshow () {if (lochoLogv) log.v (etiqueta, "Mostrar show:" + this + "mview =" + mview + "xtview =" + mnextView); {// Eliminar la vista anterior si es necesario (); (WindowManager) context.getSystemService (context.window_service); Final int gravity = gravity.getabsolutegravity (mgravity, config.getLayoutDirection ()); (Gravity & Gravity.Verical_Gravity_Mask) == Gravity.Fill_vertical) {mParams.verticalweight = 1.0 f;} mParams.x = mx; GetParent ()! = NULL) {if (lochoLogv) log.v (etiqueta, "¿Retirar!" + mview + " + this); mwm.re MoveView (mview);} if (lochoLog) log.v (etiqueta" Agregue! " + mview +" en " + this); mwm.AddView (mview, mParams); trysendac senseEvent ();}}}} daccessabilityEvent () {AccessibilityManager AccessibilityManager = AccessibilityManager. GetInStance (mview.getContext ()); if ! DispatchPopultAcessibilityEvent (evento); = NULL) {// no: Comprobar pintura () solo para hacer. Intenta no bloquear. A través del código fuente, obviamente podemos ver la relación de herencia. Se supone que los lectores tienen la base de la comunicación entre el proceso de Android (no bien conocido por aprender una serie de blogs de la comunicación de Luo Shengyang en la comunicación del proceso de la carpeta). Dado que TN se usa para la comunicación entre procesos, es fácil para nosotros pensar que el papel específico de la clase TN debe ser el objeto de devolución de llamada de la clase Toast. la clase TN.
La clase TN se hereda de Itransitenotification.Stub, ItransientNotification.Aidl se encuentra en Frameworks/Base/Core/Java/App/ITransientNotification.Aidl, el código fuente es el siguiente: como sigue:
paquete android.app;
ITransientNotification Define dos métodos show () y oculta (), y su implementación específica está en la clase TN. La implementación de la clase TN es:
/ ***Programa Handleshow en el hilo derecho* / @Override public void show () {if (lochoLogv) log.v (etiqueta, "show:" + this); */ @Override public void hide () {if (lochoLogv) log.v (etiqueta, "escondite:" + this);Aquí podemos saber que la implementación del método de exhibición y escondite de Toast se basa en el mecanismo del controlador. La implementación del controlador en la clase TN es:
Handl final mhandler = new Handler ();
Además, no encontramos ningún método looper.perpare () y looper.loop () en la clase TN. Muestra que Mhandler llama al objeto Looper del hilo actual. Por lo tanto, cuando estamos en el hilo principal (es decir, en el hilo de la interfaz de usuario), podemos llamar al método de tostada. Maketext a voluntad, porque el sistema Android nos ayuda a darnos cuenta de la inicialización del hilo principal del hilo principal.但是 , 如果你想在子线程中调用 如果你想在子线程中调用 如果你想在子线程中调用 tost.maketext 方法 , 就必须先进行 looper 初始化了 不然就会报出 不然就会报出 java.lang.runtimeException: No se puede crear un handler interior que no haya llamado looper.prepare () Esencia El aprendizaje del mecanismo del controlador puede consultar un blog que escribí antes: http://blog.csdn.net/wzy_1988/article/details/38346637.
Luego, continúe siguiendo la implementación de MSHOW y MHIDE, los cuales son ejecutables.
Final runnable mshow = new runnable () {@Override public void run () {handleshow ();}}; handleshow () mnextView = null;}}; Se puede ver que la implementación real de Show and Hide es llamar a los métodos Handleshow () y HandleHide (), respectivamente. Veamos la implementación específica de Handleshow ():
public void handleshow () {if (mview! = mnextView) {// Eliminar la vista si es necesario HandleHide (); ) {context = mview.getContext ();} mwm = (WindowsManager) context.getSystemService (context.window_service); .getContext () .getResources (). .fill_horizontal) {mparams.horizontalweight = 1.0f;} if (gravity & gravity.vertical_gravity_mask) == gravity.fill_vertical) {mParams.vericalweight = 1.0 f;} mParams.x = mxs.y = my; = MverticalMargin; Desde el código fuente, sabemos que Toast se carga en AddView a través de WindowsManager. Por lo tanto, el método de ocultación es naturalmente WindowManager para llamar al método RemoLView para eliminar la vista de tostadas.
Para resumir, al analizar el código fuente de la clase TN, sabemos que la clase TN es un objeto de devolución de llamada, y otros procesos llaman al método Mostrar y ocultar la clase TN para controlar la pantalla y la desaparición de esta tostada.
Notificación managerservicio
Volver al método de espectáculos de la clase Toast, podemos ver que el servicio de getSe se llama aquí para obtener el servicio inotificationManager.
Sservice de inotificación static privada;
Después de obtener el servicio InotificationManager, se llamó al método Enqueuetoast para poner la tostada actual en la cola de tostadas del sistema. Los parámetros del pase son PKG, TN y MDuration. En otras palabras, usamos Toast.MaketeExt (contexto, MSG, Toast.Length_Show) .Show () para presentar una tostada. El sistema llama al método de programa y oculta del objeto de devolución de llamada TN para mostrar y ocultar la tostada.
La clase de implementación específica de la interfaz inofiticanager aquí es la clase NotificationManageService, ubicada en Frameworks/Base/Services/Java/Com/Server/NotificationManagervice.java.
En primer lugar, analicemos las funciones de la entrada de Toast en el enqueuetoast.
Public void enqeuetoast (String PKG, ItransientNotification Callback, int Duration) {// PackageName es la clase NULL o TN como NULL == NULL) {return;} // (1) Determine si es una tostada final de emisión booleana. ) || ("Android" .Equals (PKG)); (Pkg, binder.getCallinguid ()) &&! // (2) Ver si el tostado ya ha int index = i ndexoftoAstlocked (PKG, llamado); get (index); final int n = mtoastqueue.size (); ++; Toastecord objetos y lo pone en Mtoastqueue. ) Si el índice es 0, significa que el equipo de entrada actual está en el equipo. }}} Se puede ver que hice un breve comentario sobre el código anterior. El código es relativamente simple, pero hay 4 puntos de nota que requiere que discutamos más.
(1) Determine si es la tostada del sistema. Si el nombre del paquete de la tostada actual es "Android", es la tostada del sistema, de lo contrario también puede llamar al método ISCallerSystem () para juzgar. El código fuente de implementación de este método es:
Boolean isUidSystem (int uid) {final int appid = userHandle.getAppid (uid); ());} El código fuente de ISCallerSystem es relativamente simple, es decir, para determinar si el UID del proceso de tostada actual es uno de los sistemas_uid, 0, phine_uid, si es así, es la tostada del sistema; tostada.
Ya sea que se trate de una tostada del sistema, lea el código fuente a continuación, se puede ver que hay dos ventajas principales:
La tostada del sistema definitivamente puede ingresar a la cola de tostadas del sistema, y la lista negra no la detendrá.
La tostada del sistema no tiene el límite de cantidad en la cola de tostadas del sistema, mientras que la tostada enviada por PKG ordinaria tiene el límite de cantidad en la cola de tostadas del sistema.
(2) Vea si la tostada para ser confiada al equipo ya está en la cola de tostadas del sistema. Esto se logra comparando PKG y devolución de llamada.
Private int IndexoftoActed (String PKG, ITransientNotification Callback) {Ibinder cBAK = llamado Callback.asBinder (); ++) {ToastRecord r = list.get (i); A través del código anterior, podemos sacar una conclusión de que mientras el nombre PKG del tostado sea consistente con el objeto TN, el sistema considera estas tostadas como el mismo tostado.
(3) Establezca el proceso actual de tostadas como procesamiento de recepción. El código fuente se muestra a continuación:
Void KeepProcessalLocked (int pid) {int toastCount = 0; list.get (i); 'T sucede.}} El MAM = ActivityManagernative.getDefault () aquí llama al método SetProcessForegrour para colocar el proceso PID actual en el procesamiento de la recepción para asegurarse de que no se mate sistemáticamente. Esto también explica por qué cuando terminamos actualmente la actividad, Toast también se puede mostrar porque el proceso actual aún se ejecuta.
(4) Cuando el índice es 0, se muestra el brindis del cabezal de la cola. El código fuente es el siguiente:
Void, ShowsExtToastLocked () {// Obtenga el ToastRecord ToastRecord Record = Mtoastqueue.get (0); () la lista y dejar que Procese int index = mtoastqueue.indexof (registro); = mtoastqueue.get (0);} else {registro = null;}}}}El objeto de devolución de llamada de Toast es el objeto TN. A continuación, echemos un vistazo, por qué el tiempo de visualización del sistema solo puede ser 2S o 3.5s, la clave es la implementación del método ScheduletIMeOutlocked. El principio es que después de llamar al método de programa de TN para mostrar Toast, debe llamar al método ScheduletMelocklocked para desaparecer Toast. (Si tiene alguna pregunta: ¿no quiere decir que el método ocultar del objeto TN para desaparecer tostadas, por qué llamar al método de programación de programación aquí para desaparecer tostadas? , y generalmente tenemos nuestra oficina. 使用的 Toast 都会在当前 Actividad 停留几秒。如何实现停留几秒呢?原理就是 Programando tiempo de bloqueo 发送 Message_timeout 消息去调用 tn 对象的 Ocultar 方法 但是这个消息会有一个 但是这个消息会有一个 retraso 延迟 这里 这里 这里 这里 这里 这里也是用了 Handler 消息机制)。
Privado final int long_delay = 3500; Long demora = R.Dury == Toast.length_long?
En primer lugar, vimos que esto aquí no envió el mensaje Message_TimeOut directamente, pero hubo un retraso de retraso. El tiempo de retraso de "Long Delay = R.Duration == Toast.length_long? Long_dlay: Short_dlay;" 2 o 3.5s. Es inútil pasar una duración en el método de tostada.
A continuación, echemos un vistazo a cómo se procesan los mensajes Message_TimeOut en WorkerHandler. El tipo de objeto Mhandler es WorkerHandler, el código fuente es el siguiente:
Private Final Clase Workrandler extiende Handler {@Override public void HandLemessage (Mensaje Msg) {Switch (Msg.what) {Case Message_TimeOut: Handleti MeOut (ToastRecord) msg.obj;Se puede ver que el procesamiento de mensajes del WorkrHandler al tipo de Message_TimeOut es llamar al método HandlerTimeOut.
Private void HandletIMeOut (ToastRecord Record) {Synchronized (mtoastqueue) {int index = indextoToastLocked (registro.pkg, registro.callback);En el código de HandletIMeOut, primero determine si el objeto ToastRecord que debe desaparecer está en la cola. La verdad está a punto de aparecer frente a nosotros, continúe rastreando el código fuente:
Privado void canceltoastlocked (int index) {toastecord registro = mtoastqueue.get (index); // la lista de todos modos} mtoastqueue.remove (índice); La lista, también, Donforms que la lista no ha cambiado // después de este punto. Jaja, ver aquí, también se ha llamado al método de ocultación de nuestro objeto de devolución de llamada, y también se elimina de Mtoastqueue de Mtoastqueue. En este punto, la pantalla completa y la desaparición de la tostada han terminado.