Реализация исходного кода тоста
Тост вход
Когда мы используем подсказки для тостов в приложении, мы обычно делаем простой кодовый вызов, как показано ниже:
[Java] Просмотреть PlainCopyPrint?
Toast.maketext (контекст, msg, toast.length_short) .show ();
MakeText - это вход Toast. Исходный код заключается в следующем (Frameworks/Base/Core/Java/Android/Widget/toast.java):
Общественный статический тост maketext (контекст контекста, текст Charbenty, int duration) {toast result = новый тост (контекст); Интернет Продолжительность;Из исходного кода MakeText мы видим, что файл макета Toast является transient_notification.xml, расположенный в Frameworks/base/core/res/mayout/transition_notification.xml:
<? Match_parent "Android: Orientation =" Vertical "Android: Founal ="? "wrap_content" Android: Mayout_weight = "1" Android: Layout_Gravity = "center_horizontal" Android: TextApperance = "@style/textaperance.toast" "Android: TextColor ="@color/bright_foreground_dark "Android: ShadowColor ="#bb000000 "android: android: android: android: android: android: android: android: android: Shadowradius = "2,75" /> < /linearlayout>
Файл макета системного тоста очень прост, то есть TextView помещается в линейную плату вертикальной макета. Далее мы продолжаем следовать методу Show () для изучения реализации кода дисплея после формирования макета:
public void show () {if (mnextview == null) {throw new runtimeexception ("setview должна быть названа"); ; В методе шоу есть два момента, на которые нам нужно обратить внимание. (1) Что такое TN? (2) Роль службы INOTICHITICENMAGER. С этими двумя проблемами, продолжайте наш тост -исходный код.
Исходный код TN
Многие вопросы могут найти ответ через исходный код. Реализация MTN в конструкторе Toast, исходный код заключается в следующем:
Public Toast (контекст) {McOntext = Context; () .getInteger (com.android.internal.r.iinteger.config_toastdefaultgravity);}Далее мы начинаем с исходного кода класса TN, чтобы исследовать роль TN. Исходный код TN выглядит следующим образом:
Private Static Class TN Extends itranSiteNotification.Stub {final Runnable mshow = new Runnable () {@Override public void run () {soundless ();}; (); ; Соответственно WindowManager.Layoutparams.type_toast; Params.Settital ("Toast"); Params.flags = WindowMana Ger.Layoutparams.flag_Keep_Screen_on | WindowManager.Layoutparams.flag_not_focusable | WindowManager.Layoutparams. Flag_not_touch; /// M: [Alps00517576] Support Multi-User Params.privateflags = windowmanager.layoutparams.private_flag_for_all_users; .post (mshow);} / ** * * ** * График handlehide insto правильный поток * / @@override public void hide () {if (locallogv) log.v (Tag (Tag "hide:" + this); mhandler.post ( mhide);} public void handleshow () {if (locallogv) log.v (tag, "handle show:" + this + "mview =" + mview + "xtview =" + mnextview); {/ Удалить старое представление при необходимости (Windowmanager) context.getSystemservice (context.window_service); Final int Gravity = Gravity.getabsolutegravity (mgravity, config.getlayoutdirection ()); (Gravity & Gravity.vertical_gravity_mask) == Gravity.fill_vertical) getParent ()! Добавить! " + mview +" in " + this); mwm.addview (mview, mparams); trysendac senseevent ();}}}} daccessibilityevent () {Accessibilation managemangemanger = accessibilmanger. getInstance (mview.getContext ()); (! Доступность manage.isenabled ()) {return;} // reate toasts как уведомления, так как используется // переходная часть информации, доступный для пользователя. DispatchPultAccessibilityEvent (Event); = null) {// not: проверить Paint () только для Mak. Постарайтесь не сбой. Через исходный код мы, очевидно, можем увидеть отношения наследования. Предполагается, что читатели имеют основу связи между процессом Android (не очень хорошо известно, чтобы изучить серию блогов об общении Луо Шенгьян в связи с обработкой связующего процесса). Поскольку TN используется для межпроцессной связи, нам легко думать, что конкретная роль класса TN должна быть объектом обратного вызова тоста. Класс TN.
Класс TN унаследован от itransiteNotification.stub, itransientNotification.aidl находится в Frameworks/Base/Core/Java/App/itransientNotification.aidl, исходный код заключается в следующем: следующее:
Пакет Android.App;
ItransientNotification определяет два метода Show () и Hide (), и их конкретная реализация находится в классе TN. Реализация класса TN:
/ ***График */ @Override public void hide () {if (locallogv) log.v (tag, "hide:" + this);Здесь мы можем знать, что реализация метода Show and Hide Show основана на механизме обработчика. Реализация обработчика в классе TN:
Окончательный handl mhandler = new Handler ();
Более того, мы не нашли никаких методов looper.perpare () и looper.loop () в классе TN. Это показывает, что Mhandler называет объект Looper текущего потока. Поэтому, когда мы находимся в основном потоке (то есть в потоке пользовательского интерфейса), мы можем вызвать метод Toast.makeText по желанию, потому что система Android помогает нам реализовать инициализацию основного потока.但是 , 如果你想在子线程中调用 toast.maketext 方法 , 就必须先进行 Looper 初始化了 , 不然就会报出 java.lang.runtimeexception: не может создать обработчик внутри нить, который не называется looper.prepare () Сущность Изучение механизма обработчика может относиться к блогу, который я написал ранее: http://blog.csdn.net/wzy_1988/article/details/38346637.
Далее, продолжайте следовать реализации Mshow и Mhide, оба из которых запускаются.
Окончательный runnable mshow = new Runnable () {@override public void run () {handleshow ();}}; handleshow () mnextview = null;}}; Можно видеть, что реальная реализация Show и Hide - это вызов Haydleshow () и Handlehide (), соответственно. Давайте посмотрим на конкретную реализацию handleshow ():
Public void Hayshow () {if (mview! = mnextview) {// Удалить старое представление при необходимости {context = mview.getContext ();} mwm = (windowmanager) context.getSystemservice (context.window_service); .getContext () .getresources (). .fill_horizontal) {mparams.horizontalight = 1.0f;} if (Gravity & Gravity.vertical_gravity_mask) == Гравитация = mverticalmargin; Из исходного кода мы знаем, что тост загружается в AddView через Windowmanager. Следовательно, метод скрыть, естественно, является Windowmanager, чтобы вызвать метод RemoveView, чтобы удалить вид тоста.
Подводя итог, анализируя исходный код класса TN, мы знаем, что класс TN является объектом обратного вызова, а другие процессы вызывают метод шоу и скрыть метод класса TN, чтобы управлять дисплеем и исчезновением этого тоста.
Уведомление, манагерсерв
Вернувшись в метод шоу класса Toast, мы видим, что Getservice вызывается здесь, чтобы получить службу INOTICANGEMANAGER.
Частный статический инотификация Manage Sservice;
После получения услуги INOTITIANGMANAGER был вызван метод EnqueToast, чтобы поместить текущий тост в тост системы. Параметры прохода - PKG, TN и Mduration. Другими словами, мы используем toast.maketext (контекст, msg, toast.length_show) .show () для представления тоста. Система вызывает метод шоу и скрыть метод обратного объекта TN, чтобы отобразить и скрыть тост.
Конкретный класс реализации интерфейса inofiticanager здесь - это класс Managerservice, расположенный в Frameworks/Base/Services/Java/Com/Server/Notificationmanagervice.java.
Прежде всего, давайте проанализируем функции входа Toast в EnqueToast.
Public void enqeuetoast (String pkg, ItransientNotification обратный вызов, int duration) {// packageName - это NULL или TN Class как NULL. ) ||. (Pkg, binder.getcallinguid ()) &&! // (2) Просмотреть, есть ли тост уже int index = i ndexoftoastced (pkg, обратный вызов); get (index); final int n = mtoastqueue.size (); ++; Toastrecord объектов и поместит его в Mtoastqueue. ) Если индекс равен 0, это означает, что текущая команда въезда находится в команде. }}} Видно, что я сделал краткий комментарий к приведенному выше коду. Код относительно прост, но есть 4 балла, которые требуют от нас обсуждения дальше.
(1) Определите, является ли это системным тостом. Если имя пакета текущего тоста - «Android», это тост системы, в противном случае вы также можете вызвать метод iscallersystem () для суждения. Исходный код реализации этого метода:
Boolean isuidsystem (int uid) {final int appid = userhandle.getappid (uid); ());} Исходный код Iscallersystem является относительно прост, то есть определить, является ли UID текущего процесса тоста одним из системных систем, 0, Phone_uid, если это так, это системный тост; тост.
Будь то системный тост, прочитайте исходный код ниже, можно увидеть, что есть два основных преимущества:
Системный тост может определенно войти в системную очередь тоста, и он не будет остановлен черным списком.
Системный тост не имеет предела количества в системной очереди тоста, в то время как тост, отправленный обычным PKG, имеет предел количества в системной очереди тоста.
(2) Посмотрите, будет ли тост, который будет поручен команде, уже в системной очереди для тостов. Это достигается путем сравнения PKG и обратного вызова.
Private int Indexoftoasted (String Pkg, ItransientNotification Callback) {ibinder cbak = callback.asbinder (); ++) {toastrecord r = list.get (i); Через приведенный выше код мы можем сделать вывод о том, что до тех пор, пока имя PKG тоста согласуется с объектом TN, система рассматривает их тост как один и тот же тост.
(3) Установите процесс текущего тоста в качестве обработки на стойке регистрации. Исходный код показан ниже:
Private void keepprocessalivelocked (int pid) {int toastCount = 0; list.get (i); Т. MAM = ActivityManagernative.getDefault () здесь вызывает метод SetProcessForeforeground, чтобы поместить текущий процесс PID в обработку на стойке регистрации, чтобы убедиться, что он не будет систематически убит. Это также объясняет, почему, когда мы заканчиваем активность в настоящее время, тост также может отображаться, потому что текущий процесс все еще выполняется.
(4) Когда индекс равен 0, отображается тост головки очереди. Исходный код заключается в следующем:
Private void indayexttoastced () {// Получить Toastercord toastercord record = mtoastqueue.get (0); (); Список и пусть Procese int index = mtoastqueue.indexof (record); = mtoastqueue.get (0);} else {record = null;}}}}Объектом обратного вызова тоста является объект TN. Далее, давайте посмотрим, почему время отображения системных тостов может составлять только 2 с или 3,5, ключом является реализация метода PradeTeMimeOutced. Принцип состоит в том, что после вызова метода шоу TN для отображения тостов вам нужно вызвать метод PradeLetMelocklocked для исчезновения. (Если у вас есть какие -либо вопросы: не говоря уже о том, что метод скрытия объекта TN исчезает Toast, зачем вызывать здесь метод PradeTemateUtclocked, чтобы исчезнуть? Потому что, как только метод скрытия класса TN выполняется, тост сразу исчезает? , и у нас обычно есть наш офис. 使用的 Toast 都会在当前 Activity 停留几秒。如何实现停留几秒呢?原理就是 停留几秒。如何实现停留几秒呢?原理就是 停留几秒。如何实现停留几秒呢?原理就是 停留几秒。如何实现停留几秒呢?原理就是 停留几秒。如何实现停留几秒呢?原理就是 停留几秒。如何实现停留几秒呢?原理就是 发送 发送 发送timeout 消息去调用 tn 对象的 скрыть 方法 , 但是这个消息会有一个 задержка 延迟 , 这里 这里 这里 这里 这里也是用了 обработчик 消息机制)。
Приватный статический финал int long_delay = 3500; Длинная задержка = R.duration == toast.length_long?
Прежде всего, мы увидели, что это здесь не отправило сообщение сообщением_timeout напрямую, но была задержка задержки. Время задержки из "Long Delay = R.Duration == toast.length_long? Long_dlay: short_dlay;" 2 или 3,5 с. Бесполезно проходить продолжительность в методе Toast.makeText по желанию.
Далее, давайте посмотрим, как сообщения Message_timeout обрабатываются в WorkerHandler. Тип объекта Mhandler - это работник -руска, исходный код заключается в следующем:
Приватный финальный класс Работник Храндлер Extends {@Override public void handlemessage (сообщение msg) {switch (msg.what) {case message_timeout: handleti meout (toastercord) msg.obj;Видно, что обработка сообщений Workrhandler к типу Message_timeout заключается в том, чтобы вызвать метод Handlertimeout.
Private void handletimeout (toastercord record) {synchronized (mtoastqueue) {int index = indexoftoastlocked (record.pkg, record.callback);В коде Handletimeout сначала определите, находится ли объект Toastrecord, который должен быть исчез, в очереди. Правда собирается появиться перед нами, продолжайте отслеживать исходный код:
Private void canceltoastlocked (int index) {toastrecord record = mtoastqueue.get (index); // В любом случае asture} mtoastqueue.remove (index); Список, так и Donforms, что список не изменился // после этого. Ха -ха, см. Здесь также был вызван метод скрытия нашего объекта обратного вызова, и он также удален из Mtoastqueue из Mtoastqueue. На этом этапе полное отображение и исчезновение тостов закончились.