appium源码分析(六)-find(下)
来源:互联网 发布:淘宝达人就是微淘吗 编辑:程序博客网 时间:2024/05/20 16:32
其实上一篇讲对find的源码分析讲的不太好,因为讲的时候,没让大家明白关于AndroidElement,以及AndroidElementsHash的定义。以及例如我们通过driver.find_element_by_name('hello').send)_keys('haha')
的时候appium是根据什么来对这个元素进行操作的呢,是根据前面我们传入的hello吗?
所以这次在讲find的源码剩余内容时,我们先穿插着讲下以上的内容
AndroidElement与UiObject的关系
我们来看看AndroidElement的成员变量就一目了然了
private final UiObject el;private String id;AndroidElement(final String id, final UiObject el) { this.el = el; this.id = id;}
AndroidElement中定义了一个Uiobject的元素对象 以及一个String类型的id值,这里的UiObject元素对象,就是我们要操作的元素了。实际上我们进行点击操作时,可以看看AndroidElement的click方法
public boolean click() throws UiObjectNotFoundException { return el.click(); }
实际上它直接就是调用了UiAutomator中的click方法。
再来说下String id这个值又是什么呢?或者我们先看看appium 的log是否有什么收获
由这个log大概就能够的出来,elementId 就是我们之前说的String id了。那个elementId这个值又是从哪里来的呢。
AndroidElementsHash与ElementId
我们先来看看AndroidElementsHash吧,AndroidElementsHash拥有两个成员变量
private final Hashtable<String, AndroidElement> elements; private Integer counter;
elements:是有个哈希表,它的key实际上就是AndroidElement的Id值,value就是AndroidElement
counter:实际上代表的是当前一共用到的控件的个数,以及后续新增一个控件的话,它就会自增1.
public static AndroidElementsHash getInstance() { if (AndroidElementsHash.instance == null) { AndroidElementsHash.instance = new AndroidElementsHash(); } return AndroidElementsHash.instance; }private static AndroidElementsHash instance;/** * Constructor */public AndroidElementsHash() { counter = 0; elements = new Hashtable<String, AndroidElement>();}
以上的代码要说下的是AndroidElementHash是一个单例模式,这样子也保证了elements 不会再重新被初始化。构造函数则是初始化counter的值为0
我们看下addElement方法就大概能知道,AndroidElementsHash是怎么生成的了。
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; }
这段代码应该不难理解了,每当一个新的元素增加counter的值就加1
最后我们在来分析下getElement,实际上getElement对应的就是我们平时用的find_element的方法,
但是查找实际上分为两种
- 基于Appium driver进行的查找
基于父控件的查找
有了前面这些的了解 我们再来看看getElement的代码吧
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(); } }
从上面的代码就可以看出来,如果说baseEl为空的情况下,这种情况就是直接通过driver进行查找
当不为空的时候,就是基于父控件的查找了。以上的查找是查找当个元素的。但是各位别忘了我们有时候还会使用到driver.find_elements()这种查看多个元素的方法。
那查找多个元素的时候与查找单个元素是一样的吗,我们来看看代码吧。
public ArrayList<AndroidElement> getElements(final UiSelector sel, final String key) throws UiObjectNotFoundException { boolean keepSearching = true; final String selectorString = sel.toString(); final boolean useIndex = selectorString.contains("CLASS_REGEX="); final boolean endsWithInstance = endsWithInstancePattern.matcher(selectorString).matches(); Logger.debug("getElements selector:" + selectorString); final ArrayList<AndroidElement> elements = new ArrayList<AndroidElement>(); // If sel is UiSelector[CLASS=android.widget.Button, INSTANCE=0] // then invoking instance with a non-0 argument will corrupt the selector. // // sel.instance(1) will transform the selector into: // UiSelector[CLASS=android.widget.Button, INSTANCE=1] // // The selector now points to an entirely different element. if (endsWithInstance) { Logger.debug("Selector ends with instance."); // There's exactly one element when using instance. UiObject instanceObj = new UiObject(sel); if (instanceObj != null && instanceObj.exists()) { elements.add(addElement(instanceObj)); } return elements; } UiObject lastFoundObj; final AndroidElement baseEl = this.getElement(key); UiSelector tmp; int counter = 0; while (keepSearching) { if (baseEl == null) { Logger.debug("Element[" + key + "] is null: (" + counter + ")"); if (useIndex) { Logger.debug(" using index..."); tmp = sel.index(counter); } else { tmp = sel.instance(counter); } Logger.debug("getElements tmp selector:" + tmp.toString()); lastFoundObj = new UiObject(tmp); } else { Logger.debug("Element[" + key + "] is " + baseEl.getId() + ", counter: " + counter); lastFoundObj = baseEl.getChild(sel.instance(counter)); } counter++; if (lastFoundObj != null && lastFoundObj.exists()) { elements.add(addElement(lastFoundObj)); } else { keepSearching = false; } } return elements; }
查找多个元素确实会复杂很多
- 首先getElements会判断传参来的UiSelector是否是以Instance结尾的,如果包含的话,那就直接new UiObject进行查找就可以了。
如果并不是以Instance结尾的时候,还是分两种情况,首先是基于appium driver进行查找还是基于父控件的查找,再来就是直接selector查找时,后面跟上instance(counter) ,每当能够查找到元素时,counter就会自增1接着继续查找。直到没要找到对应的元素后,才会跳出循环。
例:
self.driver.find_elements_by_class_name("android.widget.TextView")
运行的log记录即为
分析
回到最初find的源代码处
found = foundElements.size() > 0;result = elementsToJSONArray(foundElements);
当找到的元素大于0时,将list类型的元素转化成json数组返回给server,可以从上图的log中看出。
- appium源码分析(六)-find(下)
- Appium源码分析(六)-find(上)
- Appium源码分析(四)-swipe
- Appium源码分析(五)-drag
- Appium源码分析(七)-click
- appium源码分析(八)-touch
- appium源码分析(九)-getText,setText
- appium源码分析(十)-GetAttribute
- appium源码分析(十一)-getSize,getLocation
- appium 源码分析(十二)-pressKeyCode,LongPressKeyCode
- appium源码分析(十三)-UpdateStrings
- Appium Server 源码分析(一)
- appium Bootstrap UiSelectorParser源码分析
- quake3 源码分析(六)
- logcat源码分析(六)
- pomelo源码分析(六)
- mosquitto源码分析(六)
- openMPM源码分析(六)
- 简单之局部函数保护,加密等预防措施(动态内存)
- cocos2d-x & cocostudio bug记录
- Restore versus recovery
- PHP的内存释放问题
- 张孝祥java视频学习笔记(四)
- appium源码分析(六)-find(下)
- Ruby安装
- linux查看主板型号,cpu,内存,内存条数量,网卡等
- 云端数据加密的七大标准
- java之序列化
- 自己作死的节奏
- java 读excel包括不同版本读取,读合并单元格和读公式
- Fox Pro Access数据库知识点总结
- htaccess