<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    qileilove

    blog已經轉移至github,大家請訪問 http://qaseven.github.io/

    Appium Android Bootstrap之控件AndroidElement

    AndroidElementHash的這個getElement命令要做的事情就是針對這兩點來根據不同情況獲得目標控件
    /**
    * Return an elements child given the key (context id), or uses the selector
    * to get the element.
    *
    * @param sel
    * @param key
    *          Element id.
    * @return {@link AndroidElement}
    * @throws ElementNotFoundException
    */
    public AndroidElement getElement(final UiSelector sel, final String key)
    throws ElementNotFoundException {
    AndroidElement baseEl;
    baseEl = elements.get(key);
    UiObject el;
    if (baseEl == null) {
    el = new UiObject(sel);
    } else {
    try {
    el = baseEl.getChild(sel);
    } catch (final UiObjectNotFoundException e) {
    throw new ElementNotFoundException();
    }
    }
    if (el.exists()) {
    return addElement(el);
    } else {
    throw new ElementNotFoundException();
    }
    }
      如果是第1種情況就直接通過選擇子構建UiObject對象,然后通過addElement把UiObject對象轉換成AndroidElement對象保存到控件哈希表
      如果是第2種情況就先根據appium傳過來的控件哈希表鍵值獲得父控件,再通過子控件的選擇子在父控件的基礎上查找到目標UiObject控件,最后跟上面一樣把該控件通過上面的addElement把UiObject控件轉換成AndroidElement控件對象保存到控件哈希表
      4. 求證
      上面有提過,如果pc端的腳本執行對同一個控件的兩次findElement會創建兩個不同id的AndroidElement并存放到控件哈希表中,那么為什么appium的團隊沒有做一個增強,增加一個keyMap的方法(算法)和一些額外的信息來讓同一個控件使用不同的key的時候對應的還是同一個AndroidElement控件呢?畢竟這才是哈希表實用的特性之一了,不然你直接用一個Dictionary不就完事了?網上說了幾點hashtable和dictionary的差別,如多線程環境最好使用哈希表而非字典等,但在bootstrap這個控件哈希表的情況下我不是很信服這些說法,有誰清楚的還勞煩指點一二了
      這里至于為什么appium不去提供額外的key信息并且實現keyMap算法,我個人倒是認為有如下原因:
      有誰這么無聊在同一個測試方法中對同一個控件查找兩次?
      如果同一個控件運用不同的選擇子查找兩次的話,因為最終底層的UiObject的成員變量UiSelector mSelector不一樣,所以確實可以認為是不同的控件
      但以下兩個如果用同樣的UiSelector選擇子來查找控件的情況我就解析不了了,畢竟在我看來bootstrap這邊應該把它們看成是同一個對象的:
      同一個腳本不同的方法中分別對同一控件用同樣的UiSelelctor選擇子進行查找呢?
      不同腳本中呢?
      這些也許在今后深入了解中得到解決,但看家如果知道的,還望不吝賜教
      5. 小結
      最后我們對bootstrap的控件相關知識點做一個總結
      AndroidElement的一個實例代表了一個bootstrap的控件
      AndroidElement控件的成員變量UiObject el代表了uiautomator框架中的一個真實窗口控件,通過它就可以直接透過uiautomator框架對控件進行實質性操作
      pc端的WebElement元素和Bootstrap的AndroidElement控件是通過AndroidElement控件的String id進行映射關聯的
      AndroidElementHash類維護了一個以AndroidElement的id為鍵值,以AndroidElement的實例為value的全局唯一哈希表,pc端想要獲得一個控件的時候會先從這個哈希表查找,如果沒有了再創建新的AndroidElement控件并加入到該哈希表中,所以該哈希表中維護的是一個當前已經使用過的控件
    相關文章:
    Appium Android Bootstrap源碼分析之簡介
     通過上一篇文章Appium Android Bootstrap源碼分析之簡介》我們對bootstrap的定義以及其在appium和uiautomator處于一個什么樣的位置有了一個初步的了解,那么按照正常的寫書的思路,下一個章節應該就要去看bootstrap是如何建立socket來獲取數據然后怎樣進行處理的了。但本人覺得這樣子做并不會太好,因為到時整篇文章會變得非常的冗長,因為你在編寫的過程中碰到不認識的類又要跳入進去進行說明分析。這里我覺得應該嘗試吸取著名的《重構》這本書的建議:一個方法的代碼不要寫得太長,不然可讀性會很差,盡量把其分解成不同的函數。那我們這里就是用類似的思想,不要嘗試在一個文章中把所有的事情都做完,而是嘗試先把關鍵的類給描述清楚,最后才去把這些類通過一個實例分析給串起來呈現給讀者,這樣大家就不會因為一個文章太長影響可讀性而放棄往下學習了。
      那么我們這里為什么先說bootstrap對控件的處理,而非剛才提到的socket相關的socket服務器的建立呢?我是這樣子看待的,大家看到本人這篇文章的時候,很有可能之前已經了解過本人針對uiautomator源碼分析那個系列的文章了,或者已經有uiautomator的相關知識,所以腦袋里會比較迫切的想知道究竟appium是怎么運用了uiautomator的,那么在appium中于這個問題最貼切的就是appium在服務器端是怎么使用了uiautomator的控件的。
      這里我們主要會分析兩個類:
      AndroidElement:代表了bootstrap持有的一個ui界面的控件的類,它擁有一個UiObject成員對象和一個代表其在下面的哈希表的鍵值的String類型成員變量id
      AndroidElementsHash:持有了一個包含所有bootstrap(也就是appium)曾經見到過的(也就是腳本代碼中findElement方法找到過的)控件的哈希表,它的key就是AndroidElement中的id,每當appium通過findElement找到一個新控件這個id就會+1,Appium的pc端和bootstrap端都會持有這個控件的id鍵值,當需要調用一個控件的方法時就需要把代表這個控件的id鍵值傳過來讓bootstrap可以從這個哈希表找到對應的控件
      1. AndroidElement和UiObject的組合關系
      從上面的描述我們可以知道,AndroidElement這個類里面擁有一個UiObject這個變量:
      public class AndroidElement {
      private final UiObject el;
      private String         id;
      ...
      }
      大家都知道UiObject其實就是UiAutomator里面代表一個控件的類,通過它就能夠對控件進行操作(當然最終還是通過UiAutomation框架). AnroidElement就是通過它來跟UiAutomator發生關系的。我們可以看到下面的AndroidElement的點擊click方法其實就是很干脆的調用了UiObject的click方法:
      public boolean click() throws UiObjectNotFoundException {
      return el.click();
      }
      當然這里除了click還有很多控件相關的操作,比如dragTo,getText,longClick等,但無一例外,都是通過UiObject來實現的,這里就不一一列舉了。
      2. 腳本的WebElement和Bootstrap的AndroidElement的映射關系
      我們在腳本上對控件的認識就是一個WebElement:
      WebElement addNote =  driver.findElementByAndroidUIAutomator("new UiSelector().text(\"Add note\")");
      而在Bootstrap中一個對象就是一個AndroidElement. 那么它們是怎么映射到一起的呢?我們其實可以先看如下的代碼:
      WebElement addNote = driver.findElementByAndroidUIAutomator("new UiSelector().text(\"Add note\")");
      addNote.getText();
      addNote.click();
      做的事情就是獲得Notes這個app的菜單,然后調用控件的getText來獲得‘Add note'控件的文本信息,以及通過控件的click方法來點擊該控件。那么我們看下調試信息是怎樣的:

    pc端傳過來的json字串有幾個fields:
      cmd:代表這個是什么命令類型,其實就是AndroidCommandType的那兩個值
      package io.appium.android.bootstrap;
      /**
      * Enumeration for all the command types.
      *
      */
      public enum AndroidCommandType {
      ACTION, SHUTDOWN
      }
      action: 具體命令
      params: 提供的參數,這里提供了一個elementId的鍵值對
      從上面的兩條調試信息看來,其實沒有明顯的看到究竟使用的是哪個控件。其實這里不起眼的elementId就是確定用的是哪個控件的,注意這個elementId并不是一個控件在界面上的資源id,它其實是Bootstrap維護的一個保存所有已經獲取過的控件的哈希表的鍵值。如上一小節看到的,每一個AndroidElement都有兩個重要的成員變量:
      UiObject el :uiautomator框架中代表了一個真實的窗口控件
      Sting id :  一個唯一的自動增加的字串類型整數,pc端就是通過它來在AndroidElementHash這個類中找到想要的控件的
      3. AndroidElement控件哈希表
      上一節我們說到appium pc端是通過id把WebElement和目標機器端的AndroidElement映射起來的,那么我們這一節就來看下維護AndroidElement的這個哈希表是怎么實現的。
      首先,它擁有兩個成員變量:
      private final Hashtable<String, AndroidElement> elements;
      private       Integer                           counter;
      elements :一個以AndroidElement 的id的字串類型為key,以AndroidElement的實例為value的的哈希表
      counter : 一個整型變量,有兩個作用:其一是它代表了當前已經用到的控件的數目(其實也不完全是,你在腳本中對同一個控件調用兩次findElement其實會產生兩個不同id的AndroidElement控件),其二是它代表了一個新用到的控件的id,而這個id就是上面的elements哈希表的鍵
      這個哈希表的鍵值都是從0開始的,請看它的構造函數:
      /**
      * Constructor
      */
      public AndroidElementsHash() {
      counter = 0;
      elements = new Hashtable<String, AndroidElement>();
      }
      而它在整個Bootstrap中是有且只有一個實例的,且看它的單例模式實現:
      public static AndroidElementsHash getInstance() {
      if (AndroidElementsHash.instance == null) {
      AndroidElementsHash.instance = new AndroidElementsHash();
      }
      return AndroidElementsHash.instance;
      }
      以下增加一個控件的方法addElement充分描述了為什么說counter是一個自增加的key,且是每個新發現的AndroidElement控件的id:
      public AndroidElement addElement(final UiObject element) {
      counter++;
      final String key = counter.toString();
      final AndroidElement el = new AndroidElement(key, element);
      elements.put(key, el);
      return el;
      }
      從Appium發過來的控件查找命令大方向上分兩類:
      1. 直接基于Appium Driver來查找,這種情況下appium發過來的json命令是不包含控件哈希表的鍵值信息的
      WebElement addNote = driver.findElement(By.name("Add note"));
      2. 基于父控件查找:
      WebElement el = driver.findElement(By.className("android.widget.ListView")).findElement(By.name("Note1"));
      以上的腳本會先嘗試找到Note1這個日記的父控件ListView,并把這個控件保存到控件哈希表,然后再根據父控件的哈希表鍵值以及子控件的選擇子找到想要的Note1:

    posted on 2014-12-23 00:26 順其自然EVO 閱讀(2530) 評論(0)  編輯  收藏 所屬分類: android

    <2014年12月>
    30123456
    78910111213
    14151617181920
    21222324252627
    28293031123
    45678910

    導航

    統計

    常用鏈接

    留言簿(55)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 国产裸模视频免费区无码| 免费视频专区一国产盗摄| 免费h黄肉动漫在线观看| 国产成人亚洲综合网站不卡| 亚洲黄色免费电影| 亚洲国产日韩女人aaaaaa毛片在线| 久久精品私人影院免费看| 国产aⅴ无码专区亚洲av| 国产va在线观看免费| 中文字幕亚洲免费无线观看日本| 99久在线国内在线播放免费观看| 亚洲精品福利网泷泽萝拉| 国产一卡二卡3卡四卡免费| 亚洲一线产品二线产品| 国产成人精品免费直播| 久99久无码精品视频免费播放| 亚洲国产成人精品无码区在线观看| 久久精品免费观看国产| 亚洲一区二区三区精品视频| 美女被免费视频网站a国产| 青草青草视频2免费观看| 亚洲日韩精品A∨片无码| 18禁男女爽爽爽午夜网站免费| 亚洲妇女熟BBW| 精品国产日韩亚洲一区| 7x7x7x免费在线观看| 亚洲国产日韩a在线播放| 久久亚洲中文字幕精品一区 | 黄色一级视频免费观看| 国产亚洲成人在线播放va| 最近免费最新高清中文字幕韩国| 亚洲中文字幕无码mv| 亚洲伊人色欲综合网| 可以免费看黄的网站| 又黄又大的激情视频在线观看免费视频社区在线 | 最新国产精品亚洲| 久久精品国产亚洲Aⅴ蜜臀色欲 | 精品国产精品久久一区免费式| 久久精品免费网站网| 亚洲国产成人在线视频| 亚洲一区无码精品色|