android面試題及答案,Android Window 9問9答

 2023-12-06 阅读 18 评论 0

摘要:1.簡述一下window是什么?在android體系里 扮演什么角色? 答:window就是一個抽象類,他的實現類是phoneWindow。我們一般通過windowManager 來訪問window。就是windowmanager 和windowmanagerservice的交互。 此外 android中 你所有能看到的視圖,ac

1.簡述一下window是什么?在android體系里 扮演什么角色?

答:window就是一個抽象類,他的實現類是phoneWindow。我們一般通過windowManager 來訪問window。就是windowmanager 和windowmanagerservice的交互。

此外 android中 你所有能看到的視圖,activity,dialog,toast等 都是附加在window上的。window就是view的直接管理者。

?

android面試題及答案,2.如何使用windowmanager添加一個view?

答:

1  Button bt = new Button(this);
2         bt.setText("button here");
3         WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT,
4                 0, 0, PixelFormat.TRANSPARENT);
5         layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
6         layoutParams.x = 300;
7         layoutParams.y = 300;
8         layoutParams.gravity = Gravity.RIGHT | Gravity.TOP;
9         getWindowManager().addView(bt, layoutParams);
View Code

?

3.總共有幾種window類型?

答:三種。應用window,就是activity這種類型。子window,就是dialog這種,系統類,toast,狀態欄就是系統類型window。

windows和android區別?每種對對應著層級范圍,應用1-99 子1000-1999 系統 2000-2999.層級最大的,就是顯示在最頂層的window了。

?

4.使用系統window需要注意什么?

答:注意system_alert_window這個權限。否則要出錯

?

WINDOWS 9?5.嘗試簡單分析window的添加過程?

答:即window.addView()函數的執行過程:

  1 //首先我們要知道 windwmanger本身就是一個接口,他的實現是交給WindowManagerImpl 來做的。
  2 public final class WindowManagerImpl implements WindowManager {
  3 
  4 
  5 //他的view方法 一看,發現也是基本沒做實際的addview操作 是交給mGlobal來做的
  6  @Override
  7     public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
  8         applyDefaultToken(params);
  9         mGlobal.addView(view, params, mDisplay, mParentWindow);
 10     }
 11 
 12 
 13 //發現這是一個工廠嗎,到這里一看就明白了,WindowManagerImpl的實際操作 都橋接給了WindowManagerGlobal來處理
 14 private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
 15 
 16 //先看一下WindowManagerGlobal的 重要變量,注意上面已經分析過了,WindowManagerGlobal本身自己是一個單例,全局唯一,
 17 //所以下面這些參數list ,全局也是唯一的,mViews 就是所有window對應的view,mRoots就是所有viewRootImpl,mParams就是這些
 18 //view的參數,dyingviews 就是正在刪除的對象,就是那種你調用了remove操作 但是remove還沒有操作完畢的那些view
 19  private final ArrayList<View> mViews = new ArrayList<View>();
 20     private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
 21     private final ArrayList<WindowManager.LayoutParams> mParams =
 22             new ArrayList<WindowManager.LayoutParams>();
 23     private final ArraySet<View> mDyingViews = new ArraySet<View>();
 24 
 25 
 26 
 27 
 28 //所以 我們就看看WindowManagerGlobal源碼里的addView是如何實現的
 29 public void addView(View view, ViewGroup.LayoutParams params,
 30             Display display, Window parentWindow) {
 31         if (view == null) {
 32             throw new IllegalArgumentException("view must not be null");
 33         }
 34         if (display == null) {
 35             throw new IllegalArgumentException("display must not be null");
 36         }
 37         if (!(params instanceof WindowManager.LayoutParams)) {
 38             throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
 39         }
 40 
 41         final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
 42         //如果是子window 就調整一下參數
 43         if (parentWindow != null) {
 44             parentWindow.adjustLayoutParamsForSubWindow(wparams);
 45         } else {
 46             // If there's no parent and we're running on L or above (or in the
 47             // system context), assume we want hardware acceleration.
 48             final Context context = view.getContext();
 49             if (context != null
 50                     && context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
 51                 wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
 52             }
 53         }
 54 
 55         ViewRootImpl root;
 56         View panelParentView = null;
 57 
 58         synchronized (mLock) {
 59             // Start watching for system property changes.
 60             if (mSystemPropertyUpdater == null) {
 61                 mSystemPropertyUpdater = new Runnable() {
 62                     @Override public void run() {
 63                         synchronized (mLock) {
 64                             for (int i = mRoots.size() - 1; i >= 0; --i) {
 65                                 mRoots.get(i).loadSystemProperties();
 66                             }
 67                         }
 68                     }
 69                 };
 70                 SystemProperties.addChangeCallback(mSystemPropertyUpdater);
 71             }
 72 
 73             int index = findViewLocked(view, false);
 74             if (index >= 0) {
 75                 if (mDyingViews.contains(view)) {
 76                     // Don't wait for MSG_DIE to make it's way through root's queue.
 77                     mRoots.get(index).doDie();
 78                 } else {
 79                     throw new IllegalStateException("View " + view
 80                             + " has already been added to the window manager.");
 81                 }
 82                 // The previous removeView() had not completed executing. Now it has.
 83             }
 84 
 85             // If this is a panel window, then find the window it is being
 86             // attached to for future reference.
 87             if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
 88                     wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
 89                 final int count = mViews.size();
 90                 for (int i = 0; i < count; i++) {
 91                     if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
 92                         panelParentView = mViews.get(i);
 93                     }
 94                 }
 95             }
 96 
 97             //這個代碼充分說明了每一個window都對應著一個view 和一個viewrootIMPL,window本身自己不存在,
 98             //他的意義就在于管理view,而管理view 就要通過windowmanager 最終走到windwmanagerglobal這里來完成管理
 99             root = new ViewRootImpl(view.getContext(), display);
100 
101             view.setLayoutParams(wparams);
102 
103             mViews.add(view);
104             mRoots.add(root);
105             mParams.add(wparams);
106         }
107 
108         // do this last because it fires off messages to start doing things
109         try {
110             //view的最終繪制 是在viewrootimpl里完成的,所以這里view的繪制也是在這個里面完成的
111             //我們在viewrootimpl里能找到setview的源碼 他在這個函數里調用了requetlayout
112             root.setView(view, wparams, panelParentView);
113         } catch (RuntimeException e) {
114             // BadTokenException or InvalidDisplayException, clean up.
115             synchronized (mLock) {
116                 final int index = findViewLocked(view, false);
117                 if (index >= 0) {
118                     removeViewLocked(index, true);
119                 }
120             }
121             throw e;
122         }
123     }
124 
125 
126     //而requestLayout里有scheduleTraversals方法 這個就是view繪制的入口處
127     public void requestLayout() {
128         if (!mHandlingLayoutInLayoutRequest) {
129            checkThread();
130             mLayoutRequested = true;
131             scheduleTraversals();
132         }
133     }
134 
135     //回到前面提到的setView那個函數 
136     //我們可以看到requestLayout 結束以后 mWindowSession.addToDisplay 就有了這個方法的調用
137     //實際上這個方法 完成的就是一個window的添加。
138      requestLayout();
139     if ((mWindowAttributes.inputFeatures
140                          & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
141                     mInputChannel = new InputChannel();
142     }
143     try {
144                     mOrigWindowType = mWindowAttributes.type;
145                     mAttachInfo.mRecomputeGlobalAttributes = true;
146                    collectViewAttributes();
147                     res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
148                             getHostVisibility(), mDisplay.getDisplayId(),
149                             mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mInputChannel);
150 
151     //然后我們很容易就發現這是一個接口 并且代碼一看就知道 還是一個binder
152     //所以實際上添加window的功能 就是通過BInder 是調用windwmangerservice的方法 來完成的                
153 public interface IWindowSession extends android.os.IInterface
154 {
155 /** Local-side IPC implementation stub class. */
156 public static abstract class Stub extends android.os.Binder implements android.view.IWindowSession
157 {
158 private static final java.lang.String DESCRIPTOR = "android.view.IWindowSession";
159 /** Construct the stub at attach it to the interface. */
160 public Stub()
161 {
162 this.attachInterface(this, DESCRIPTOR);
163 }
View Code

?

6.activity的window是如何創建的?

答:應用類的window創建過程:

  1  
  2 //activity的window創建 由activityThread的performLaunchActivity 方法開始
  3  private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
  4         ......
  5             if (activity != null) {
  6                 Context appContext = createBaseContextForActivity(r, activity);
  7                 CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
  8                 Configuration config = new Configuration(mCompatConfiguration);
  9                 if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
 10                         + r.activityInfo.name + " with config " + config);
 11                 //其中最主要的就是attach方法 注意是調用的activity的attach方法 不是activitytherad的
 12                 activity.attach(appContext, this, getInstrumentation(), r.token,
 13                         r.ident, app, r.intent, r.activityInfo, title, r.parent,
 14                         r.embeddedID, r.lastNonConfigurationInstances, config,
 15                         r.referrer, r.voiceInteractor);
 16 
 17             ......
 18 
 19         return activity;
 20     }
 21 
 22 
 23 final void attach(Context context, ActivityThread aThread,
 24             Instrumentation instr, IBinder token, int ident,
 25             Application application, Intent intent, ActivityInfo info,
 26             CharSequence title, Activity parent, String id,
 27             NonConfigurationInstances lastNonConfigurationInstances,
 28             Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
 29         attachBaseContext(context);
 30 
 31         mFragments.attachActivity(this, mContainer, null);
 32         //這里一下就能看出來 Acitity的window對象 是由PolicyManager的makeNewWindow方法構造出來
 33         //有興趣的還可以看一下 這里set了很多接口 都是我們熟悉的那些方法
 34         mWindow = PolicyManager.makeNewWindow(this);
 35         mWindow.setCallback(this);
 36         mWindow.setOnWindowDismissedCallback(this);
 37         mWindow.getLayoutInflater().setPrivateFactory(this);
 38         if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
 39             mWindow.setSoftInputMode(info.softInputMode);
 40         }
 41         if (info.uiOptions != 0) {
 42             mWindow.setUiOptions(info.uiOptions);
 43         }
 44         mUiThread = Thread.currentThread();
 45 
 46         mMainThread = aThread;
 47         mInstrumentation = instr;
 48         mToken = token;
 49         mIdent = ident;
 50         mApplication = application;
 51         mIntent = intent;
 52         mReferrer = referrer;
 53         mComponent = intent.getComponent();
 54         mActivityInfo = info;
 55         mTitle = title;
 56         mParent = parent;
 57         mEmbeddedID = id;
 58         mLastNonConfigurationInstances = lastNonConfigurationInstances;
 59         if (voiceInteractor != null) {
 60             if (lastNonConfigurationInstances != null) {
 61                 mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
 62             } else {
 63                 mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
 64                         Looper.myLooper());
 65             }
 66         }
 67 
 68         mWindow.setWindowManager(
 69                 (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
 70                 mToken, mComponent.flattenToString(),
 71                 (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
 72         if (mParent != null) {
 73             mWindow.setContainer(mParent.getWindow());
 74         }
 75         mWindowManager = mWindow.getWindowManager();
 76         mCurrentConfig = config;
 77     }
 78 
 79 
 80 
 81 //makenewWindow就是在這里被調用的,可以看出來 makenewWindow返回的 正是phoneWindow對象
 82 //到這里我們的window對象就生成了,
 83     public class Policy implements IPolicy {
 84     private static final String TAG = "PhonePolicy";
 85 
 86     private static final String[] preload_classes = {
 87         "com.android.internal.policy.impl.PhoneLayoutInflater",
 88         "com.android.internal.policy.impl.PhoneWindow",
 89         "com.android.internal.policy.impl.PhoneWindow$1",
 90         "com.android.internal.policy.impl.PhoneWindow$DialogMenuCallback",
 91         "com.android.internal.policy.impl.PhoneWindow$DecorView",
 92         "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState",
 93         "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState",
 94     };
 95 
 96     static {
 97         // For performance reasons, preload some policy specific classes when
 98         // the policy gets loaded.
 99         for (String s : preload_classes) {
100             try {
101                 Class.forName(s);
102             } catch (ClassNotFoundException ex) {
103                 Log.e(TAG, "Could not preload class for phone policy: " + s);
104             }
105         }
106     }
107 
108     public Window makeNewWindow(Context context) {
109         return new PhoneWindow(context);
110     }
111 
112     public LayoutInflater makeNewLayoutInflater(Context context) {
113         return new PhoneLayoutInflater(context);
114     }
115 
116     public WindowManagerPolicy makeNewWindowManager() {
117         return new PhoneWindowManager();
118     }
119 
120     public FallbackEventHandler makeNewFallbackEventHandler(Context context) {
121         return new PhoneFallbackEventHandler(context);
122     }
123 }
124 
125 
126 //再看activity的方法 就是在這里把我們的布局文件和window給關聯了起來
127 //我們上面已經知道window對象就是phonewindow 所以這里就要看看phonewindow的setContentView方法
128 public void setContentView(@LayoutRes int layoutResID) {
129         getWindow().setContentView(layoutResID);
130         initWindowDecorActionBar();
131     }
132 
133 
134 //phoneWindow的setContentView方法
135 
136 //要注意的是 這個方法執行完畢 我們也只是 通過decorView創建好了 我們自己的view對象而已。
137 //但是這個對象還沒有被顯示出來,只是存在于內存之中。decorview真正被顯示 要在makevisible方法里了    
138      @Override
139     public void setContentView(int layoutResID) {
140         // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
141         // decor, when theme attributes and the like are crystalized. Do not check the feature
142         // before this happens.
143         if (mContentParent == null) {
144             //這個就是創建decorview的 decorView就是那個framelayout我們的根布局 有一個標題欄和內容欄
145             //其中內容蘭 就是android.R.id.content
146             installDecor();
147         } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
148             mContentParent.removeAllViews();
149         }
150 
151         if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
152             final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
153                     getContext());
154             transitionTo(newScene);
155         } else {
156             //這里就是我們自己寫的布局 layout 給關聯到deorview的content布局里面
157             mLayoutInflater.inflate(layoutResID, mContentParent);
158         }
159         final Callback cb = getCallback();
160         if (cb != null && !isDestroyed()) {
161             //添加完畢以后調用回調
162             cb.onContentChanged();
163         }
164     }
View Code

android:windowSoftInputMode,?

7.dialog的window創建過程?

答:子window的創建過程如下:其實和activity的過程差不多 無非是acitivity對于decorView的顯示是自動控制,交給actitytherad 按照流程來走 最后makevISIABLE函數來完成最終顯示的,而dialog就是需要你手動來完成這個過程也就是show函數

 1 //看Dialog的構造函數 ,和acitivity差不多 也是PhoneWindow 對象。
 2 Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
 3         if (createContextThemeWrapper) {
 4             if (themeResId == 0) {
 5                 final TypedValue outValue = new TypedValue();
 6                 context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true);
 7                 themeResId = outValue.resourceId;
 8             }
 9             mContext = new ContextThemeWrapper(context, themeResId);
10         } else {
11             mContext = context;
12         }
13 
14         mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
15 
16         final Window w = new PhoneWindow(mContext);
17         mWindow = w;
18         w.setCallback(this);
19         w.setOnWindowDismissedCallback(this);
20         w.setWindowManager(mWindowManager, null, null);
21         w.setGravity(Gravity.CENTER);
22 
23         mListenersHandler = new ListenersHandler(this);
24     }
25 
26 //Dialog的setContentView方法 也是調用的phonewindow的方法 和acitivity流程也是一樣的
27      public void setContentView(@LayoutRes int layoutResID) {
28         mWindow.setContentView(layoutResID);
29     }
30 
31 
32 //我們都知道dialog必須要show才能顯示出來,
33 
34      public void show() {
35         if (mShowing) {
36             if (mDecor != null) {
37                 if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
38                     mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);
39                 }
40                 mDecor.setVisibility(View.VISIBLE);
41             }
42             return;
43         }
44 
45         mCanceled = false;
46         
47         if (!mCreated) {
48             dispatchOnCreate(null);
49         }
50 
51         onStart();
52         mDecor = mWindow.getDecorView();
53 
54         if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
55             final ApplicationInfo info = mContext.getApplicationInfo();
56             mWindow.setDefaultIcon(info.icon);
57             mWindow.setDefaultLogo(info.logo);
58             mActionBar = new WindowDecorActionBar(this);
59         }
60 
61         WindowManager.LayoutParams l = mWindow.getAttributes();
62         if ((l.softInputMode
63                 & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) {
64             WindowManager.LayoutParams nl = new WindowManager.LayoutParams();
65             nl.copyFrom(l);
66             nl.softInputMode |=
67                     WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
68             l = nl;
69         }
70 
71         try {
72             //在這里 把decorview給add到這個window中了 與activity流程也是一樣的
73             mWindowManager.addView(mDecor, l);
74             mShowing = true;
75     
76             sendShowMessage();
77         } finally {
78         }
79     }
View Code

?

8.Dialog的創建是不是必須要有activity的引用?

windows 11 android、答:不需要,只要你更改為系統window就可以了。系統window是不需要activity作為引用的。注意別遺漏了權限

1  Dialog dialog=new Dialog(MainActivity.this.getApplicationContext());
2                 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
3                 TextView textView=new TextView(MainActivity.this);
4                 textView.setText("this is dialog not use activity this");
5                 dialog.setContentView(textView);
6                 dialog.show();
View Code

?

?9.toast的window創建過程?

答:這屬于系統級別的window創建了,和前面的兩種window創建過程稍微不一樣。其實主要就是notificationmanagerservice和toast本身之間兩者的相互調用而已。

就是簡單的ipc過程。前面binder的教程有講到,如何利用binder來進行雙向通信。toast的源碼 就是利用了binder的雙向通信來完成toast的功能。

源碼就不分析了,ipc的東西講過太多了,有興趣的可以自己看。

轉載于:https://www.cnblogs.com/punkisnotdead/p/5186474.html

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/4/189899.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息