토스트 소스 코드 구현
토스트 입구
응용 프로그램에서 토스트 프롬프트를 사용하면 일반적으로 다음과 같이 간단한 코드 호출을합니다.
[Java] Code Tablet에 파생 된 코드 태블릿보기
Toast.maketext (Context, MSG, Toast.length_short) .show ();
Maketext는 토스트의 입구입니다. 소스 코드는 다음과 같습니다 (Frameworks/Base/Core/Java/Android/Widget/Toast.java) :
공개 정적 토스트 Maketext (컨텍스트 컨텍스트, 숯불 텍스트, int 시간) {Toast result = new Toast (Context); interct.r.layout.transient_notification, null); 시간; 반환 결과;Maketext의 소스 코드에서 토스트의 레이아웃 파일이 transient_notification.xml임을 알 수 있습니다. 프레임 워크/베이스/코어/res/레이아웃/레이아웃/transition_notification.xml :
<? match_parent "android ="수직 "안드로이드 : background ="? and artroid : <textview android : id = "@andd roid : id/message"android : "wrap_content"android : layout_height = "wrap_content"Android : layout_weight = "1"Android : layout_gravity = "center_horizontal"Android : textParperance = "@style/textAperance.toast" "Android : textColor ="@color/bright_foreground_dark "Android : 섀도 콜러 ="#bb000000 "android : Shadowradius = "2.75" /> < /linearlayout>
시스템 토스트의 레이아웃 파일은 매우 간단합니다. 다음으로, 우리는 레이아웃이 형성된 후 Show () 메소드를 계속 따라 디스플레이 코드 구현을 연구합니다.
public void show (mnextView == NULL) {setView는 CE (); try {service.enqueuetoast (pkg, tn, mduration);} catch (remoteexception e) {// empty}} 쇼 방법에는주의를 기울여야 할 두 가지 점이 있습니다. (1) TN은 무엇입니까? (2) InotificationManager 서비스의 역할. 이 두 가지 문제로 인해 토스트 소스 코드를 계속하십시오.
TN 소스 코드
많은 질문이 소스 코드를 통해 답을 찾을 수 있습니다. 토스트 생성자에서 MTN의 구현, 소스 코드는 다음과 같습니다.
공개 토스트 (Context Context) {McOntext = mtn.my = 컨텍스트 () .getInteger (com.android.internal.r.iinteger.config_toastdefaultgravity);}다음으로 TN 클래스의 소스 코드에서 시작하여 TN의 역할을 탐색합니다. TN 소스 코드는 다음과 같습니다.
개인 정적 클래스 TN은 Itransitenotification.stub을 확장합니다. {@override public void run () {handless ();}; (); handleshow () mnextview = null; int mx, mhorizontalmargin; Final Manger.layoutparams = mparams; winder.layoutparams ER 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 (mhandler.post) mhide);} public void handleshow () {if (locallogv) log.v (tag, "핸들 쇼 :" + this + "mview =" + mview + "xtview =" + mnextview); {// 필요한 경우 handshide (); mnextview; (WindowManager) getSystemService (context.window_service); 최종 int gravity.getabsolutegravity (mgravity, config.getLayoutDirection ()); (중력. getParent ()! = null) {if (locallogv) log.v (tag, "remov!" + mview + " + this); mwm.re moveview (mview);} if (locallogv) log.v (tag,") " + mview +"in " + this); mwm.addview (mview, mparams); trysendac senseevent ();}}}} daccessibilityEvent () {accessibilityManager accessibilityManager = accessibilityManager. getInstance (mview.getContext (if); (! accessibilityManager.isEnabled ()) {return;} // user accessibilityEvent event = accessibilityEvent.obtain.obtain에 대한 일시적인 정보를 사용하기 때문에 토스트를 알립니다. DispatchPultAccessibityEvent (이벤트); Sendac Sense (Event);} public void handshide () {if (locallogv) hide : " + this +"mview = " + mview); = null) {// not : paint ()가 mak에 확인하십시오. 충돌하지 않도록하십시오. if (mview.getParent ()! = null) {if; 소스 코드를 통해 상속 관계를 볼 수 있습니다. 독자들은 Android 프로세스 간의 의사 소통의 기초를 가지고 있다고 가정합니다 (Luo Shengyang의 바인더 프로세스 커뮤니케이션에 대한 커뮤니케이션의 일련의 블로그를 배우는 것은 잘 알려져 있지 않습니다). TN은 프로세스 간 통신에 사용되기 때문에 TN 클래스의 특정 역할은 토스트 클래스의 콜백 객체라고 생각하기 쉽습니다. TN 클래스.
TN 클래스는 itransitenotification.stub에서 상속됩니다. itransientNotification.aidl은 프레임 워크/베이스/코어/java/app/itransientnotification.aidl에 있습니다. 소스 코드는 다음과 같습니다.
패키지 android.app; / ** @hide* / oneway 인터페이스 itransientNotification {void show ();ItransientNotification은 show ()와 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의 Show and Hide 메소드 구현이 핸들러 메커니즘을 기반으로한다는 것을 알 수 있습니다. TN 클래스의 핸들러 구현은 다음과 같습니다.
Final Handl Mhandler = New Handler ();
또한 TN 클래스에서 Looper.PerPare () 및 Looper.Loop () 메소드를 찾지 못했습니다. Mhandler는 현재 스레드의 루퍼 객체를 호출 함을 보여줍니다. 따라서 메인 스레드 (즉, UI 스레드에서)에있을 때는 Android 시스템이 기본 스레드의 루퍼 초기화를 실현하는 데 도움이되기 때문에 Toast.maketext 메소드를 마음대로 호출 할 수 있습니다. 짐 본질 핸들러 메커니즘의 학습은 이전에 쓴 블로그를 참조 할 수 있습니다 : http://blog.csdn.net/wzy_1988/article/details/38346637.
다음으로 Mshow와 Mhide의 구현을 계속 따르십시오.
최종 Runnable MSHOW = New Runnable () {handleshow ();} {handleHide (); Handleshow () mnextView = null;}}; Show and Hide의 실제 구현은 각각 Handleshow () 및 HandleHide () 메소드를 호출하는 것임을 알 수 있습니다. Handleshow ()의 특정 구현을 살펴 보겠습니다.
void handleshow (mview! = mnextview) {// handshide () 컨텍스트 컨텍스트를 제거합니다 ) {context = mview.getContext ();} mwm = (WindowManager) context.getSystemService (context.window_service); .getContext (). getConfiguration (); .fill_horizontal) {mparams.horizontalweight = 1.0f;} if (gravity & gravity.vertical_gravity_mask) {mparams.fill_vertical)} mparams.x = mparams = mverticalmargin.horizontalmargin = mhorizontalmargin; 소스 코드에서 Toast는 WindowManager를 통해 AddView에로드된다는 것을 알고 있습니다. 따라서 숨기기 메소드는 자연스럽게 Windowmanager입니다. removeView 메소드를 호출하여 토스트 뷰를 제거합니다.
요약하면, TN 클래스의 소스 코드를 분석함으로써, 우리는 TN 클래스가 콜백 객체라는 것을 알고 있으며, 다른 프로세스는 TN 클래스의 쇼를 호출 하여이 토스트의 디스플레이 및 사라짐을 제어합니다.
NotificationManagerservice
토스트 클래스의 쇼 메소드로 돌아가서, 우리는 소스 코드를 얻기 위해 getService가 호출되어 있음을 알 수 있습니다.
Private static inotificationManager sservice; 정적 개인 비교 관리자 getService () {if (sservice! = null) {reture sservice = in otifinager.stub.asinterface (servicemanager.getSrevice ( "notification"); 부적합한 관리인 서비스를받은 후, Enqueuetoast 방법을 사용하여 현재 토스트를 시스템의 토스트 큐에 넣습니다. 패스의 매개 변수는 PKG, TN 및 MDURATION입니다. 다시 말해서, 우리는 토스트, maketext (context, msg, toast.length_show) .show ()를 사용 하여이 토스트가 현재 창에 즉시 표시되지 않지만 먼저 시스템의 토스트 큐에 들어갑니다. 시스템은 콜백 객체 TN의 쇼를 호출하고 토스트를 표시하고 숨 깁니다.
InofiticAnager 인터페이스의 특정 구현 클래스는 Frameworks/Base/Services/Java/Com/Server/NotificationManagervice.java에 위치한 NotificationManagerservice 클래스입니다.
우선, 토스트의 Enqueuetoast에 대한 기능을 분석하겠습니다.
public void enqeuetoast (문자열 pkg, itransientnotification 콜백, int duration) {// packagename은 null 또는 tn class as allback == null) {return;} // ) || (Android ".equals (pkg)); (pkg, getCallinguid ()) {issystemtoast) {mtoastqueue) {int callerpid = binder.getcalllingpid (); // (2) 토스트가 이미 index = i ndexoftoastlocked (pkg, 콜백)인지 확인하십시오. get (index); record.update (duration);} else {// 비 시스템 토스트, 각 pkg, 각 pkg, mtoastque의 총 토스트 수는 max_package_notifications if (! issystemtoast) {int count = 0; 최종 int n = mtoastque.size (); ++; if (count = max_package_notifications) {slog.e, Almedy는 " + count +"토스트를 게시했습니다 Toastrecord 객체 및 mtoastque.add에 넣습니다. ) 인덱스가 0 인 경우, 현재 입력 팀이 팀에 있다는 것을 의미합니다. index == 0) {showxtToastLocked ();} 마지막으로 표시됩니다. }}} 위의 코드에 대해 간단한 의견을 제시했다는 것을 알 수 있습니다. 코드는 비교적 간단하지만 4 점의 노트 코드가 있습니다.
(1) 시스템 토스트인지 여부를 결정하십시오. 현재 토스트의 패키지 이름이 "Android"인 경우 시스템 토스트입니다. 그렇지 않으면 판단 할 iscallersystem () 메소드를 호출 할 수도 있습니다. 이 방법의 구현 소스 코드는 다음과 같습니다.
부울 isuidsystem (int uid) {최종 int appid = userhandle.getAppid (uid); ());} iscallersystem의 소스 코드는 비교적 간단합니다 토스트.
시스템 토스트이든 아래 소스 코드를 읽으 든, 두 가지 주요 장점이 있음을 알 수 있습니다.
시스템 토스트는 확실히 시스템 토스트 큐에 들어갈 수 있으며 블랙리스트로 중지되지 않습니다.
시스템 토스트는 시스템 토스트 큐에 수량 제한이 없으며 일반 PKG로 보낸 토스트는 시스템 토스트 큐의 수량 제한을 갖습니다.
(2) 팀에 위탁 될 토스트가 이미 시스템 토스트 큐에 있는지 확인하십시오. 이것은 PKG와 콜백을 비교하여 달성됩니다.
Private IndexoftoastLocked (String Pkg, ItransientNotification Callback) {ibinder cbak.asbinder (); ++) {toastrecord r = list.get (i); 위의 코드를 통해 토스트의 PKG 이름이 TN 객체와 일치하는 한 시스템은 이러한 토스트를 동일한 토스트로 간주한다는 결론을 도출 할 수 있습니다.
(3) 현재 토스트 프로세스를 프론트 데스크 처리로 설정하십시오. 소스 코드는 다음과 같습니다.
개인 void keepprocessalivelocked (int pid) {int toastcount = 0; list.get (i); if (r.pid == pid) {toastcount ++;}} {mam.setprocessforeground (mforegrounttoken, pid, toastcount> 0);} cat 't renate.}} MAM = ActivityManagernative.getDefault ()는 SetProcessForeground 메소드를 호출하여 현재 PID 프로세스를 프론트 데스크 처리에 배치하여 체계적으로 죽이지 않도록합니다. 또한 현재 활동을 마치면 현재 프로세스가 여전히 실행되어 토스트를 표시 할 수있는 이유도 설명합니다.
(4) 인덱스가 0 인 경우, 큐 헤드의 토스트가 표시됩니다. 소스 코드는 다음과 같습니다.
private void showdToastLocked () {// toastrecord toastrecord record = mtoastque.get (record! = null) {// 방법이 토스트를 표시하는 방법 (); ScheduleteCeption (record); 목록 및 Procese Index = mtoastqueue.indexof (index> = 0) {mtoastqueue.remove (index); = mtoastqueue.get (0);} else {record = null;}}}}토스트의 콜백 객체는 TN 객체입니다. 다음으로, 시스템 토스트의 디스플레이 시간이 2s 또는 3.5s 일 수있는 이유를 살펴 보겠습니다. 키는 ScheduleTimeOutlocked 메소드의 구현입니다. 원칙은 TN의 쇼 메소드를 호출하여 토스트를 표시 한 후에 ScheduleTMelockLocked 메소드를 호출하여 토스트를 사라져야한다는 것입니다. (궁금한 점이 있으면 : TN 물체의 숨기기 방법이 토스트를 사라지는 이유는 말하지 말고, 왜 TN 클래스의 숨기기 방법이 실행 되 자마자, 토스트는 즉시 사라집니다. , 우리는 보통 사무실을 가지고 있습니다. 使用的 토스트 都会在当前 활동 停留几秒。如何实现停留几秒呢?原理就是 scheduletimeoutlocked 发送 message_timeout 消息去调用 tn 对象的 hide 方法 方法, 但是这个消息会有一个 지연 延迟, 这里也是用了 핸들러 消息机制 ler。。
개인 정적 최종 Long_delay = 3500; Long Delay == Toast.length_long : short_dlay.
우선, 우리는 여기에서 이것으로 Message_Timeout 메시지를 직접 보내지 않았지만 지연이 지연되었습니다. "Long Delay = r.duration == Toast.length_long? long_dlay : short_dlay;" 2s 또는 3.5s. Toast.maketext 메소드에서 마음대로 지속 시간을 전달하는 것은 쓸모가 없습니다.
다음으로 WorkerHandler에서 Message_Timeout 메시지가 처리되는 방법을 살펴 보겠습니다. Mhandler 객체의 유형은 WorkerHandler이며 소스 코드는 다음과 같습니다.
Private Final Class WorkerHandler는 핸들러를 확장합니다 {@override public void handleSage (message msg) {switch (msg.what) {case 메시지WorkRhandler의 Message_Timeout 유형에 대한 메시지 처리는 HandlerTimeout 방법을 호출하는 것임을 알 수 있습니다.
개인 void handletimeout (toastrecord record) {synchronized (mtoastqueue) {int index = index.pkg, record.callback) {canceltoastlocked (index);}}};Handletimeout 코드에서 먼저 사라져야하는 Toastrecord 객체가 대기열에있는 경우 CanceltoastLocked (인덱스) 메소드를 호출하는지 여부를 결정하십시오. 진실은 우리 앞에 나타나고 소스 코드를 계속 추적합니다.
개인 void canceltoastlocked (int index) {toastrecord record = mtoastqueue.get (index); // 어쨌든} mtoastque.remove (index); 목록은이 시점에서 목록이 변경되지 않았다는 것을 포함합니다. 하하, 여기를 참조하십시오. 콜백 객체의 숨기기 방법도 호출되었으며 Mtoastqueue에서 Mtoastqueue에서도 제거됩니다. 이 시점에서 토스트의 완전한 디스플레이와 실종이 끝났습니다.