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控件并加入到该哈希表中,所以该哈希表中维护的是一个当前已经使用过的控件