共计 5225 个字符,预计需要花费 14 分钟才能阅读完成。
本文次要形容了怎么样进步一个客户端开发排查和定位的效率,并且入手写了一个小工具的实际和思考,以及团队中其余合作者可能进步了定位问题效率,验证性能是否精确的效率。
作者 /马杰 中国大学 MOOC 团队
编辑 /刘振宇
一、前言
中国大学 MOOC 是由网易与高教社携手推出的在线教育平台,承接教育部国家精品凋谢课程工作,向公众提供中国出名高校的 MOOC 课程。目前,无论是课程数量、品质还是社会影响力,中国大学 MOOC 都已成为寰球当先的中文慕课平台。
在日常的 Android 开发中,咱们常常会遇到以下的一些问题:测试、经营、产品同学跑过来说这个页面出了问题,连忙看下。这时候客户端开发同学就须要连忙定位到具体的某个页面。
据察看,大部分的状况下对于一个突发页面的问题定位,或者业务方想让开发者确认这个页面的业务逻辑的时候,客户端开发者,往往须要破费比拟长的工夫去给业务方回答。如果近期业务可能还能记得,然而客户端的页面比拟多,想要疾速定位到具体业务页面,那么就须要花更多的工夫去找相干的页面。
所以本文的想法是怎么 疾速找到对应的页面 ,帮忙开发 疾速的进入业务代码,疾速的回复业务方提出的问题。
二、计划施行
在探讨计划的时候,咱们须要比照目前有哪些计划,比照之后再抉择一种更加无效的办法。
2.1 解决问题的罕用形式
在 Android 开发中解决上述提供的问题,罕用的有以下 3 种形式:
- 关上 Android studio,靠着源码记忆,文案记忆去搜寻;
- 应用 adb 命令来过滤以后的 activity;
// windows
adb shell dumpsys window windows | Select-String -Pattern 'mCurrentFocus|mFocusedApp|mLastOpeningApp|mObscuringWindow'
// Mac
adb shell dumpsys window windows | grep -E 'mCurrentFocus|mFocusedApp|mLastOpeningApp'
- 全局搜寻要害文案。
下面 3 种形式是可能解决问题,但从 工夫效率 上剖析,能够估算一下每一种形式大略须要多长时间:
第一种,依照集体教训,相熟我的项目代码的同学最快也要几十秒左右,慢的话 10 几分钟;
第二种,应用 adb 可能几秒就定位到页面,然而须要记住命令,或者提前设置命令快捷方式;
第三种,如果有很多雷同文案,须要多搜寻几遍,工夫也可能是 10 几秒到 1 分钟不等。
所有下面几种形式得出的工夫效率就是几秒到几分钟不等,而且根本都是须要代码或者 adb 的开发工具,依赖于开发环境。
既然须要花的工夫也不少,那么是不是应该做一个工具来晋升更快的定位速度,晋升定位效率呢?
2.2 更加高效的办法
其实思路很简略,就是写一个开发的 SDK,用来实时关注以后的页面信息。这个页面信息次要蕴含如下的信息:
- 以后 Activity 是哪个?
- 以后的 Fragment 是哪个?
- 以后页面的参数传递,如:intent 中的各种参数是什么?
效果图如下:
从下面信息就可能很快的定位到以后的页面;当一个页面的深度到十分深的时候,这样的小工具就特地好用;最快速度只有几秒 就能疾速定位到页面,效率晋升 快几十倍不止,而且可能当着测试和产品的面,可能把以后要害的参数给他看,如:xxxId、埋点信息等。
2.3 次要实现原理
下面的小工具,次要的工作是 取得以后的 Activity。取得以后 Activity 的形式次要有以下几种形式:
- 通过 RunningTaskInfo 的 topActivity,该办法在后续的一些版本曾经被禁用
- 手写代码治理 Activity,这个办法比拟粗犷,保护比拟麻烦;
- 通过反射 ActivityThread 取得 currentActivityThread 从 mActivities 中查问取得;
- 应用 AccessibilityService 这个辅助性能,这个办法取得的信息比拟少;
- 通过 ActivityLifecycleCallback 监听来取得。
通过比照,抉择应用 AccessibilityService 和ActivityLifecycleCallback 这 2 种形式去尝试。以下就简略的说下这 2 种办法的实现,并进行二者之间的比照以及最初做出的抉择。
2.3.1 ActivityLifecycleCallback 形式
private static Activity topActivity;
@Override
public void onActivityResumed(Activity activity) {topActivity = activity;}
是不是很简略?为了防止内存透露,能够在 onDestroy 的时候把 topActivity 设置成 null。这种形式 简略疾速,不须要申请权限。
2.3.2 AccessibilityService 形式
- 继承 AccessibilityService
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {Log.d(TAG, "onAccessibilityEvent");
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {if (event.getPackageName() != null && event.getClassName() != null) {
ComponentName componentName = new ComponentName(event.getPackageName().toString(),
event.getClassName().toString()
);
ActivityInfo activityInfo = tryGetActivity(componentName);
boolean isActivity = activityInfo != null;
if (isActivity) {Log.d(TAG, "CurentActivity" + componentName.flattenToShortString());
Log.d(TAG, "CurentActivity" + event.getPackageName().toString());
}
}
}
}
private ActivityInfo tryGetActivity(ComponentName componentName) {
try {return getPackageManager().getActivityInfo(componentName, 0);
} catch (PackageManager.NameNotFoundException e) {return null;}
}
- manifest 配置
<service
android:name=".WindowChangeDetectingService"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService"/>
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="@xml/accessibilityservice"/>
</service>
- 须要 res/xm/accessibilityservice.xml 文件
<?xml version="1.0" encoding="utf-8"?>
<!-- These options MUST be specified here in order for the events to be received on first
start in Android 4.1.1 -->
<accessibility-service
xmlns:tools="http://schemas.android.com/tools"
android:accessibilityEventTypes="typeWindowStateChanged"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagIncludeNotImportantViews"
android:canRetrieveWindowContent="true"
android:description="@string/accessibility_service_description"
xmlns:android="http://schemas.android.com/apk/res/android"
tools:ignore="UnusedAttribute"/>
2.3.3 2 种形式的比照
从 实现角度 比照,应用 ActivityLifecycleCallback 比 AccessibilityService 更加简略。然而 AccessibilityService 有个劣势就是能够不必集成到本人的 app 外面,能够独立运行,能够查看所有的以后页面是属于哪个 Activity,能够跨过程应用。应用 ActivityLifecycleCallback 必须要集成到本人的 app 中。
在 实际过程 中,其实咱们不只是想取得以后的 Activity,咱们还想晓得以后的 Activity 中有哪些以后的 fragment, 以后的 Activity 从上一个 Activity 中取得了哪些参数,以后的 fragment 中有哪些参数等细节信息,那么只能集成到 app 中去的时候才会比拟容易取得。所以最初抉择了应用 ActivityLifecycleCallback 的形式。
2.3.4 页面更具体的信息
个别页面上的信息开发,简略一点的就是一个 Activity 而后简略布局;简单一点的根本都是 Activity + (ViewPager)Adatper + fragment,有时候 fragment 外面还会有 ViewPager 装载着 fragment, 对于不相熟代码的人找对应的业务逻辑页面和代码,还是须要破费不少工夫的。所以页面信息 fragment 也很重要。
topActivity.getIntent().getExtras();// 取得 activity 的页面参数
topActivity.getSupportFragmentManager().getFragments(); // 取得 activity 一级中的 fragments
fragment.getChildFragmentManager().getFragments();// 对应 fragment 中的 fragments
fragment.getArguments() // 取得 fragment 的页面参数
三、提高效率举例
对于页面信息采集,在这里列举了几个应用场景,来证实效率失去了进步:
- 对于 客户端开发者,可能疾速的定位到以后出错的页面,特地是刚来的开发,或者不相熟这块业务的,或者业务页面深度比拟深的时候;
- 页面外围参数的确认。比方详情页面须要一些 id,这些具体参数就不须要客户端共事打断点的形式去获取,经营和测试本人能够去查看;
- 在 精品课和云课堂集成 的时候,可能让测试同学疾速的辨别哪个是精品课外面的页面,哪个是云课堂外面的页面,这样不便测试晓得以后页面是属于哪个业务端的;(这个场景是网易外部交融我的项目)
- 页面全链路参数传递验证场景。比方:首页点击须要传递转化率的参数始终传递到下单页面,平时都是开发本人验证,有这个工具后,产品也能在提测后,从测试包上本人查看验证。
四、页面信息其余想法
对于页面信息场景加强,以下几种页面信息形式,认为能够进行裁减的:
- 能够取得 RecyclerView 中的 adapter;(有很多布局逻辑,放到了 adapter 外面的 ViewHolder)
- webview 以后信息的监控;(前端共事调试)
- 网络看板的监控;(以后页面的网络申请信息)
- 不连贯电脑 Logcat 日志查看看板;(不必连贯电脑,取得 adb 信息)
- 参考线,界面元素地位,对应元素的色彩。(UI 走查的验证)
以上的几点,次要是依照本身 app 的状况去判断是否须要实现,判断哪些实现性价比比拟高。目前曾经实现的,根本都是集体认为 性价比是比拟高 的货色。
五、总结
当咱们遇见一个问题的时候,首先思考这个问题是不是本人比拟好受的点,而后察看其他人是否有相似的状况。这个问题罕用的解决方案什么?有没有工具办法去代替?如果没有,可不可以用比拟低的老本去制作一个工具?最初来晋升本人的效率,这个工具如果可能帮忙其他人,那么能效就更加好了。
-END-