Toast Implementação de código -fonte
Torrada entrada
Quando usamos as solicitações de torradas no aplicativo, geralmente fazemos uma chamada de código simples, como mostrado abaixo:
[Java] Visualize PlainCopyPrint?
Toast.MakeText (contexto, msg, Toast.Length_Short) .Show ();
MakeText é a entrada da torrada. O código -fonte é o seguinte (estruturas/base/core/java/android/widget/Toast.java):
Torrada estática Internet.R.Layout.Transient_Notification, NULL); Duração; resultado de retorno;}
A partir do código -fonte do MakeText, podemos ver que o arquivo de layout do Toast é transient_notification.xml, localizado em estruturas/base/core/res/layout/transition_notification.xml:
<? Match_parent "Android: Orientation =" Vertical "Android: Background ="? "wrap_content" Android: layout_weight = "1" Android: layout_gravity = "Center_horizontal" Android: textappAnce = "@style/textpapance.toast" "Android: textcolor ="@color/bright_dark_dark "Android: shadowcolor = bb = bb ="# ShadowRadius = "2,75" /> </linearlayout>
O arquivo de layout da torrada do sistema é muito simples, ou seja, uma visualização de texto é colocada no linearlayout do layout vertical. Em seguida, continuamos a seguir o método show () para estudar a implementação do código de exibição após a formação do layout:
public void show () {if (mNextView == NULL) {THREGA NOVA RUNDOMENTE ("SetView deve ter sido chamado"); ; Há dois pontos no método do show no qual precisamos prestar atenção. (1) O que é TN? (2) O papel do serviço InotificationManager. Com esses dois problemas, continue nosso código -fonte de torrada.
Código fonte TN
Muitas perguntas podem encontrar a resposta através do código -fonte. A implementação do MTN no construtor da torrada, o código -fonte é o seguinte:
Torrada pública (contexto de contexto) {McOntext = Contexto; () .getInteger (com.android.internal.r.iinteger.config_toastdefaultgravity);}Em seguida, começamos a partir do código -fonte da classe TN para explorar o papel da TN. O código -fonte do TN é o seguinte:
Classe estática privada tn estende ItransiteNotification.stub {final Runnable mshow = new Runnable () {@Override public void run () {Handless ();}; (); Int mx, meu fluxo mhorizontaltina; Apropriadamente Windows Params.privateflags = windowmanager.layoutparams.private_flag_for_all_users; .Post (mshow);} / ** * agende o manipulamento do Insto o thread direito * / @Override public void hide () {if (LocalLogv) log.v (tag (tag "hide:" + this); mhandler.post ( mhide);} public void handleshow () {if (LocalLogv) log.v (tag, "Handle mostram:" + this "mview =" + mview + "xtview =" + mNextView); {// Remova a visualização antiga, se necessário, Handlehide (); (WindowManager) Context.getSystemService (Context.Window_Service); Final Int Gravity = Gravity.getAbsoluteGravity (mgravity, config.getLayoutDirection ()); (Gravidade e gravidade.vertical_gravity_mask) == Gravity.fill_vertical) {mParams.verticalweight = 1.0 f;} mParams.x = mx; getParent ()! add! " + mview +" em " + this); mwm.addview (mview, mparams); trysendac senseEvent ();}}}} daccessibilityEvent () {acessibilidade manager (! AccessibilityManager.IsEnabled ()) {return;} // Trate as brindes como notificações, pois o uso para // uma informação transitória para o evento de acessibilidade do usuário = AccessibilityEvent.Obtain.Obtain; DispatchpopultAccessibilityEvent (Evento); = null) {// não: verificando tinta () apenas para fazer. Tente não travar. Através do código -fonte, podemos obviamente ver o relacionamento de herança. Supõe -se que os leitores tenham a base da comunicação entre o processo do Android (não muito conhecido para aprender uma série de blogs da comunicação de Luo Shengyang sobre a comunicação do processo do Binder). Como o TN é usado para a comunicação entre processos, é fácil pensar que o papel específico da classe TN deve ser o objeto de retorno de chamada da classe de brinde. a classe TN.
A classe TN é herdada de itransiteNotification.stub, ItransientNotification.aidl está localizada em estruturas/base/core/java/app/itransientNotification.aidl, o código -fonte é o seguinte: da seguinte forma:
pacote Android.App;
O ITRansientNotification define dois métodos mostram () e Hide (), e sua implementação específica está na classe TN. A implementação da classe TN é:
/ ***Cronograma Handleshow no thread certo* / @Override public void show () {if (LocalloGV) log.v (tag, "Show:" + this); */ @Override public void hide () {if (LocalloGV) log.v (tag, "ocultar:" + this);Aqui podemos saber que a implementação do Mostrar e Ocultar do Toast é baseada no mecanismo manipulador. A implementação do manipulador na classe TN é:
Final Handl Mhandler = new Handler ();
Além disso, não encontramos nenhum método looper.perpare () e looper.loop () na classe TN. Ele mostra que Mhandler chama o objeto Looper do thread atual. Portanto, quando estamos no encadeamento principal (ou seja, no thread da interface do usuário), podemos chamar o método Toast.MakeText à vontade, porque o sistema Android nos ajuda a realizar a inicialização do Looper do encadeamento principal.但是 , 如果你想在子线程中调用 Toast.MakeText 方法 , Looper 初始化了 , Java.lang.RuntimeException: Não é possível criar manipulador dentro do thread que não chamou looper.Prepare () Essência O aprendizado do mecanismo manipulador pode se referir a um blog que escrevi antes: http://blog.csdn.net/wzy_1988/article/details/38346637.
Em seguida, continue a seguir a implementação do MSHOW e MHIDE, ambos executados.
Final Runnable MSHOW = new Runnable () {@Override public void run () {Handleshow ();}}; Handleshow () mNextView = null;}}; Pode -se observar que a verdadeira implementação de Mostrar e Ocultar é chamar HandleShow () e HandleHide () Métodos, respectivamente. Vejamos a implementação específica de Handleshow ():
public void Handleshow () {if (mview! ) {context = mview.getContext ();} mwm = (WindowManager) context.getSystemService (context.window_service); .getContext () .getResources (). .fill_horizontal) {mparams.horizontalweight = 1.0f;} if (gravidade e gravidade.vertical_gravity_mask) == gravidade.fill_vertical) {mparams.verticalweight = 1.0 f;} mparams.x = mxgin; = mverticalMargin; Do código -fonte, sabemos que o brinde é carregado no AddView através do WindowManager. Portanto, o método de oculto é naturalmente WindowManager para chamar o método RemoverView para remover a visualização de brinde.
Para resumir, analisando o código -fonte da classe TN, sabemos que a classe TN é um objeto de retorno de chamada e outros processos chamam o método de show e ocultação da classe TN para controlar a exibição e o desaparecimento desta torrada.
NotificationManagerService
De volta ao método de show da classe de brinde, podemos ver que o GetService é chamado aqui para obter o serviço InotificationManager.
INOTIFICAÇÃO ESTÁTICA PRIVADA SERVICE SSERVICE;
Depois de obter o serviço InotificationManager, o método Enqueuetoast foi chamado para colocar a torrada atual na fila de torradas do sistema. Os parâmetros da passagem são PKG, TN e MDURATION. Em outras palavras, usamos o Toast.MakeText (contexto, msg, Toast.Length_Show) .Show () para apresentar uma torrada. O sistema chama o método SHOW e OCED do objeto TN de retorno de chamada para exibir e ocultar a torrada.
A classe de implementação específica da interface INOFITICANAGER aqui está a classe NotificationManagerService, localizada em estruturas/base/serviços/java/com/server/notificationManagervice.java.
Primeiro, vamos analisar as funções da entrada do Toast no Enqueuetoast.
Public void enqeuetoast (string pkg, retorno de chamada ItransientNotification, duração int) {// packagename é nulo ou classe tn como nula. ) ||. (PKG, Binder.getCallinguid ()) &&! // (2) Veja se a torrada já tem índice int = i ndexoftOastlocked (PKG, retorno de chamada); get (índice); registro.Update (duração);} else {// Torrada não -sistema, cada PKG está atualmente, o número total de torradas no mtoastqueue não pode exceder o max_package_notificações se (! IssystemToast) {int count = 0; final int n = mtoastqueue.size (); ++; ToAstrecord Objetos e coloca -os no Mtoastqueue. ) Se o índice for 0, significa que a equipe de entrada atual está na equipe. }}} Pode -se observar que fiz um breve comentário sobre o código acima. O código é relativamente simples, mas existem 4 pontos de código de nota que exigem que discutamos mais.
(1) Determine se é a torrada do sistema. Se o nome do pacote da torrada atual for "Android", é a torrada do sistema; caso contrário, você também poderá chamar o método iSCallerSystem () para julgar. O código fonte de implementação deste método é:
Boolean isuidsystem (int uid) {final int appid = userHandle.getAppid (uid); ());} O código -fonte do ISCALLERSYSTEM é relativamente simples, ou seja, para determinar se o UID do processo de brinde atual é um dos system_uid, 0, Phone_uid, se for, é a torrada do sistema; brinde.
Seja uma torrada do sistema, leia o código -fonte abaixo, pode -se ver que existem duas vantagens principais:
A torrada do sistema pode definitivamente entrar na fila de torradas do sistema e não será interrompida pela lista negra.
A torrada do sistema não possui o limite de quantidade na fila de torradas do sistema, enquanto a torrada enviada pelo PKG comum tem o limite de quantidade na fila de torradas do sistema.
(2) Veja se a torrada a ser confiada à equipe já está na fila de torradas do sistema. Isso é conseguido comparando o PKG e o retorno de chamada.
Private Int IndexoToastlock (String PKG, ItransientNotification Retorno de chamada) {Ibinder CBAK = Callback.ASBinder (); ++) {Toastrecord r = list.get (i); Através do código acima, podemos tirar uma conclusão de que, desde que o nome PKG da torrada seja consistente com o objeto TN, o sistema considere essas torradas como a mesma torrada.
(3) Defina o processo de brinde atual como o processamento da recepção. O código -fonte é mostrado abaixo:
Void privado keepprocessalivened (int pid) {int ToastCount = 0; list.get (i); 't Acontece.}} O MAM = ActivityManagernative.getDefault () aqui chama o método setProcessFeRound para colocar o processo PID atual no processamento da recepção para garantir que ele não seja morto sistematicamente. Isso também explica por que, quando terminamos a atividade atualmente, a torrada também pode ser exibida porque o processo atual ainda é executado.
(4) Quando o índice é 0, a torrada da cabeça da fila é exibida. O código -fonte é o seguinte:
Void privado mostrou -se o ToAstrecord Record = Mtoastquee.get (0); (); a lista e deixe o Procese int index = mtoastqueue.indexOf (registro); = mtoastqueue.get (0);} else {registro = null;}}}}O objeto de retorno de chamada da torrada é o objeto TN. Em seguida, vamos dar uma olhada, por que o tempo de exibição do System Toast pode ser apenas 2s ou 3.5s, a chave é a implementação do método ScheduleTimeOutlocked. O princípio é que, depois de chamar o método Show of TN para exibir torradas, você precisa ligar para o método ScheduletMelocklockeded para desaparecer a torrada. (Se você tem alguma dúvida: para não dizer que o método oculto do objeto TN desapareça brinde, por que chamar o método de scheduletimeoutLock aqui para desaparecer torradas? Porque assim que o método de oculto da classe TN for executado, a torrada desaparece imediatamente , e geralmente temos nosso escritório. 使用的 brinde 都会在当前 Atividade 停留几秒。如何实现停留几秒呢?原理就是 AgendleTimeOutlocked 发送 Message_timeout 消息去调用 tn 对象的 ocultar 方法 , 但是这个消息会有一个 Atraso 延迟 , 这里 这里也是用了 Manipulador 消息机制)。
Private estático int long_delay = 3500; Long Atraso = R.Duration == Toast.Length_long?
Primeiro de tudo, vimos que isso aqui não enviou a mensagem Message_timeout diretamente, mas houve um atraso no atraso. O tempo de atraso de "Longo Atraso = R.Duration == Toast.Length_long? Long_dlay: Short_dlay;" 2s ou 3.5s. É inútil passar uma duração no método Toast.MakeText à vontade.
Em seguida, vamos dar uma olhada em como as mensagens message_timeout são processadas no trabalhador. O tipo de objeto Mhandler é trabalhador, o código -fonte é o seguinte:
Classe final Private WorkerHandler estende o manipulador {@Override public void HandleMessage (Mensagem MSG) {Switch (Msg.what) {case message_timeout: handleti meout (toastrecord) msg.obj;Pode -se observar que o processamento da mensagem do WorkRhandler para o tipo Message_timeout é chamar o método HandlerTimeout.
Void privado HandleTimeout (ToAstrecord Register) {Sincronizado (mtoastqueue) {int index = indexoftoastlocked (Record.pkg, Record.Callback);No código HandleTimeout, primeiro determine se o objeto Toastrecord que precisa ser desaparecido está na fila. A verdade está prestes a aparecer na nossa frente, continue rastreando o código -fonte:
Private vazio canceltoastlocked (int index) {toastrecord registro = mtoastqueue.get (index); // A lista de qualquer maneira} mtoastqueue.remove (índice); A lista, assim como as doações que a lista não mudou // após este ponto. Haha, veja aqui, o método oculto do nosso objeto de retorno de chamada também foi chamado e também é removido do Mtoastqueue do Mtoastqueue. Neste ponto, a exibição completa e o desaparecimento da torrada terminam.