2018-10-18
我們知道android中的view的更新(大小,位置,內容)全部都交給了WindowManager,其實現類為WindowManagerImpl有著三大方法addView,updateViewLayout,removeView。由意思可以做到他們的具體功能,對應著新增view,更新view,和刪去view。 removeViewImmediate和removeView的區別在於removeViewImmediate為同步刪除和非同步刪除。
private void initView() { final Button newButton=new Button(MainActivity.this); Button button=findViewById(R.id.start); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new Thread(new Runnable() { @Override public void run() { Looper.prepare(); windowManager = (WindowManager) MainActivity.this.getSystemService(WINDOW_SERVICE); newButton.setText("it was created"); params = new WindowManager.LayoutParams(); params.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; // 設定不攔截焦點 params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; params.width = (int) (60 * getResources().getDisplayMetrics().density); params.height = (int) (60 * getResources().getDisplayMetrics().density); params.gravity = Gravity.LEFT | Gravity.TOP;// 且設定座標系 左上角 params.format = PixelFormat.TRANSPARENT; int width = windowManager.getDefaultDisplay().getWidth(); int height = windowManager.getDefaultDisplay().getHeight(); params.y = height / 2 - params.height / 2; windowManager.addView(newButton, params); Looper.loop(); } }).start(); } }); Button button1=findViewById(R.id.end); button1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { windowManager.removeView(newButton); } }); }
程式碼中點選start按鈕在一個新的執行緒中addview,顯示一個新的button,再點選end按鈕在主執行緒中removeView刪除掉。

1.gif
可以看出來完美,成功執行,然而把windowManager.removeView(newButton);改成windowManager.removeViewImmediate(newButton);

image.png
程式奔潰掉,提示Only the original thread that created a view hierarchy can touch its views.
由於WindowManagerGlobal.checkThread檢查當前執行緒是不是建立view的執行緒,是的話再在ViewRootImpl進行刪除view處理。然而removiewImmedate是在主執行緒執行的,所以奔了。
而removeView非同步執行,傳送一個MES_DIE訊息,再由ViewRootImpl進行刪除操作。