不使用Activity如何新增一個View

釋然小師弟發表於2019-11-06

WindowManger詳解

更新

直播回放已放出,請戳連結食用:不使用Activity如何新增一個View

整體方案

在Service中通過WindowManger新增View的方式來把UI介面顯示出來

業務場景

具體場景

  • IQOO手機,遊戲輔助

不使用Activity如何新增一個View

這種場景能否使用Activity方式來做

使用activity會對下層window產生阻塞,而使用WindowManager新增view的方式則不會阻塞

WindowManger簡介

WindowManger是普通App程式用來與系統服務(WindowMangerService)通訊的一個介面。 獲取WindowManger例項物件的方法是使用Context.getSystemService(Context.WINDOW_SERVICE

如何使用

  1. 新增許可權
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
複製程式碼
  1. 手動引導開啟顯示在其他應用上層

  2. 獲取WindowManger並新增View

WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); //獲取系統服務
windowManager.addView(myView, p);
複製程式碼
  1. 不使用時移除View

WindowManager使用詳解

WindowManger

  1. 新增View :addView()

    注意 同一個window,只能新增一個View,新增多個View會報出以下異常

Caused by: java.lang.IllegalStateException: View android.widget.RelativeLayout{b3a2c6a V.E...... ......I. 0,0-0,0 #7f070081 app:id/rl_root} has already been added to the window manager.
複製程式碼
  1. 移除View : remoview()

由於同一個View只能新增一個View,所以,要想在已新增View的Window中再新增View,必須先移除已新增的View

  1. 更新佈局屬性 :updateViewLayout(view,params)

通過對第二個引數WindowManger.LayoutParams的屬性設定後,呼叫本方法才會使這些屬性生效

WindowManger.LayoutParms

WindowManger.LayoutParms 其實是ViewGrop.LayoutParms的子類物件,所以View設定LayoutParams時可以直接設定

  1. 控制是否可以響應觸控事件

    layoutParams.type

    • FLAG_NOT_TOUCHABLE
    • FLAG_NOT_TOUCH_MODAL
  2. 控制window的顯示層級

    layoutParams.type

    • TYPE_TOAST(Andorid 5.0及以下系統版本可規避許可權問題)
    • TYPE_APPLICATION_WINOW (應用層Winow等級)
    • TYPE_PRIORTY_PHONE (系統層Window等級)
  3. 控制view的顯示範圍

    layoutParams.flags

    • FLAG_FULLSCREEN
    • FLAG_LAYOUT_IN_SCREEN
  4. 控制view的顯示位置
    • layoutParams.width
    • layoutParams.height

示例專案

github.com/happyburgla…

還要注意哪些問題?

  1. 使用單獨程式,避免影響主業務功能
  2. 提升程式優先順序,避免被Kill
    • 使用前臺服務
    • 1畫素保活
    • 繫結系統服務

    提示:可通過oom_adj檢視某個程式的程式等級

  3. 要對服務被Kill後的重啟邏輯進行處理

原始碼淺析

由於時間關係,這裡我們只對相關原始碼進行一個簡單的介紹,先來看下相關的類

不使用Activity如何新增一個View

WindowManger這個類,其實只是一個介面,用來溝通普通應用程式和系統服務WindowMangerservice

我們在上面的使用中也看到了,獲取WindowManger這個類的例項物件,是通過Context.getSystemServer(Context.WINDOW_SERICE)獲取的

通過上面的UML類圖我們也可以看到,其實WindowManger是一個介面,而它的真正的例項物件是WindowMangerImpl這個類

WindowMangerImpl又把具體的新增View的工作封裝到了WindowManagerGlobal中來操作,這個類中又涉及到了另外一個重要的類--Display,這個類主要是封裝了一些顯示相關的資訊,比如window的邏輯寬顯示資料(logical displays)和物理顯示資料(physical displays)

什麼是logical displays

原始碼中對此解釋是,邏輯顯示不一定代表特定的物理顯示裝置,例如內建螢幕或外接顯示器。 邏輯上的內容根據裝置的不同,螢幕可以顯示在一個或多個物理螢幕上

什麼是physical displays

就是Android裝置螢幕的真實的Displays資料,比如你的手機是4K的螢幕(physical displays),但是廠商為了進行一些優化工作(比如省電?)可以把顯示尺寸(logical displays)設定為1920* 1080

鄭重宣告

本文版權歸Android研習社所有,未經允許禁止轉載,侵權必究!

相關文章