Implementasi kode sumber bersulang
Pintu masuk roti panggang
Ketika kami menggunakan prompt roti panggang dalam aplikasi, kami umumnya membuat panggilan kode sederhana, seperti yang ditunjukkan di bawah ini:
[Java] Lihat PlainCopyPrint?
Toast.maketext (konteks, msg, toast.length_short) .show ();
Maketext adalah pintu masuk roti bakar. Kode sumber adalah sebagai berikut (Frameworks/Base/Core/Java/Android/Widget/Toast.java):
Public Toast MakeText (Konteks Konteks, Teks Charsequence, Durasi Int) {Toast Hasil = Toast Baru (Konteks); Internet.r.layout.transient_notification, null); Durasi;Dari kode sumber MakeText, kita dapat melihat bahwa file tata letak roti panggang adalah transient_notification.xml, yang terletak di Frameworks/Base/Core/Res/Layout/Transition_notification.xml:
<? Versi XML = "1.0" encoding = "UTF-8"?> <linearlayout xmlns: android = "http://schemas.android.com/apk/android" android: layout_width = "match_parent" android: layout_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 ="#BB0000 "dan DAN Brightground_Dark": ShadowColor = "#BB0000" dan dan GREATHEGROGED " Shadowradius = "2.75" /> < /linearlayout>
File tata letak dari roti bakar sistem sangat sederhana, yaitu, TextView ditempatkan di linearlayout dari tata letak vertikal. Selanjutnya, kami terus mengikuti metode show () untuk mempelajari implementasi kode tampilan setelah tata letak dibentuk:
public void () {if (mnextView == null) {throw runimeException baru ("SetView pasti telah dipanggil"); ; Ada dua poin dalam metode acara yang perlu kita perhatikan. (1) Apa itu TN? (2) Peran Layanan Manajemen Inotification. Dengan dua masalah ini, lanjutkan kode sumber roti panggang kami.
Kode Sumber TN
Banyak pertanyaan dapat menemukan jawabannya melalui kode sumber. Implementasi MTN dalam konstruktor Toast, kode sumber adalah sebagai berikut:
Toast Publik (Konteks) {Mcontext = Context; () .getInteger (com.android.internal.r.iinteger.config_toastdefaultgravity);}Selanjutnya, kita mulai dari kode sumber kelas TN untuk mengeksplorasi peran TN. Kode sumber TN adalah sebagai berikut:
Private Static Class TN memperluas itransitenotification.stub {final runnable mshow = runnable baru () {@Override public void run () {handless ();}; (); ; dengan tepat WindowManager.layoutparams.type_toast; Params.privateflags = WindowManager.layoutparams.private_flag_for_all_users; .post (mshow);} / ** * Jadwal Telana Insto utas yang tepat * / @Override public void hide () {if (locallogv) log.v (tag (tag "sembunyikan:" + ini); mhandler.post ( mHide);} public void handleshow () {if (locallogv) log.v (tag, "handle show:" + this + "mview =" + mview + "xtview =" + mnextView); {// Hapus tampilan lama jika perlu TOLEHIDE (); (WindowManager) Context.GetSystemservice (Context.Window_Service); Final Int Gravity = Gravity.getAbsolutegravity (mGravity, config.getLayoutDirection ()); (Gravity & Gravity.Vertical_gravity_mask) == gravity.fill_vertical) {mparams.verticalweats = 1.0 f;} mparams.x = mx; getParent ()! = null) {if (locallogv) log.v (tag, "remov!" + mview + " + this); mwm.re moveview (mview);} if (locallogv) log.v (tag," Tambahkan! " + MView +" di " + this); mwm.addview (mview, mparams); trysendac senseEvent ();}}} daccescessibilityEvent () {accessibleManagerManager = accessibleManager. getInstance (mview.getContext (); (! AccessibleManager. DispatchPopultAccessibilityEvent (acara); = null) {// tidak: memeriksa cat () hanya untuk membuat. Cobalah untuk tidak macet. Melalui kode sumber, kita dapat dengan jelas melihat hubungan warisan. Diasumsikan bahwa pembaca memiliki dasar komunikasi antara proses Android (tidak diketahui untuk mempelajari serangkaian blog komunikasi Luo Shengyang tentang komunikasi proses pengikat). Karena TN digunakan untuk komunikasi antar -proses, mudah bagi kita untuk berpikir bahwa peran spesifik dari kelas TN harus menjadi objek callback dari kelas bersulang. kelas TN.
Kelas TN diwarisi dari itransitenotification.stub, itransientNotification.aidl terletak di kerangka kerja/basis/inti/java/app/itransientNotification.aidl, kode sumber adalah sebagai berikut: sebagai berikut:
paket android.app; / ** @hide* / oneway antarmuka itransientNotification {void show ();ITransientNotification mendefinisikan dua metode show () dan hide (), dan implementasi spesifiknya ada di kelas TN. Implementasi kelas TN adalah:
/ ***Jadwal menangani ke utas yang tepat* / @Override public void show () {if (locallogv) log.v (tag, "show:" + this); */ @Override public void hide () {if (locallogv) log.v (tag, "hide:" + this);Di sini kita dapat mengetahui bahwa Toast's Show and Sembunyikan Implementasi Metode didasarkan pada mekanisme pawang. Implementasi penangan di kelas TN adalah:
Handl final mhandler = handler baru ();
Selain itu, kami tidak menemukan metode looper.perpare () dan looper.loop () di kelas TN. Ini menunjukkan bahwa Mhandler memanggil objek looper dari utas saat ini. Oleh karena itu, ketika kita berada di utas utama (yaitu, di utas UI), kita dapat memanggil metode Toast.maketext sesuka hati, karena sistem Android membantu kita untuk mewujudkan inisialisasi looper dari utas utama.但是 , 如果你想在子线程中调用 toast.maketext 方法 , 就必须先进行 looper 初始化了 , 不然就会报出 java.lang.runtimeException: Tidak dapat membuat pawang di dalam utas yang belum disebut looper.prepare () Esensi Pembelajaran mekanisme penangan dapat merujuk ke blog yang saya tulis sebelumnya: http://blog.csdn.net/wzy_1988/article/details/38346637.
Selanjutnya, terus ikuti implementasi mshow dan mhide, yang keduanya dapat dijalankan.
Final runnable mshow = runnable baru () {@Override public void run () {handleshow ();}}; handleshow () mnextView = null;}}; Dapat dilihat bahwa implementasi nyata dari Show dan Hide adalah untuk memanggil metode Handleshow () dan Tloehide (). Mari kita lihat implementasi spesifik Handleshow ():
public void handleshow () {if (mview! = mnextView) {// Hapus tampilan lama jika perlu tegang (); ) {context = mview.getContext ();} mwm = (windowManager) context.getsystemservice (context.window_service); .getContext () .getResources (). .fill_horizontal) {mparams.horizontalweight = 1.0f;} if (gravity & gravity.vertical_gravity_mask) == gravity.fill_vertical) {mparams.verticalweight = 1.0 f;} mparams.x = mx; = MverticalMargin; Dari kode sumber, kita tahu bahwa Toast dimuat di AddView melalui WindowManager. Oleh karena itu, metode Hide secara alami adalah WindowManager untuk memanggil metode RepoVeView untuk menghapus tampilan Toast.
Singkatnya, dengan menganalisis kode sumber kelas TN, kita tahu bahwa kelas TN adalah objek callback, dan proses lain memanggil metode show dan sembunyikan kelas TN untuk mengontrol tampilan dan hilangnya roti panggang ini.
NotificationManagerservice
Kembali ke metode pertunjukan kelas roti panggang, kita dapat melihat bahwa GetService dipanggil di sini untuk mendapatkan layanan InotificationManager.
Private Static InotificationManager SService; Statis Private InotificationManager GetService () {if (sService! = Null) {return sService;} sService = di otifinager.stub.asinterface (serviceManager.getService ("notifikasi"); return ssrevice;}; Setelah mendapatkan layanan InotificationManager, metode EnqueueToast dipanggil untuk memasukkan roti bakar saat ini ke dalam antrian roti panggang sistem. Parameter pass adalah PKG, TN dan Mduration. Dengan kata lain, kami menggunakan Toast.makeText (konteks, msg, toast.length_show) .show () untuk menyajikan roti panggang. Sistem memanggil metode show dan sembunyikan objek callback TN untuk menampilkan dan menyembunyikan roti panggang.
Kelas implementasi spesifik dari antarmuka inofiticanager di sini adalah kelas NotificationManagerservice, yang terletak di Frameworks/Base/Services/Java/Com/Server/notificationManAgervice.java.
Pertama -tama, mari kita menganalisis fungsi masuk Toast ke dalam enqueuetoast.
Public void enqeuetoast (string pkg, itransientNotification callback, int durasi) {// packageName adalah null atau kelas tn sebagai null. ) ||. (Pkg, binder.getCallinguid ()) &&! // (2) Lihat apakah roti panggang sudah int index = i ndexoftoastlocked (pkg, callback); get (index); int n = mtoastqueue.size (); untuk (int i = 0; i <n; i ++) {final toastrecord r = mtoastqueue.get (i); ++; if (count> = max_package_notifications) {slog.e (tag, "Paket telah memposting" + hit Objek Toastrecord dan menempatkannya di mtoastqueue. ) Jika indeks adalah 0, itu berarti bahwa tim entri saat ini ada di tim. }}} Dapat dilihat bahwa saya membuat komentar singkat tentang kode di atas. Kode ini relatif sederhana, tetapi ada 4 poin kode catatan yang mengharuskan kita untuk membahas lebih lanjut.
(1) Tentukan apakah itu roti panggang sistem. Jika nama paket roti panggang saat ini adalah "Android", itu adalah sistem roti panggang, jika tidak, Anda juga dapat memanggil metode iscallersystem () untuk menilai. Kode sumber implementasi dari metode ini adalah:
Boolean isuidsystem (int uid) {final int appid = userhandle.getappid (uid); ());} Kode sumber iscallersystem relatif sederhana, yaitu, untuk menentukan apakah UID dari proses roti panggang saat ini adalah salah satu dari System_uid, 0, phone_uid, jika itu, itu adalah roti bakar sistem; roti panggang.
Apakah itu roti panggang sistem, baca kode sumber di bawah ini, dapat dilihat bahwa ada dua keuntungan utama:
Toast sistem pasti dapat memasuki sistem roti panggang sistem, dan tidak akan dihentikan oleh daftar hitam.
Toast sistem tidak memiliki batas kuantitas dalam antrian bersulang sistem, sedangkan roti panggang yang dikirim oleh PKG biasa memiliki batas kuantitas dalam antrian bersulang sistem.
(2) Lihat apakah roti panggang yang akan dipercayakan kepada tim sudah ada dalam sistem roti panggang. Ini dicapai dengan membandingkan PKG dan Callback.
Private INCOfOtoastlocked (String PKG, ITRANSIENTNOTIFIKASI Callback) {Ibinder cbak = callback.asbinder (); ++) {toastrecord r = list.get (i); Melalui kode di atas, kita dapat menarik kesimpulan bahwa selama nama PKG roti panggang konsisten dengan objek TN, sistem menganggap roti panggang ini sebagai roti bakar yang sama.
(3) Atur proses roti panggang saat ini sebagai pemrosesan meja depan. Kode sumber ditampilkan di bawah ini:
Private Void Keepprocessaliveed (int pid) {int toastcount = 0; list.get (i); if (r.pid == pid) {toastcount ++;}} coba {mam.setProcessForeground (mforegrounttoken, pid, toastcount> 0);} Cat. 't terjadi.}} MAM = ActivityManAgernative.getDefault () di sini menyebut metode SetProcessForeGround untuk menempatkan proses PID saat ini ke dalam pemrosesan meja depan untuk memastikan bahwa itu tidak akan dibunuh secara sistematis. Ini juga menjelaskan mengapa ketika kami menyelesaikan aktivitas saat ini, Toast juga dapat ditampilkan karena proses saat ini masih dijalankan.
(4) Ketika indeks adalah 0, bersulang kepala antrian ditampilkan. Kode sumber adalah sebagai berikut:
Void Private ShowEttoAtLocked () {// Dapatkan Toastrecord Toastrecord Record = mtoastqueue.get (0); (); Daftar dan Biarkan Indeks Int Procese = mtoastqueue.indexof (Rekaman); = mtoastqueue.get (0);} else {Record = null;}}}Objek Callback Toast adalah objek TN. Selanjutnya, mari kita lihat, mengapa waktu tampilan bersulang sistem hanya 2s atau 3.5s, kuncinya adalah implementasi metode scheduletimeoutlocked. Prinsipnya adalah bahwa setelah memanggil metode acara TN untuk menampilkan roti panggang, Anda perlu memanggil metode jadwal dengan bersulang untuk menghilang. (Jika Anda memiliki pertanyaan: bukan untuk mengatakan bahwa metode hide dari objek TN untuk menghilang bersulang, mengapa memanggil metode jadwal yang terkurung terkunci di sini untuk menghilang roti panggang? Karena segera setelah metode hide dari kelas TN dieksekusi, roti panggang segera menghilang menghilang , dan kami biasanya memiliki kantor kami. 使用的 Toast 都会在当前 aktivitas 停留几秒。如何实现停留几秒呢?原理就是 jadwal outlocked 发送 message_timeout 消息去调用 tn 对象的 sembunyikan 方法 , 但是这个消息会有一个 但是这个消息会有一个 但是这个消息会有一个 , , , , , , , , , ,也是用了 Handler 消息机制)。
Private static int long_delay = 3500; // 3,5 detik static final int short_dlay = 2000; Long Delay = R.Duration == Toast.length_long?
Pertama -tama, kami melihat bahwa ini di sini tidak mengirim pesan pesan_timeout secara langsung, tetapi ada penundaan penundaan. Waktu penundaan dari "Long Delay = R.Duration == Toast.length_long? Long_dlay: Short_dlay; 2s atau 3.5s. Tidak ada gunanya melewati durasi dalam metode Toast.makeText sesuka hati.
Selanjutnya, mari kita lihat bagaimana pesan message_timeout diproses di WorkerHandler. Jenis objek Mhandler adalah WorkerHandler, kode sumbernya adalah sebagai berikut:
Private Final Class WorkerHandler Extends Handler {@Override public void handlemessage (pesan pesan) {switch (msg.what) {case message_timeout: handleti meout (toastrecord) msg.obj;Dapat dilihat bahwa pemrosesan pesan dari WorkRHandler ke jenis message_timeout adalah untuk memanggil metode handlerTimeout.
Private void handletimeout (Toastrecord Record) {disinkronkan (mtoastqueue) {int index = indexOftoastlocked (Record.pkg, Record.callback);Dalam kode handletimeout, pertama -tama tentukan apakah objek Toastrecord yang perlu dihilang dalam antrian. Kebenaran akan muncul di depan kita, terus melacak kode sumber:
Private void canceltoastlocked (int index) {toastrecord record = mtoastqueue.get (index); // Daftar} mtoastqueue.remove (indeks); Daftar, begitu pula Donform bahwa daftar itu tidak berubah // setelah titik ini. Haha, lihat di sini, metode hide dari objek callback kami juga telah dipanggil, dan juga dihapus dari mtoastqueue dari mtoastqueue. Pada titik ini, tampilan lengkap dan hilangnya roti panggang sudah berakhir.