ソースコードの実装をトーストします
トーストの入り口
アプリケーションでトーストプロンプトを使用すると、以下に示すように、通常、簡単なコード呼び出しを行います。
[Java] PlainCopyPrintを表示しますか?
toast.maketext(context、msg、toast.length_short).show();
Maketextは、Maketextのソースコードからのトーストの実装を理解しています。ソースコードは次のとおりです(Frameworks/base/core/java/android/widget/toast.java):
public static toast maketext(コンテキスト、チャーセクセンステキスト、int duration){toast result = new toast(context); Internet.R.Layout.Transient、Null);持続時間;}Maketextのソースコードから、ToastのレイアウトファイルがTransient_notification.xmlであることがわかります。
<?XMLバージョン= "1.0" encoding = "utf-8"? Match_Parent "Android:Orientation =" Vertical "Android:background ="? "wrap_content" android:layout_weight = "1" android:layout_gravity = "center_horizontal" android:textapperance = "@style/textaperance.toast" "android ="@coler/bright_foreground_dark "android:shadowcolor ="#bb0000 "android: Shadowradius = "2.75" /> < /linearlayout>
システムトーストのレイアウトファイルは非常に単純です。つまり、テキストビューは垂直レイアウトのリニアレイアウトに配置されます。次に、レイアウトが形成された後、ディスプレイコードの実装を調査するためにショー()方法に従っています。
public void show(mnextview == null){setviewが呼ばれている必要があります; {service.enqueuetoast(pkg、tn、mduration);} catch(// empty}}ショー方法には、注意が必要な2つのポイントがあります。 (1)TNとは何ですか? (2)InotificationManagerサービスの役割。これら2つの問題を使用して、トーストソースコードを続けます。
TNソースコード
多くの質問は、ソースコードを介して答えを見つけることができます。トーストのコンストラクターでのMTNの実装、ソースコードは次のとおりです。
Public Toast(コンテキスト){MCENTEXT = CONTEXTN = Context.GetResources(); ().getinteger(com.android.internal.r.iinteger.config_toastdefaultgravity);}次に、TNクラスのソースコードから始めて、TNの役割を調査します。 TNソースコードは次のとおりです。
Private static class tnはitransiteNotification.stubを拡張します{final runnable mshow = new runnable(){@override public void run(){handless();}; ()HandleHideでこれを行いますint mx、flow mview mview; windoutparams = mparams.layoutparams.wrap_content; windowmanager.type_toast; ]マルチユーザーをサポートしますparams.privateflags = windowmanager.layoutparams.private_frag_for_all_users; .post(mshow);} / ** *スケジュールハンドルハイドインスタム正しいスレッド * / @Override public void hide(){if(locallogv)log.v(tag(tag "hide:" + this); mhandler.post( mhide);} public void handleshow(){if(locallogv)log.v( " + this +" mview = " + mview +" xtview = " + mnextview); {//必要に応じて削除します。 (windowmanager)context.getSystemService(context.window_service);最終的な重力= getabsolutegravity(config.getlayoutdirection()); (Gravity&Gravity_mask)== fill_vertical){mparams.x = mx; mparams.y; getParent()! add! " + mview +" in " + this); mwm.addview(mview、mparams); trysendac sensevent();}}}} daccessibilityvent(){accessibilitymanager accessibilitymanager = accessibilitymanager。 (!accessibilitymanager.isenabled(){return;} //ユーザーアクセシビティへの一時的な情報= accessibilityevent.obtain.obtain)。 DispatchPopultAcsibilityEvent(event); = null){// NOT:Paint()を確認するだけです。 if(mview.getparent()!= null){if;ソースコードを通じて、TNクラスは、プロセス間通信のためにitransientNotification.stubから継承されることを明らかに見ることができます。読者は、Androidプロセス間のコミュニケーションの基礎を持っていると想定されています(バインダープロセス通信に関するLuo Shengyangのコミュニケーションの一連のブログを学ぶことはあまり知られていません)。 TNはプロセス間通信に使用されるため、TNクラスの特定の役割は、トーストクラスのコールバックオブジェクトであると考えるのは簡単です。 TNクラス。
TNクラスはitransiteNotification.stubから継承されます、itransientNotification.aidlはFrameworks/base/core/java/app/itransientnotification.aidlにあります。ソースコードは次のとおりです。
パッケージandroid.app;
itransientNotificationは、2つの方法をshow()とhide()を定義し、それらの特定の実装はTNクラスにあります。 TNクラスの実装は次のとおりです。
/ ***右のスレッドへのハンドルをスケジュールします* / @Override public void show(){if(locallogv)log.v( "show:" + this); */ @Override public void hide(){if(locallogv)log.v( "hide:" + this);ここでは、Toastのショーアンドハイニングメソッドの実装がハンドラーメカニズムに基づいていることを知ることができます。 TNクラスでのハンドラーの実装は次のとおりです。
final handl mhandler = new Handler();
さらに、TNクラスにlooper.perpare()およびlooper.loop()メソッドは見つかりませんでした。 MANDLERが現在のスレッドのルーパーオブジェクトを呼び出すことを示しています。したがって、Androidシステムはメインスレッドのルーパー初期化を実現するのに役立つため、メインスレッド(つまりUIスレッド)にいる場合、Toast.maketextメソッドを自由に呼び出すことができます。但是、如果你想在子线程中调用、toast.maketext方法、就必须先进行ルーパー初始化了、不然就会报出java.lang.runtimeexception:looper.prepare()エッセンスハンドラーメカニズムの学習は、以前に書いたブログを参照できます:http://blog.csdn.net/wzy_1988/article/details/38346637。
次に、MSHOWとMHIDEの実装に従って続けます。どちらも実行可能です。
final runnable mshow = new runnable(){@override public void run(){handlehide(); handleshow()mnextview = null;}}; Show and Hideの実際の実装は、それぞれHandleshow()とHandlehide()メソッドを呼び出すことであることがわかります。 handleshow()の具体的な実装を見てみましょう。
public boid handly(mview!= mnextview) ){context = mview.getContext();} mwm =(windowmanager)context.getSystemService(context.window_service); .getContext()GetConfiguration() .fill_horizontal){mparams.horizontalweight = 1.0f;} if(gravity.vertical_gravity_mask)= fill_vertical) = mverticalmargins.horizontalmargin = mhorizontalmargin;ソースコードから、トーストはWindowManagerを介してAddViewにロードされていることがわかります。したがって、非表示メソッドは、トーストビューを削除するremoveViewメソッドを呼び出すための自然にWindowManagerです。
要約すると、TNクラスのソースコードを分析することにより、TNクラスはコールバックオブジェクトであり、他のプロセスがTNクラスのショーと非表示の方法を呼び出して、このトーストの表示と消失を制御することがわかります。
NotificationManagerService
Toastクラスのショー方法に戻ると、GetServiceがここで呼び出され、ソースコードが次のとおりです。
private static inotificationmanager sservice; static private inotification getervice(){sservice!= null){return sservice;} sservice = otifinager.stub.asinterface(servicemanager.getService( "notification"); InotificationManagerサービスを取得した後、Enqueuetoastメソッドが呼び出され、現在のトーストをシステムのトーストキューに入れました。パスのパラメーターは、PKG、TN、およびmDurationです。つまり、toast.makeText(Context、MSG、Toast.Length_show)を使用して、このトーストを表示するのではなく、最初にシステムのトーストキューに入り、次に表示されます。システムは、トーストを表示および非表示にするために、コールバックオブジェクトTNのショーと非表示のメソッドを呼び出します。
inofiticanagerインターフェイスの特定の実装クラスは、frameworks/base/services/java/com/server/notificationmanagervice.javaにあるNotificationManagerServiceクラスです。
まず、ToastのEnqueueToastへのエントリの関数を分析しましょう。
public void enqeuetoast(string pkg、itransientnotification callback、int duration){// packageNameはnullまたはtn class a aallback == null;} //(1)最終的なブーリアンIssuestoast = isCallerSystem( )||( "Android"。 (pkg、binder.getCallinguid()&&! //(2)トーストが既にindex = i ndexoftoastlocked(pkg、callback)を持っているかどうか。 get(index); cupdate(duration);} else {//各pkgは現在、mtoastqueueのトーストの総数はmax_package_notificationsを超えることはできません。 final n = mtoastqueue.size(); ++; if(count> = max_package_notifications){slog.e、 " + count +"トーストaStqueue.add(記録)に配置されます。 )インデックスが0の場合、現在のエントリチームが[indexttoastlocked();} if(indexttoastlocked();})を表示するために、[現在のエントリチーム]を呼び出します。 }}}上記のコードについて簡単にコメントしたことがわかります。コードは比較的簡単ですが、さらに議論する必要がある4つのポイントオブノートコードがあります。
(1)システムトーストであるかどうかを判断します。現在のトーストのパッケージ名が「Android」の場合、それはシステムトーストであり、それ以外の場合は、iScallerSystem()メソッドを呼び出すこともできます。このメソッドの実装ソースコードは次のとおりです。
boolean isuidsystem(int uid){final int appid = userhandle.getappid(uid); ());} IscallerSystemのソースコードは、現在のトーストプロセスのUIDがSystem_UID、0、Phone_UIDの1つであるかどうかを判断するために、比較的単純ですトースト。
それがシステムトーストであるかどうか、以下のソースコードを読んで、2つの主な利点があることがわかります。
システムトーストは間違いなくシステムトーストキューに入ることができ、ブラックリストによって停止することはありません。
システムトーストには、システムトーストキューに数量制限がありませんが、通常のPKGから送信されたトーストには、システムトーストキューに数量制限があります。
(2)チームに委ねられるトーストがすでにシステムトーストキューにあるかどうかを確認します。これは、PKGとコールバックを比較することで達成されます。
private indexoftoastlocked(string pkg、itransientnotification callback){callback.asbinder(); ++){toastRecord r = list.get(i);上記のコードを通して、ToastのPKG名がTNオブジェクトと一致している限り、システムはこれらのトーストを同じトーストと見なすという結論を描くことができます。
(3)現在のトーストプロセスをフロントデスクの処理として設定します。ソースコードを以下に示します。
private keepprocessaliveLocked(int pid){int toastcount = 0; list.get(i); if(r.pid == pid){toastcount ++;}} 'tが起こる。}} MAM = ActivityManagernative.getDefault()は、SetProcessForeGroundメソッドを呼び出して、現在のPIDプロセスをフロントデスク処理に配置して、体系的に殺さないようにします。これは、現在のアクティビティを終了したときに、現在のプロセスがまだ実行されているためにトーストを表示できる理由も説明しています。
(4)インデックスが0の場合、キューヘッドのトーストが表示されます。ソースコードは次のとおりです。
private void shownextoastlocked {// astrecord record = mtoastqueue(0); ()リストとlet the procese index = mtoastqueue.indexof(record); = mtoastqueue.get(0);} else {record = null;}}}}}トーストのコールバックオブジェクトはTNオブジェクトです。次に、システムトーストのディスプレイ時間が2秒または3.5秒しかない理由を見てみましょう。重要なのは、ScheduleTimeOutLockedメソッドの実装です。原則は、TOASTを表示するためにTNのショー方法を呼び出した後、トーストを消滅させるためにScheduleTmelockLockedメソッドを呼び出す必要があるということです。 (質問がある場合:TNオブジェクトの非表示メソッドが乾杯すると言っていない場合は、なぜScheduleTimeOutLockedメソッドを呼び出してトーストを消滅させますか? 、そして私たちは通常私たちのオフィスを持っています也是用了ハンドラー消息机制)。
Private static int long_delay = 3500; LONG DELAY === length_long:short_dlay(m、delay);
まず第一に、これがメッセージ_timeoutメッセージを直接送信しなかったことがわかりましたが、遅延の遅延がありました。 「長い遅延= R.duration == toast.length_long?long_dlay:short_dlay;」からの遅延の時間2秒または3.5秒。 Toast.maketextメソッドの期間を自由に渡すことは役に立たない。
次に、message_timeoutメッセージがWorkerhandlerでどのように処理されるかを見てみましょう。 MhandlerオブジェクトのタイプはWorkerHandlerであり、ソースコードは次のとおりです。
プライベートファイナルクラスワーカーハンドラーはハンドラーを拡張します{@Override public void handlemessage(message msg){what){case message_timeout:handleti meout(toastrecord)msg.obj;message_timeoutタイプへのWorkRhandlerのメッセージ処理は、HandLertimeOutメソッドを呼び出すことです。
private void handletimeout(toastrecord Record){synchronized(mtoastqueue){int index = indexoftoastlocked(record.pkg、record.callback);Handletimeoutコードでは、最初に消失する必要があるToastrecordオブジェクトがキューにある場合、CancelToAstlocked(index)メソッドを呼び出します。真実は私たちの前に現れようとしています。ソースコードを追跡し続けます。
private void toastlocked(int index){toastrecord record = mtoastqueue.get(index); //とにかく} mtoastqueue.remove(index);リストは、このポイントの後にリストが変更されていないことをdonformします。ハハ、ここを参照してください、コールバックオブジェクトの非表示方法も呼び出されており、MtoastqueueからMtoastqueueからも削除されています。この時点で、トーストの完全なディスプレイと消失が終わりました。