Android可以直接可見的界面包括Activity Toast Dialog PopuWindow ...
android的窗口分為三種:
1、應用程序窗口 (Application Window): 包括所有應用程序自己創建的窗口,以及在應用起來之前系統負責顯示的窗口。
2、子窗口(Sub Window):比如應用自定義的對話框,或者輸入法窗口,子窗口必須依附於某個應用窗口(設置相同的token)。
3、系統窗口(System Window): 系統設計的,不依附於任何應用的窗口,比如說,狀態欄(Status Bar), 導航欄(Navigation Bar), 壁紙(Wallpaper), 來電顯示窗口(Phone),鎖屏窗口(KeyGuard), 信息提示窗口(Toast), 音量調整窗口,鼠標光標等等。
1、Window是android中的窗口,表示頂級窗口的意思,也就是主窗口,它有兩個實現類,PhoneWindow和MidWindow
(1) 我們一般的activity對應的主要是PhoneWindow,在activity中經常使用的setContentView等方法也是在這個里面實現的。
performLaunchActivity中,會調用activity.attach方法建立一個window, 在handleResumeActivity方法中啟動activity的時候,會將主窗口加入到WindowManager中
(2) popupwindow是屬於 sub window的,所以一定要有一個view去依附
(3) 自定義Toast:自定義的原理也很簡單,就是給WindowManager添加View和刪除View,不過需要設置WindowManager.LayoutParams和View的樣式,使其看起來和Android系統的Toast看起來很相像。
Toast是通過WindowManager調用addView加載進來的。因此,hide方法自然是WindowManager調用removeView方法來將Toast視圖移除。 總結一下,通過對TN類的源碼分析,我們知道了TN類是回調對象,其他進程調用tn類的show和hide方法 來控制這個Toast的顯示和消失。Toast類的show方法中,我們可以看到,這里調用了getService得到INotificationManager服務,判斷是否為系統Toast。
1) 如果當前Toast所屬的進程的包名為“android”,則為系統Toast,否則還可以調用isCallerSystem()方法來;
判斷當前Toast所屬進程的uid是否為SYSTEM_UID、0、PHONE_UID中的一個,如果是,則為系統Toast;如果不是,則不為系統Toast。 是否為系統Toast,通過下面的源碼閱讀可知,主要有兩點優勢: 系統Toast一定可以進入到系統Toast 隊列中,不會被黑名單阻止。系統Toast在系統Toast隊列中沒有數量限制,而普通pkg所發送的Toast在系統Toast隊列中有數量限制。
2) 查看將要入隊的Toast是否已經在系統Toast隊列中。這是通過比對pkg和callback來實現的
3) 將當前Toast所在進程設置為前台進程,這里的mAm=ActivityManagerNative.getDefault(),調用了setProcessForeground方法將當前pid的進程置為前台進程,保證不會系統殺死。這也就解釋了為什么當我們finish當前Activity時, Toast還可以顯示,因為當前進程還在執行。
4) index為0時,對隊列頭的Toast進行顯示
(4) Dialog
在service中打開dialog需要編程系統窗口
改變Dialog背景透明度:
Dialog dg = new Dialog(this);
Window window = dg.getWindow();
WindowManager.LayoutParams lp = window.getAttributes();
lp.alpha = 0.5f;
window.setAttributes(lp);
WindowManager:
WindowManager主要用來管理窗口的一些狀態、屬性、view增加、刪除、更新、窗口順序、消息收集和處理等。
通過Context.getSystemService(Context.WINDOW_SERVICE)的方式可以獲得WindowManager的實例.
WindowManager繼承自ViewManager,里面涉及到窗口管理的三個重要方法,分別是:
* addView();
* updateViewLayout();
* removeView();
在WindowManager中還有一個重要的靜態類LayoutParams.通過它可以設置和獲得當前窗口的一些屬性。
我們先來看看addView()方法,在addView中,會利用LayoutParams獲得window的View屬性,並為每個window創建ViewRoot,ViewRoot是View和WindowManager之間的橋梁,真正把View傳遞給WindowManager的是通過ViewRoot的setView()方法,ViewRoot實現了View和WindowManager之間的消息傳遞。在將主窗口添加到WindowManger時,它首先會建立一個代理對象:
wm=(WindowManagerImpl)context.getSystemService(Context.WINDOW_SERVICE)
並且打開會話(IWindowSession),之后Window將通過該會話與WindowManager建立聯系,
來看下setView方法:
try {
res =sWindowSession.add(mWindow, mWindowAttributes,
getHostVisibility(), mAttachInfo.mContentInsets);
} catch (RemoteException e) {
mAdded = false;
mView = null;
mAttachInfo.mRootView =null;
unscheduleTraversals();
throw newRuntimeException("Adding window failed", e);
} finally {
if (restore) {
attrs.restore();
}
}
在這段代碼中,ViewRoot通過IWindowSession把窗口添加到WindowManager中。ViewRoot繼承了Handler,實際上它的本質就是一個Handler,窗口中View的事件處理、消息發送、回調等將通過ViewRoot來處理。
這樣就完成了把窗口添加到WindowManager中,並交由WindowManager來管理窗口的view、事件、消息收集處理等。
更新UI的線程必須是添加window的線程
在初始化一個ViewRootImpl函數的時候,會調用native方法,獲取到該線程對象mThread,接着setText函數會調用到requestLayout方法
(TextView繪制出來之后,調用setText才會去調用requestLayout方法,沒有繪制出來之前,在子線程中調用setText是不會拋出Exception):
public void requestLayout() { ..... checkThread(); ..... } .... void checkThread() { if (mThread != Thread.currentThread()) { throw new CalledFromWrongThreadException( "Only the original thread that created a view hierarchy can touch its views."); } }
在android中真正展示給用戶的是window和view,activity在android中所其的作用主要是處理一些邏輯問題,比如生命周期的管理、建立窗口等。
在android中,窗口的管理還是比較重要的一塊,因為他直接負責把內容展示給用戶,並和用戶進行交互。響應用戶的輸入等。
先說下ViewManager這個接口,這個接口主要有以下的實現子接口和實現類,分別是:WindowManager和ViewGroup里面還有三個重要的方法:
* addView();
* updateViewLayout();
* removeView();
在WindowManager中,addView方法表示的是將主窗口中的頂級view(也就是DecorView)添加到WindowManager中,並建立會話。接下來會詳細介紹。我們先來看看Window
Window:
Window是android中的窗口,表示頂級窗口的意思,也就是主窗口,它有兩個實現類,PhoneWindow和MidWindow,
我們一般的activity對應的主要是PhoneWindow,在activity中經常使用的setContentView等方法也是在這個里面實現的。
@Override
public void setContentView(View view,ViewGroup.LayoutParams params) {
if (mContentParent == null) {
installDecor();
} else {
mContentParent.removeAllViews();
}
mContentParent.addView(view, params);
final Callback cb = getCallback();
if (cb != null) {
cb.onContentChanged(); //窗口類容發生變化時更新
}
}
每個主窗口中都有一個View,稱之為DecorView,是主窗口中的頂級view(實際上就是ViewGroup),在View中有兩個成員變量叫做mParent、mChildren,它是用來管理view的上下級關系的。
而ViewGroup是對一組View的管理。因此,在ViewGroup中建立了所有view的關系網。而最終ViewGroup附屬在主窗口上。這樣就很容易在窗口中通過findViewById找到具體的View了。view中的事件處理也是根據這個路徑來處理的。
我們再來看看ActivityThead中的兩個重要的方法(至於ActivityThead將在一篇中詳細介紹):
performLaunchActivity( );
handleResumeActivity( );
在performLaunchActivity中,會調用activity.attach方法建立一個window, 在handleResumeActivity方法中啟動activity的時候,會將主窗口加入到WindowManager中
View decor =r.window.getDecorView(); //獲得窗口的頂級View
decor.setVisibility(View.INVISIBLE);
ViewManager wm= a.getWindowManager(); //WindowManager繼承自ViewManager
WindowManager.LayoutParams l =r.window.getAttributes();
a.mDecor = decor;
l.type =WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (a.mVisibleFromClient) {
a.mWindowAdded = true;
wm.addView(decor, l); //實際上是把主窗口的頂級view加入到WindowMangaer
}
我們再來看看WindowManager。
WindowManager:
WindowManager主要用來管理窗口的一些狀態、屬性、view增加、刪除、更新、窗口順序、消息收集和處理等。
通過Context.getSystemService(Context.WINDOW_SERVICE)的方式可以獲得WindowManager的實例.
WindowManager繼承自ViewManager,里面涉及到窗口管理的三個重要方法,分別是:
* addView();
* updateViewLayout();
* removeView();
在WindowManager中還有一個重要的靜態類LayoutParams.通過它可以設置和獲得當前窗口的一些屬性。
我們先來看看addView()方法,在addView中,會利用LayoutParams獲得window的View屬性,並為每個window創建ViewRoot,
ViewRoot是View和WindowManager之間的橋梁,真正把View傳遞給WindowManager的是通過ViewRoot的setView()方法,
ViewRoot實現了View和WindowManager之間的消息傳遞。在將主窗口添加到WindowManger時,它首先會建立一個代理對象:
wm=(WindowManagerImpl)context.getSystemService(Context.WINDOW_SERVICE)
並且打開會話(IWindowSession),之后Window將通過該會話與WindowManager建立聯系,
來看下setView方法:
try {
res =sWindowSession.add(mWindow, mWindowAttributes,
getHostVisibility(), mAttachInfo.mContentInsets);
} catch (RemoteException e) {
mAdded = false;
mView = null;
mAttachInfo.mRootView =null;
unscheduleTraversals();
throw newRuntimeException("Adding window failed", e);
} finally {
if (restore) {
attrs.restore();
}
}
在這段代碼中,ViewRoot通過IWindowSession把窗口添加到WindowManager中。ViewRoot繼承了Handler,實際上它的本質就是一個Handler,窗口中View的事件處理、消息發送、回調等將通過ViewRoot來處理。
這樣就完成了把窗口添加到WindowManager中,並交由WindowManager來管理窗口的view、事件、消息收集處理等。