08.建立機制分析php
01.Activity、Window、View三者關係java
02.Toast源碼深度分析android
04.Dialog源碼分析github
05.PopupWindow源碼分析segmentfault
07.彈窗常見問題ide
09.onAttachedToWindow和onDetachedFromWindow源碼分析
彈窗有哪些類型
Window是什麼?
R.layout.activity_main
。如何經過WindowManager添加Window(代碼實現)?
以下所示
//1. 控件 Button button = new Button(this); button.setText("Window Button"); //2. 佈局參數 WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, 0, 0, PixelFormat.TRANSPARENT); layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; layoutParams.gravity = Gravity.LEFT | Gravity.TOP; layoutParams.x = 100; layoutParams.y = 300; // 必需要有type否則會異常: the specified window type 0 is not valid layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; //3. 獲取WindowManager並添加控件到Window中 WindowManager windowManager = getWindowManager(); windowManager.addView(button, layoutParams);
WindowManager的主要功能是什麼?
添加、更新、刪除View
public interface ViewManager{ public void addView(View view, ViewGroup.LayoutParams params); //添加View public void updateViewLayout(View view, ViewGroup.LayoutParams params); //更新View public void removeView(View view); //刪除View }
DecorView是FrameLayout的子類,它能夠被認爲是Android視圖樹的根節點視圖。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:fitsSystemWindows="true" android:orientation="vertical"> <!-- Popout bar for action modes --> <ViewStub android:id="@+id/action_mode_bar_stub" android:layout_width="match_parent" android:layout_height="wrap_content" android:inflatedId="@+id/action_mode_bar" android:layout="@layout/action_mode_bar" android:theme="?attr/actionBarTheme" /> <FrameLayout style="?android:attr/windowTitleBackgroundStyle" android:layout_width="match_parent" android:layout_height="?android:attr/windowTitleSize"> <TextView android:id="@android:id/title" style="?android:attr/windowTitleStyle" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@null" android:fadingEdge="horizontal" android:gravity="center_vertical" /> </FrameLayout> <FrameLayout android:id="@android:id/content" android:layout_width="match_parent" android:layout_height="0dip" android:layout_weight="1" android:foreground="?android:attr/windowContentOverlay" android:foregroundGravity="fill_horizontal|top" /> </LinearLayout>
在Activity中經過setContentView所設置的佈局文件其實就是被加到內容欄之中的,成爲其惟一子View,就是上面的id爲content的FrameLayout中,在代碼中能夠經過content來獲得對應加載的佈局。
ViewGroup content = (ViewGroup)findViewById(android.R.id.content); ViewGroup rootView = (ViewGroup) content.getChildAt(0);
Activity 與 PhoneWindow 與 DecorView 關係圖
App點擊桌面圖片啓動過程
window啓動流程
Activity 與 PhoneWindow 與 DecorView 之間什麼關係?
ActivityThread中執行performLaunchActivity,從而生成了Activity的實例。源碼以下所示,ActivityThread類中源碼
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ... Activity activity = null; try { java.lang.ClassLoader cl = r.packageInfo.getClassLoader(); activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); ... } catch (Exception e) { ... } try { ... if (activity != null) { ... activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config, r.referrer, r.voiceInteractor); ... } ... } catch (SuperNotCalledException e) { throw e; } catch (Exception e) { ... } return activity; }
在attach該方法中完成window的初始化。源碼以下所示,Activity類中源碼
final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, int ident, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances, Configuration config, String referrer, IVoiceInteractor voiceInteractor, Window window, ActivityConfigCallback activityConfigCallback) { mWindow = new PhoneWindow(this, window, activityConfigCallback); mWindow.setWindowControllerCallback(this); mWindow.setCallback(this); mWindow.setOnWindowDismissedCallback(this); mWindow.getLayoutInflater().setPrivateFactory(this); if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) { mWindow.setSoftInputMode(info.softInputMode); } if (info.uiOptions != 0) { mWindow.setUiOptions(info.uiOptions); } }
用戶執行Activity的setContentView方法,內部是調用PhoneWindow的setContentView方法,在PhoneWindow中完成DecorView的建立。流程
public void setContentView(@LayoutRes int layoutResID) { getWindow().setContentView(layoutResID); initWindowDecorActionBar(); } @Override public void setContentView(int layoutResID) { ... if (mContentParent == null) { installDecor(); } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) { mContentParent.removeAllViews(); } ... } private void installDecor() { if (mDecor == null) { mDecor = generateDecor(); mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); mDecor.setIsRootNamespace(true); if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) { mDecor.postOnAnimation(mInvalidatePanelMenuRunnable); } } ... }