国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

各種Window的創建過程

2019-11-09 18:57:54
字體:
來源:轉載
供稿:網友

Window的創建過程

Activity的Window創建過程

Activity的啟動最終會通過ActivityThread#performLaunchActivity()來完成。

ActivityThread#performLaunchActivity()

PRivate Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { //... //通過類加載器創建Activity實例 java.lang.ClassLoader cl = r.packageInfo.getClassLoader(); activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); //... application app = r.packageInfo.makeApplication(false, mInstrumentation); Context appContext = createBaseContextForActivity(r, activity); CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager()); Configuration config = new Configuration(mCompatConfiguration); //關聯運行過程中所依賴的一系列上下文環境變量 activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config, r.voiceInteractor); mActivities.put(r.token, r); return activity;}

在attach方法里,系統會創建Activity所屬的Window對象并為其設置回調接口。

Activity#attach()

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, IVoiceInteractor voiceInteractor) { attachBaseContext(context); mFragments.attachActivity(this, mContainer, null); //創建Window對象 mWindow = PolicyManager.makeNewWindow(this); //設置回調 比如我們熟悉的onAttachedToWindow、onDetachedFromWindow、dispatchTouchEvent //[重要] 當Window接收到外界的狀態改變時就會調用Activity實現的回調 mWindow.setCallback(this); mWindow.setOnWindowDismissedCallback(this); //賦值 if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) { mWindow.setSoftInputMode(info.softInputMode); } if (info.uiOptions != 0) { mWindow.setUiOptions(info.uiOptions); } mUiThread = Thread.currentThread(); mMainThread = aThread; mInstrumentation = instr; mToken = token; mIdent = ident; mApplication = application; mIntent = intent; mComponent = intent.getComponent(); mActivityInfo = info; mTitle = title; mParent = parent; mEmbeddedID = id; mLastNonConfigurationInstances = lastNonConfigurationInstances; //... //設置WindowManager mWindow.setWindowManager( (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), mToken, mComponent.flattenToString(), (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0); if (mParent != null) { mWindow.setContainer(mParent.getWindow()); } mWindowManager = mWindow.getWindowManager(); mCurrentConfig = config;}

再來看 PolicyManager.makeNewWindow(this),PilicyManager的真正實現類是Policy類。 位于source/frameworks/base/policy/src/com/android/internal/policy/impl/Policy.java

public Window makeNewWindow(Context context) { return new PhoneWindow(context);}

可以發現Window的實現類確實是PhoneWindow。

Window初始完畢后,再來看Activity的視圖是如何依附在Window上的。Activity的視圖通過setContent方法提供。

public void setContentView(int layoutResID) { getWindow().setContentView(layoutResID); initWindowDecorActionBar();}

可以發現,Activity的setContentView將具體實現交由Window處理。

phoneWindow#setContentView()

@Overridepublic void setContentView(int layoutResID) { // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window // decor, when theme attributes and the like are crystalized. Do not check the feature // before this happens. //1.創建DecorView (如果沒有創建的話) if (mContentParent == null) { installDecor(); } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) { mContentParent.removeAllViews(); } if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) { final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID, getContext()); transitionTo(newScene); //2.將View添加到DecorView的mContentParent中 mLayoutInflater.inflate(layoutResID, mContentParent); } //3.回調Activity的onContentChanged()通知Activity視圖已經發生改變 final Callback cb = getCallback(); if (cb != null && !isDestroyed()) { cb.onContentChanged(); }}

經過setContentView方法,DecorView已經被創建并初始化完畢,Activity的布局文件也已經成功添加到DecorView的mContentParent中,但這個時候DecorView還沒有被WindowManager添加到Window中。 (在添加之前)

#

Activity的attach()中,Window被創建并初始化 在Activity的setContentView中 (PhoneWindow#setContentView),DecorView被創建 (如果沒被創建的話) 而在ActivityThread#handleResumeActivity首先會調用Activity的onResume方法中,接著會先將DecorView設為不可見(INVISIBLE),然后會調用Activity的makeVisible(),在makeVisible()中,將DecorView添加到Window并置為Visible。

#

void makeVisible() { //將DecorView添加到Window if (!mWindowAdded) { ViewManager wm = getWindowManager(); wm.addView(mDecor, getWindow().getAttributes()); mWindowAdded = true; } //將Activity的顯示置為Visible mDecor.setVisibility(View.VISIBLE);}

Dialog的window創建過程

Dialog的Window創建過程和Activity類似

Dialog#構造方法

Dialog(Context context, int theme, boolean createContextThemeWrapper) { //... mContext = context; mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); //創建Window對象 Window w = PolicyManager.makeNewWindow(mContext); mWindow = w; w.setCallback(this); w.setOnWindowDismissedCallback(this); w.setWindowManager(mWindowManager, null, null); w.setGravity(Gravity.CENTER); mListenersHandler = new ListenersHandler(this);}

再來看Dialog#setContentView()

public void setContentView(int layoutResID) { mWindow.setContentView(layoutResID);}

同樣是交由Window處理。

當Dialog dismiss時,會通過WindowManager來移除DecorView

@Overridepublic void dismiss() { if (Looper.myLooper() == mHandler.getLooper()) { dismissDialog(); } else { mHandler.post(mDismissAction); }}void dismissDialog() { //... //移除DecorView mWindowManager.removeViewImmediate(mDecor); //...}

注意

普通Dialog需要使用Activity的Content 因為Window需要應用token,而應用token一般只有Activity才擁有。 系統Window比較特殊,它可以不需要token。

Toast的Window創建過程

Toast屬于系統Window Toast內部有兩類ipC過程

Toast訪問NotifationManagerServiceNotificationManagerService回調Toast的TN接口

Toast提供了show和cancel分別用于顯示和隱藏Toast [都是IPC過程]

public void show() { if (mNextView == null) { throw new RuntimeException("setView must have been called"); } INotificationManager service = getService(); String pkg = mContext.getOpPackageName(); TN tn = mTN; tn.mNextView = mNextView; try { service.enqueueToast(pkg, tn, mDuration); } catch (RemoteException e) { // Empty }} public void cancel() { mTN.hide(); try { getService().cancelToast(mContext.getPackageName(), mTN); } catch (RemoteException e) { // Empty }}

主要來看enqueueToast()

//參數一:當前應用的包名//參數二:遠程回調//參數三:Toast的時長//enqueueToast首先將Toast封裝為ToastRecord對象并將其添加到一個名為mToastQueue的隊列中service.enqueueToast(pkg, tn, mDuration);

當ToastRecord被添加到mToastQueue中后,Inotifacationmanager就會通過showNextToastLacked方法來顯示當前的Toast。

NotificationManagerService#showNextToastLocked()

void showNextToastLocked() { //獲取下一個ToastRecord ToastRecord record = mToastQueue.get(0); while (record != null) { if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback); try { //record.callback就是Toast.java類中的TN (Binder) 對象 record.callback.show(); //發送延遲消息來移除toast //scheduleTimeoutLocked -> mHandler.sendMessageDelayed -> cancelToastLocked -> record.callback.hide(); scheduleTimeoutLocked(record); return; } catch (RemoteException e) { Slog.w(TAG, "Object died trying to show notification " + record.callback + " in package " + record.pkg); // remove it from the list and let the process die int index = mToastQueue.indexOf(record); if (index >= 0) { mToastQueue.remove(index); } keepProcessAliveLocked(record.pid); if (mToastQueue.size() > 0) { record = mToastQueue.get(0); } else { record = null; } } }}

可以發現,Toast的顯示和移除都是通過Toast的TN類(Binder對象)來完成的。

Toast內部類TN

private static class TN extends ITransientNotification.Stub { final Runnable mShow = new Runnable() { @Override public void run() { handleShow(); } }; final Runnable mHide = new Runnable() { @Override public void run() { handleHide(); // Don't do this in handleHide() because it is also invoked by handleShow() mNextView = null; } }; @Override public void show() { if (localLOGV) Log.v(TAG, "SHOW: " + this); mHandler.post(mShow); } @Override public void hide() { if (localLOGV) Log.v(TAG, "HIDE: " + this); mHandler.post(mHide); } //...}

真正的顯示

public void handleShow() { //... mWM = (WindowManager)context.getSystemService //... if (mView.getParent() != null) { mWM.removeView(mView); } mWM.addView(mView, mParams); //... }}

真正的隱藏

public void handleHide() { if (mView != null) { if (mView.getParent() != null) { mWM.removeView(mView); } mView = null; }}

相關

PhoneWindow偽代碼


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 乌兰浩特市| 威海市| 手游| 成安县| 凤翔县| 娄底市| 策勒县| 隆尧县| 陆良县| 清镇市| 香港 | 龙州县| 昌宁县| 临朐县| 新乡县| 朝阳区| 新建县| 东平县| 榆树市| 镇原县| 改则县| 菏泽市| 武汉市| 丹东市| 昌都县| 金门县| 兴仁县| 花莲县| 炎陵县| 靖边县| 陈巴尔虎旗| 隆德县| 台东市| 平舆县| 交口县| 封开县| 呼伦贝尔市| 会理县| 中山市| 莱西市| 汤阴县|