看了一下源码,但还没搭建好调试环境,所以跟踪到某一步后就跟踪不下去了。在此仅分享一下找的过程:
先接着 doctorq 的思路,去找 android 源码中的getRootInActiveWindow
:
android.app.UiAutomation
/**
* Gets the root {@link AccessibilityNodeInfo} in the active window.
*
* @return The root info.
*/
public AccessibilityNodeInfo getRootInActiveWindow() {
final int connectionId;
synchronized (mLock) {
throwIfNotConnectedLocked();
connectionId = mConnectionId;
}
// Calling out without a lock held.
return AccessibilityInteractionClient.getInstance()
.getRootInActiveWindow(connectionId);
}
接着找 return 中的getRootInActiveWindow
:
android.view.acessibility.AccessibilityInteractionClient
/**
* Gets the root {@link AccessibilityNodeInfo} in the currently active window.
*
* @param connectionId The id of a connection for interacting with the system.
* @return The root {@link AccessibilityNodeInfo} if found, null otherwise.
*/
public AccessibilityNodeInfo getRootInActiveWindow(int connectionId) {
return findAccessibilityNodeInfoByAccessibilityId(connectionId,
AccessibilityNodeInfo.ACTIVE_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID,
false, AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS);
}
继续找findAccessibilityNodeInfoByAccessibilityId
:
android.view.acessibility.AccessibilityInteractionClient
/**
* Finds an {@link AccessibilityNodeInfo} by accessibility id.
*
* @param connectionId The id of a connection for interacting with the system.
* @param accessibilityWindowId A unique window id. Use
* {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
* to query the currently active window.
* @param accessibilityNodeId A unique view id or virtual descendant id from
* where to start the search. Use
* {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID}
* to start from the root.
* @param bypassCache Whether to bypass the cache while looking for the node.
* @param prefetchFlags flags to guide prefetching.
* @return An {@link AccessibilityNodeInfo} if found, null otherwise.
*/
public AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityId(int connectionId,
int accessibilityWindowId, long accessibilityNodeId, boolean bypassCache,
int prefetchFlags) {
try {
IAccessibilityServiceConnection connection = getConnection(connectionId);
if (connection != null) {
if (!bypassCache) {
AccessibilityNodeInfo cachedInfo = sAccessibilityNodeInfoCache.get(
accessibilityNodeId);
if (cachedInfo != null) {
return cachedInfo;
}
}
final int interactionId = mInteractionIdCounter.getAndIncrement();
final boolean success = connection.findAccessibilityNodeInfoByAccessibilityId(
accessibilityWindowId, accessibilityNodeId, interactionId, this,
prefetchFlags, Thread.currentThread().getId());
// If the scale is zero the call has failed.
if (success) {
List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
interactionId);
finalizeAndCacheAccessibilityNodeInfos(infos, connectionId);
if (infos != null && !infos.isEmpty()) {
return infos.get(0);
}
}
} else {
if (DEBUG) {
Log.w(LOG_TAG, "No connection for connection id: " + connectionId);
}
}
} catch (RemoteException re) {
if (DEBUG) {
Log.w(LOG_TAG, "Error while calling remote"
+ " findAccessibilityNodeInfoByAccessibilityId", re);
}
}
return null;
}
注意中间的connection.findAccessibilityNodeInfoByAccessibilityId
,我用的 IDE 是 Android Studio,findAccessibilityNodeInfoByAccessibilityId
方法显示为红色,表示找不到它的声明位置。
然后我们看看 connection 的声明:
·IAccessibilityServiceConnection connection = getConnection(connectionId);·
它是通过getConnection(connectionId)
获得的实例,继续找:
public IAccessibilityServiceConnection getConnection(int connectionId) {
synchronized (sConnectionCache) {
return sConnectionCache.get(connectionId);
}
}
再找sConnectionCache
:
// The connection cache is shared between all interrogating threads.
private static final SparseArray<IAccessibilityServiceConnection> sConnectionCache =
new SparseArray<IAccessibilityServiceConnection>();
继续IAccessibilityServiceConnection
,这时候只能找到一个相关的 import 语句了:
import android.accessibilityservice.IAccessibilityServiceConnection;
到这里为止,寻找方法声明位置的这种方法找不下去了,因为源码里找不到IAccessibilityServiceConnection
声明的位置。
大致猜测是本来每个 Node 其实都带有一定的信息 (具体有哪些信息可以在android.accessibilityservice.AccessibilityServiceInfo
找到) 表示它是否影响显示,--compress 插入的标志位会在存储 Node 时不存储这些不影响显示的 Node。具体是如何实现的等研究好如何搭建调试环境后继续研究。
看完以后,我觉得我压根就没学会设计模式。用过 singleton,但没试过探究到内存这么深入。赞一个
@ice87875494 这个库是用来给其他应用调用的。你应该下载下来后用其他 py 文件 import pylib 来使用。
举个例子:
folder
├─pylib(pylib源码)
│ test.py
此时 test.py 里面使用import pylib
就能 import。
在 module xxx 里面 import xxx 是会提示" No module named xxx"的,因为这个 module 不在查找范围内。具体 import 过程可以看看import system
12 年实习,一开始主要做政府部门的验收测试(公司拿到了对应的资质证书),2~3 天把项目的招标、需求、概设、详设等看完并根据需求写用例,然后又 2~3 天到客户现场把用例执行完(功能测试和压力测试,使用 LoadRunner 录脚本然后根据需求确认性能点是否达标),最后出报告。基本上 1 周 1 个项目的节奏。后面公司需要人手做公司的操作系统的兼容性测试,于是学习了 linux,开始用 shell 脚本来跑一部分测试(脚本都是别人写好的,当时对 linux 的东西还不是太了解),测试安装、驱动性能等。
13 年毕业,进入一个做海外外包的外企,进入了一个产品线包括嵌入式、web、android、ios 的项目。第一年先是做 ios 测试,然后 android,然后 web,都是纯手工测试。业余学了一些 ios 和 android 调试工具的使用,知道了 appium 的存在(当时 appium 刚出来,还是挺热门的),学会了用 python 写一些简单的监控脚本。正准备开始自己弄一些脚本来让手工测试不那么枯燥的时候,公司需要开发一个测试第三方配件的测试工具,刚好用的是 python,leader 和我也比较熟,然后很幸运地就加入了。现在基本完成了工具的开发,正在写对应这个工具用例作为演示。
过程中也有人建议我转做开发,因为我有一定的编程经验(以前在学校搞过 J2EE 和 web 的一些东西),但我还是更想做测试,一方面做开发做久了也会很枯燥(开发也有重复性的工作,也有不少 copy/paste),会让我失去对计算机的兴趣,另一方面如同《Google 软件测试之道》里面 Chrome 测试工程经理 Joel Hynoski 所说,“测试是开发过程里面工程师能涉及的最远的地方”。我喜欢对所有事情都一探究竟,直到我完全理解,测试正好可以做到。
后面还会继续专注自动化测试,当然作为基础的开发也会继续学习。
根据 log 的描述,无法创建新 session 的原因是旧 session 没有被关闭。
个人建议:
@lihuazhang github 账号:chenhengjie123
@doctorq 有兴趣,求加入,学习 appium 同时改进它。
希望留下,虽然主要都是潜水,但是视野比以前开阔了很多。
一般公司隔一段时间会组织一些活动的吧,多参加这些活动就有一定锻炼效果了。
最好还是有一项运动方面的爱好,坚持每周至少参加一次,那么身体相对就好一些。