上一篇记录到了View控件的获取,获取windowManager类中mView属性的值,并从中筛选非DecorView和Activity/Dialog的DecorView,从而获得所有view
在这篇记录中,将记录我对search类的方法源码研究的一些总结
以SearchText为例,通过Solo的searchText(String text)方法调用searcher.searchWithTimeoutFor(TextView.class, text, 0, true, false)方法,在这里有一个计时器,如果到时还未找到,则返回false 方法如下
public boolean searchWithTimeoutFor(Class<? extends TextView> viewClass, String regex, int expectedMinimumNumberOfMatches, boolean scroll, boolean onlyVisible) {
final long endTime = SystemClock.uptimeMillis() + TIMEOUT;
TextView foundAnyMatchingView = null;
while (SystemClock.uptimeMillis() < endTime) {
sleeper.sleep();
foundAnyMatchingView = searchFor(viewClass, regex, expectedMinimumNumberOfMatches, 0, scroll, onlyVisible);
if (foundAnyMatchingView !=null){
return true;
}
}
return false;
}
在计时时间内调用SearchFor()方法,其中 修改了expectedMinimumNumberOfMatches:这个参数表示搜索目标最小发现数目,当一个界面中有多个控件满足搜索条件,通过此参数可以指定想要获取的是第几个。
public <T extends TextView> T searchFor(final Class<T> viewClass, final String regex, int expectedMinimumNumberOfMatches, final long timeout, final boolean scroll, final boolean onlyVisible) {
if(expectedMinimumNumberOfMatches < 1) {
expectedMinimumNumberOfMatches = 1;
}
<pre class="prettyprint xml"><span class="tag">
//定义一个<span class="attribute">Callable</span>给下层<span class="attribute">searchFor</span>使用,可以直接获取到符合条件的控件列表</span>
final Callable<Collection<T>> viewFetcherCallback = new Callable<Collection<T>>() {
@SuppressWarnings("unchecked")public Collection<T> call() throws Exception {sleeper.sleep();
//从当前的Android View中获取到符合viewClass的控件列表
ArrayList<T> viewsToReturn = viewFetcher.getCurrentViews(viewClass, true);if(onlyVisible){viewsToReturn = RobotiumUtils.removeInvisibleViews(viewsToReturn);}if(viewClass.isAssignableFrom(TextView.class)) {viewsToReturn.addAll((Collection<? extends T>) webUtils.getTextViewsFromWebView());}return viewsToReturn;}};try {return searchFor(viewFetcherCallback, regex, expectedMinimumNumberOfMatches, timeout, scroll);} catch (Exception e) {throw new RuntimeException(e);}}
在call()方法中调用getCurrentViews()方法,将符合条件的view列表返回
public <T extends View> ArrayList<T> getCurrentViews(Class<T> classToFilterBy, boolean includeSubclasses, View parent) {
ArrayList<T> filteredViews = new ArrayList<T>();
List<View> allViews = getViews(parent, true);
for(View view : allViews){
if (view == null) {
continue;
}
Class<? extends View> classOfView = view.getClass();
if (includeSubclasses && classToFilterBy.isAssignableFrom(classOfView) || !includeSubclasses && classToFilterBy == classOfView) {
filteredViews.add(classToFilterBy.cast(view));
}
}
allViews = null;
return filteredViews;
}
将定义的viewFetcherCallback 传递给 searchFor()方法,在此方法中完成真正的"查找"
public <T extends TextView> T searchFor(Callable<Collection<T>> viewFetcherCallback, String regex, int expectedMinimumNumberOfMatches, long timeout, boolean scroll) throws Exception {
final long endTime = SystemClock.uptimeMillis() + timeout;
Collection<T> views;
while (true) {
final boolean timedOut = timeout > 0 && SystemClock.uptimeMillis() > endTime;
if(timedOut){
logMatchesFound(regex);
return null;
}
views = viewFetcherCallback.call();
for(T view : views){
if (RobotiumUtils.getNumberOfMatches(regex, view, uniqueTextViews) == expectedMinimumNumberOfMatches) {
uniqueTextViews.clear();
return view;
}
}
if(scroll && !scroller.scrollDown()){
logMatchesFound(regex);
return null;
}
if(!scroll){
logMatchesFound(regex);
return null;
}
}
}
首先回调刚刚定义的Callable的call()方法得到所有的符合view的列表,在遍历这个列表调用getNumberOfMatches()方法在查询
public static int getNumberOfMatches(String regex, TextView view, Set<TextView> uniqueTextViews){
if(view == null) {
return uniqueTextViews.size();
}
Pattern pattern = null;
try{
pattern = Pattern.compile(regex);
}catch(PatternSyntaxException e){
pattern = Pattern.compile(regex, Pattern.LITERAL);
}
Matcher matcher = pattern.matcher(view.getText().toString());
if (matcher.find()){
uniqueTextViews.add(view);
}
if (view.getError() != null){
matcher = pattern.matcher(view.getError().toString());
if (matcher.find()){
uniqueTextViews.add(view);
}
}
if (view.getText().toString().equals("") && view.getHint() != null){
matcher = pattern.matcher(view.getHint().toString());
if (matcher.find()){
uniqueTextViews.add(view);
}
}
return uniqueTextViews.size();
}
这个方法使用正则表达式来查找匹配的文本 如果找到就放在uniqueTextView中最后返回列表的大小
最后SearchFor()方法将找到的View返回,最后返回一个true 查找结束