تنفيذ رمز المصدر المحمص
مدخل نخب
عندما نستخدم مطالبات الخبز المحمص في التطبيق ، نقوم عمومًا بإجراء مكالمة رمز بسيطة ، كما هو موضح أدناه:
[Java] عرض PlaincopyPrint؟
Toast.MakeText (السياق ، msg ، toast.length_short) .show () ؛
Maketext هو مدخل الخبز المحمص. الرمز المصدر هو كما يلي (الأطر/القاعدة/الأساسية/Java/Android/Widget/Toast.java):
نخب ثابتة (سياق السياق ، نص charsepr ، internet.r.layout.transient_notification ، TextView TV = (TextView) المدة ؛
من الكود المصدري لـ maketext ، يمكننا أن نرى أن ملف تخطيط الخبز المحمص هو transient_notification.xml ، الموجود في الأطر/القاعدة/الأساسية/الدقة/التصميم/transition_notification.xml:
<إصدار XML = "1.0" charcoding = "utf-8"؟> <linearlayout match_parent "Android: extrection =" vertical "Android: Background ="؟ "WRAP_CONTENT" Android: layout_weight = "1" Android: layout_gravity = "center_horizontal" Android: textapperance = "@style/textaperance.toast" "Android: textColor ="@color/bright_dorground_dark Shadowradius = "2.75" /> </linearlayout>
ملف تخطيط نخب النظام بسيط للغاية ، أي يتم وضع TextView في Linearlayout للتخطيط العمودي. بعد ذلك ، نستمر في متابعة طريقة العرض () لدراسة تطبيق رمز العرض بعد تشكيل التخطيط:
show public void () {if (mnextView == NULL) ؛ هناك نقطتان في طريقة العرض التي نحتاج إلى الانتباه إليها. (1) ما هو TN؟ (2) دور خدمة inotificationManager. مع هاتين المشكلتين ، تابع رمز مصدر الخبز المحمص.
رمز المصدر TN
يمكن أن تجد العديد من الأسئلة الإجابة من خلال الكود المصدري. تنفيذ MTN في مُنشئ الخبز المحمص ، رمز المصدر هو كما يلي:
توست (سياق السياق) {mcontext = سياق ؛ ().بعد ذلك ، نبدأ من الكود المصدري لفئة TN لاستكشاف دور TN. رمز مصدر TN كما يلي:
يمتد الفئة الثابتة الخاصة tn itransitenotification.stub {Final Runnable Mshow = new RunNable () {Override public void run () () ؛ ؛ بشكل مناسب 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) ؛} / ** * الجدول عن طريق الجدول عن طريق القبض على مؤشر الترابط الأيمن * / Override public void Hide () {if (locallogv) log.v (tag (tag "hide:" + this) ؛ mhandler.post ( mhide) ؛} public void learleshow () {if (locallogv) log.v (tag ، "handle show:" + this + "mview =" + mview + "xtview =" + mnextView) ؛ {// إزالة العرض القديم إذا لزم الأمر (WindowManager) سياق. الجاذبية النهائية = الجاذبية. (Gravity & Gravity. getParent ()! = null) {if (locallogv) log.v (tag ، "requov! أضف! " + mview +" in " + this) ؛ mwm.addview (mview ، mParams) ؛ trysendac senseevent () ؛}}}} daccessibilityevent () (! Accessiblemanager.isenabled ()) DispatchPultActibleEvent (Event) ؛ = NULL) {// لا: التحقق من الطلاء () فقط إلى MAK. حاول عدم التعطل. من خلال رمز المصدر ، من الواضح أننا نرى علاقة الميراث. من المفترض أن يكون لدى القراء أساس التواصل بين عملية Android (غير معروف جيدًا لتعلم سلسلة من مدونات تواصل Luo Shengyang على اتصال عملية الموثق). نظرًا لأن TN يستخدم للاتصال بين العمليات ، فمن السهل علينا أن نفكر في أن الدور المحدد لفئة TN هو كائن رد الاتصال في فئة الخبز المحمص. فئة TN.
يتم موروث فئة TN من itransitenotification.stub ، itransientNotification.aidl تقع في الأطر/القاعدة/الأساسية/java/app/itransientnotification.aidl ، رمز المصدر هو كما يلي: كما يلي:
Package Android.App ؛
يعرّف ItransientNotification طريقة عرضين () و Hide () ، وتنفيذها المحدد في فئة TN. تنفيذ فئة TN هو:
/ ***الجدول الزمني في الخيط الأيمن* / Override public void show () {if (locallogv) log.v (tag ، "show:" + this) ؛ */ Override public void Hide () {if (locallogv) log.v (tag ، "Hide:" + this) ؛هنا يمكننا أن نعرف أن تطبيق Toast و Hide Method يعتمد على آلية المعالج. تطبيق المعالج في فئة TN هو:
HANDL HANDL MANDLER = New Handler () ؛
علاوة على ذلك ، لم نجد أي طرق looper.perpare () و looper.loop () في فئة TN. يوضح أن Mhandler يستدعي كائن Looper للمعلومات الحالية. لذلك ، عندما نكون في الخيط الرئيسي (أي في مؤشر ترابط واجهة المستخدم) ، يمكننا استدعاء Toast.Maketext طريقة الإرادة ، لأن نظام Android يساعدنا على إدراك تهيئة Looper للخيط الرئيسي.但是 , 如果你想在子线程中调用 توست. جوهر يمكن أن يشير تعلم آلية المعالج إلى مدونة كتبت من قبل: http://blog.csdn.net/wzy_1988/article/details/38346637.
بعد ذلك ، استمر في متابعة تنفيذ Mshow و Mhide ، وكلاهما يمكن تشغيله.
Final Runnable Mshow = new Runnable () handleshow () mnextView = null ؛}} ؛
يمكن ملاحظة أن التنفيذ الحقيقي للعرض والاختباء هو استدعاء الأساليب () وطرق المقابض () ، على التوالي. دعونا نلقي نظرة على التنفيذ المحدد لـ Handleshow ():
public void learleshow () {if (mview! = mnextView) {// إزالة العرض القديم إذا لزم الأمر )) . .fill_horizontal) {mparams.horizontalweight = 1.0f ؛} if (gravity & gravity.vertical_gravity) == gravity.fill_vertical) = mverticalmargin ؛ من رمز المصدر ، نعلم أن Toast يتم تحميله في Addview من خلال WindowManager. لذلك ، فإن طريقة الاختباء هي بشكل طبيعي في WindowManager للاتصال بالطريقة RemoveView لإزالة عرض الخبز المحمص.
لتلخيص ، من خلال تحليل الكود المصدري لفئة TN ، نعلم أن فئة TN هي كائن رد اتصال ، وعمليات أخرى تستدعي طريقة العرض وإخفاء فئة TN للتحكم في العرض واختفاء هذا الخبز المحمص.
إخطار MORSERSEVICE
بالعودة إلى طريقة العرض في فئة Toast ، يمكننا أن نرى أن GetService يتم استدعاؤه هنا للحصول على خدمة inotificationManager.
inotification inotification inotification sservice الثابتة الثابتة ؛
بعد الحصول على خدمة inotificationManager ، تم استدعاء طريقة enqueuetoast لوضع الخبز المحمص الحالي في قائمة انتظار الخبز المحمص للنظام. معلمات المرور هي PKG و TN و MDURINT. بمعنى آخر ، نستخدم Toast.Maketext (السياق ، MSG ، Toast.length_show). يستدعي النظام طريقة العرض وإخفاء كائن رد الاتصال TN لعرض الخبز المحمص وإخفاءه.
فئة التنفيذ المحددة لواجهة Inofiticanager هنا هي فئة SotificationManagerservice ، الموجودة في Frameworks/Base/Services/Java/Com/Server/NotificationManagervice.java.
بادئ ذي بدء ، دعنا نحلل وظائف دخول Toast إلى Enqueuetoast.
public void enqeuetoast (سلسلة pkg ، رد الاتصال itransientNotification ، مدة int) {// packagename هي فئة خالية أو tn كـ null alback. ) || (pkg ، binder.getCallinguid ()) &&! // (2) عرض ما إذا كان الخبز المحمص بالفعل int index = i ndexoftoastlocked (pkg ، callback) ؛ GET (INDEX) ؛ int n = mtoastqueue.size () ؛ ++ ؛ كائنات toastRecord ويضعها في mtoastqueue. ) إذا كان الفهرس 0 ، فهذا يعني أن فريق الدخول الحالي في الفريق. }}} يمكن ملاحظة أنني أدليت بتعليق موجز على الرمز أعلاه. الرمز بسيط نسبيًا ، ولكن هناك 4 نقاط من رمز الملاحظة تتطلب منا مناقشة المزيد.
(1) تحديد ما إذا كان نخب النظام. إذا كان اسم حزمة الخبز المحمص الحالي هو "Android" ، فهو نخب النظام ، وإلا يمكنك أيضًا استدعاء طريقة isCallersystem () للحكم. رمز مصدر التنفيذ لهذه الطريقة هو:
Boolean isuidsystem (int uid) {final int appid = userHandle.getAppId (uid) ؛ ()) ؛} رمز المصدر لنظام iscallersystem بسيط نسبيًا ، أي تحديد ما إذا كان UID لعملية الخبز المحمص الحالي أحد System_UID ، 0 ، phone_uid ، إذا كان ذلك ، فهو نخب النظام ؛ نخب.
سواء كان نخب النظام ، اقرأ من خلال الكود المصدري أدناه ، يمكن ملاحظة أن هناك مزايزتان رئيسيتان:
يمكن لنخب النظام بالتأكيد إدخال قائمة انتظار System Toast ، ولن يتم إيقافه بواسطة القائمة السوداء.
لا يحتوي نخب النظام على حد الكمية في قائمة انتظار System Toast ، في حين أن الخبز المحمص المرسل بواسطة PKG العادي له حد الكمية في قائمة انتظار System Toast.
(2) تعرف على ما إذا كان الخبز المحمص الذي سيتم تكليفه للفريق موجود بالفعل في قائمة انتظار النظام المحمص. يتم تحقيق ذلك من خلال مقارنة PKG ورد الاتصال.
Private IndexoftoActed (سلسلة PKG ، ItransientNotification) ++) {toastRecord r = list.get (i) ؛ من خلال الكود أعلاه ، يمكننا استخلاص أنه طالما أن اسم Toast الخاص بـ PKG يتوافق مع كائن TN ، فإن النظام يعتبر هذه الخبز المحمص نفس الخبز المحمص.
(3) اضبط عملية الخبز المحمص الحالي كمعالجة مكتب الاستقبال. يظهر رمز المصدر أدناه:
private void keepprocessaliveled (int pid) {int toastcount = 0 ؛ list.get (i) ؛ يحدث.}} MAM = ActivityManagerNative.getDefault () هنا يدعو إلى طريقة setProcessForeground لوضع عملية PID الحالية في معالجة مكتب الاستقبال لضمان عدم قتلها بشكل منهجي. وهذا ما يفسر أيضًا سبب الانتهاء من النشاط حاليًا ، يمكن أيضًا عرض الخبز المحمص لأن العملية الحالية لا تزال تنفذ.
(4) عندما يكون الفهرس 0 ، يتم عرض نخب رأس قائمة الانتظار. رمز المصدر كما يلي:
private extrecttoasttoastrolched () {// احصل على سجل toastrecord = mtoastqueue.get (0) ؛ () ؛ القائمة والسماح لـ procese int index = mtoastqueue.indexof (record) ؛ = mtoastqueue.get (0) ؛} آخر {سجل = null ؛}}}}كائن رد الاتصال من الخبز المحمص هو كائن TN. بعد ذلك ، دعنا نلقي نظرة ، لماذا لا يمكن أن يكون وقت عرض System Toast فقط 2s أو 3.5s ، والمفتاح هو تنفيذ طريقة ScheduletimeOtlocked. المبدأ هو أنه بعد استدعاء طريقة العرض لـ TN لعرض الخبز المحمص ، تحتاج إلى استدعاء طريقة ScheduleTmelocked للاختفاء الخبز المحمص. (إذا كان لديك أي أسئلة: لا تقل أن طريقة إخفاء كائن TN للاختفاء الخبز المحمص ، فلماذا استدعاء طريقة ScheduleTieTlocked هنا لتختفي الخبز المحمص؟ لأنه بمجرد تنفيذ طريقة إخفاء فئة TN ، يختفي الخبز المحمص على الفور ، وعادة ما يكون لدينا مكتبنا. 使用的 نخب 都会在当前 النشاط 停留几秒。如何实现停留几秒呢?原理就是 scheduleTimeOtlocked 发送 message_timeout 消息去调用 tn 对象的 Hide 方法 , 但是这个消息会有一个 但是这个消息会有一个 延迟 , 这里 这里也是用了 المعالج 消息机制)。
int static int long_delay = 3500 ؛ تأخير طويل == toast.length_long؟
بادئ ذي بدء ، رأينا أن هذا هنا لم يرسل رسالة message_timeout مباشرة ، ولكن كان هناك تأخير في التأخير. وقت التأخير من "التأخير الطويل = R.Duration == Toast.length_long؟ Long_dlay: Short_dlay ؛" 2S أو 3.5S. من غير المجدي تمرير مدة في طريقة toast.maketext في الإرادة.
بعد ذلك ، دعنا نلقي نظرة على كيفية معالجة رسائل message_timeout في العامل. نوع كائن mhandler هو العامل ، والرمز المصدر هو كما يلي:
يمتد WorkerHandler من الدرجة النهائية المعالج {Override public void handlemessage (message msg) {switch (msg.what) {case message_timeout: handleti meout (toastrecord) msg.obj ؛يمكن ملاحظة أن معالجة الرسائل لـ Workrandler to the Message_timeout type هي استدعاء طريقة HandlerTimeout.
private void handletimeout (سجل toastRecord) {synchronized (mtoastqueue) {int index = indexoftoClocked (record.pkg ، record.callback) ؛في رمز handletimeout ، حدد أولاً ما إذا كان كائن ToastRecord الذي يحتاج إلى اختفاء في قائمة الانتظار. الحقيقة على وشك الظهور أمامنا ، واصل تتبع رمز المصدر:
private void canceltoastlocked (int index) {toastRecord Record = mtoastqueue.get (index) ؛ // القائمة على أي حال} mtoastqueue.remove (index) ؛ القائمة ، وكذلك الحال بالنسبة إلى أن القائمة لم تتغير // بعد هذه النقطة. هاها ، انظر هنا ، تم استدعاء طريقة إخفاء كائن رد الاتصال لدينا أيضًا ، ويتم إزالتها أيضًا من mtoastqueue من mtoastqueue. في هذه المرحلة ، انتهى العرض الكامل واختفاء الخبز المحمص.