2013-10-29 28 views
14

是否可以通過編程方式枚舉應用程序中的所有android.view.Window或裝飾視圖?有沒有辦法以編程方式在給定的應用程序中找到所有的Windows?

Dialogs例如都將在新的Window中打開,與主Activity窗口分開。我可以通過Dialog.getWindow()找到它們,但我不知道如何使用內置組件(如活動菜單彈出窗口)來執行此操作。

有沒有辦法從Application,ContextWindowManager,或其他什麼東西來枚舉與我的應用程序相關的Windows?

我可以在adb dumpsys window上看到我的應用程序的所有窗口,但我正在尋找一種在我的應用程序中執行此操作而不需要root權限的方法。

+0

活動菜單彈出窗口將與Activity相同,Activity.getWindow()不適合你嗎? – kassim

+0

不幸的是,沒有。我運行Android FingerPaint樣品(上4.3)後,我按由三個圓點構成的菜單按鈕,我可以在監視器彈出的是在自己的窗口看到。 我也可以運行「adb shell dumpsys窗口令牌」,並看到繪圖應用程序確實有兩個與之相關的窗口: allAppWindows = [Window {418f9ce8 u0 com.example.paintsample/com.example.paintsample.PaintSample} ,窗口{41a06d08 U0 PopupWindow:41ac65a0}] 同樣的,對話框。 –

+0

只是好奇,爲什麼你會需要這個信息,或者說,你有什麼打算,一旦你擁有它用它做什麼? – Josh

回答

15

我找到了一種方法,通過@hidden WindowManagerGlobal上的反射來完成它。至少到目前爲止,我知道這適用於android-18。

private void logRootViews() { 
    try { 
     Class wmgClass = Class.forName("android.view.WindowManagerGlobal");       
     Object wmgInstnace = wmgClass.getMethod("getInstance").invoke(null, (Object[])null); 

     Method getViewRootNames = wmgClass.getMethod("getViewRootNames"); 
     Method getRootView = wmgClass.getMethod("getRootView", String.class); 
     String[] rootViewNames = (String[])getViewRootNames.invoke(wmgInstnace, (Object[])null); 

     for(String viewName : rootViewNames) { 
      View rootView = (View)getRootView.invoke(wmgInstnace, viewName); 
      Log.i(TAG, "Found root view: " + viewName + ": " + rootView); 
     } 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

輸出:

實測值根視圖: com.example.paintsample/com.example.paintsample.PaintSample/[email protected]: com.android.internal.policy .impl.PhoneWindow $ DecorView {41dcc278 VE ....ř....... 0,0-768,1184}

實測值根視圖: PopupWindow:42887380/[email protected] : android.widget.PopupWindow $ Popu pViewContainer {42891450 VE .... ........ 0,0-424,618}

賞金這仍然是一個當然的爭奪的人誰可以找到一個更好的辦法:)

3

SDK附帶的Hierarchyviewer工具值得黃金分享。

+0

它,但我一直在尋找一種方式來做到這一點編程(我有,雖然我接觸一個隱藏的類來做到這一點)。 會解決這個問題有點做出更清晰。 –

+0

哦,它沒關係 - 我不認爲你在設備上使用adb dumpsys。 – Pedantic

6

我不完全確定這是回答實際問題,但它是獲得所接受答案中建議的所有根視圖的更好方法。

由於沒有提及,我也成功地做到這一點只使用反射,除非這個代碼支持所有的API 14及以上(我還沒有下文選中)版本:

public static List<View> getWindowManagerViews() { 
    try { 

     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH && 
       Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { 

      // get the list from WindowManagerImpl.mViews 
      Class wmiClass = Class.forName("android.view.WindowManagerImpl"); 
      Object wmiInstance = wmiClass.getMethod("getDefault").invoke(null); 

      return viewsFromWM(wmiClass, wmiInstance); 

     } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 

      // get the list from WindowManagerGlobal.mViews 
      Class wmgClass = Class.forName("android.view.WindowManagerGlobal"); 
      Object wmgInstance = wmgClass.getMethod("getInstance").invoke(null); 

      return viewsFromWM(wmgClass, wmgInstance); 
     } 

    } catch (Exception e) { 
     e.printStackTrace(); 
    } 

    return new ArrayList<View>(); 
} 

private static List<View> viewsFromWM(Class wmClass, Object wmInstance) throws Exception { 

    Field viewsField = wmClass.getDeclaredField("mViews"); 
    viewsField.setAccessible(true); 
    Object views = viewsField.get(wmInstance); 

    if (views instanceof List) { 
     return (List<View>) viewsField.get(wmInstance); 
    } else if (views instanceof View[]) { 
     return Arrays.asList((View[])viewsField.get(wmInstance)); 
    } 

    return new ArrayList<View>(); 
} 
+1

這是這裏最好的解決方案! – refaelos

0

你可以直接使用@隱藏的API,不需要通過訪問類文件來反射,然後添加到Android SDK中的android.jar中。具體方法如下: https://devmaze.wordpress.com/2011/01/18/using-com-android-internal-part-1-introduction/

而對於Android源。罐子特定Android版本(19,21,22,23,24)可以在這裏抓起:那麼 https://github.com/anggrayudi/android-hidden-api

,你可以直接使用WindowManagerGlobal類來獲取所有的根的觀點類似,

private void logRootViews() { 
    WindowManagerGlobal windowManagerGlobal = WindowManagerGlobal.getInstance(); 
    String[] rootViewNames = windowManagerGlobal.getViewRootNames(); 

    for (String viewName : rootViewNames) { 
     View rootView = windowManagerGlobal.getRootView(viewName); 
     Log.i("", "Root view is: " + viewName + ": " + rootView); 
     /*do what you want with the rootView*/ 
    } 
} 

輸出:

根的觀點是:com.example.paintsample/com.example.paintsample.PaintSample/[email protected]:com.android.internal.policy.impl.PhoneWindow $ {DecorView 41dcc278 VE .... R ....... 0,0-768,1184}

根的觀點是:PopupWindow:42887380/[email protected]:android.widget.PopupWindow $ {PopupViewContainer VE 42891450 .... ........ 0,0-424,618}

相關問題