版本
v0.6.5
溫馨提示
配合 推薦 Matrix 源碼完整注釋
可能會有更好的效果
概述
本篇文章是 騰訊開源的 APM 框架 Matrix 系列文章的第二篇,將對 matrix-android-lib
這個模塊的代碼進行閱讀。這個模塊主要是對Matrix 插件架構進行構建。上一篇為Matrix 源碼閱讀 - gradle插件
先看一下類圖及類功能的簡介。
Matrix整體架構.jpg
- Matrix:Matrix整個框架運行期的入口。也控制著插件的生命周期。所有插件都需要注冊到Matrix這個類中進行統一管理
- AppActiveMatrixDelegate:相當于Application的代理,本身可以感知Activity生命周期,和 APP 進入前臺還是 退出到后臺 ,感知到以后 會通知給
IAppForeground
- IPlugin:定義了所有 Plugin的生命周期及通用方法
- IssuePublisher.OnIssueDetectListener:只有一個
onDetectIssue
方法,當需要上報問題時會被調用 - IAppForeground: 只有一個方法就是
onForeground
會被AppActiveMatrixDelegate
調用,可以感知 APP 進入前臺還是 退出到后臺 - Plugin: 實現了
IPlugin
,ssuePublisher.OnIssueDetectListener
和IAppForeground
。是所有插件的父類,本身兼具插件的 生命周期,感知 問題和 APP狀態切換的功能。具體實現有TracePlugin
,IOCanaryPlugin
,ResourcePlugin
,SQLiteLintPlugin
后面我們會挨個分析。
下面我們就從 Matrix這個入口類開始看。
1. Matrix
我們使用Matrix一般會這樣初始化
Matrix.Builder builder = new Matrix.Builder(this);
builder.plugin(new TracePlugin());
builder.plugin(new IOCanaryPlugin());
.....
//詳見【1.1】
Matrix matrix=builder.build();
//詳見【3.1】
matrix.startAllPlugins();
1.1 Matrix構造方法
看到builder 就知道是使用建造者模式來創建Matrix對象,所以我們二話不說直接看Matrix的構造方法
private Matrix(Application app, PluginListener listener, HashSet<Plugin> plugins) {
//保存builder傳入的參數
this.application = app;
this.pluginListener = listener;
this.plugins = plugins;
//初始化Application的代理對象 詳見【1.2】
AppActiveMatrixDelegate.INSTANCE.init(application);
for (Plugin plugin : plugins) {
//調用plugin的init方法 詳見【2.1】
plugin.init(application, pluginListener);
//回調plugin onInit生命周期
pluginListener.onInit(plugin);
}
}
可以看到Matrix的構造方法中,做了三件事
- 首先是將builder中傳入的參數保存到自己的成員變量中,其中最重要的就是HashSet中存儲的各個
Plugin
. - 初始化
AppActiveMatrixDelegate
這個Application的代理對象 - 循環調用所有
Plugin
的init方法
1.2 AppActiveMatrixDelegate.init()
值得說一下的是 AppActiveMatrixDelegate
這個類是個 枚舉單例,不了解枚舉單例好處及和其他幾種單例方式區別的同學,可以自行百度,谷歌一下,網上文章一大把。
我們繼續看AppActiveMatrixDelegate.init()
//詳見【1.3】
Controller controller = new Controller();
public void init(Application application) {
//保證只初始化一次
if (isInit) {
return;
}
this.isInit = true;
//獲取 子線程 handler
this.handler = new Handler(MatrixHandlerThread.getDefaultHandlerThread().getLooper());
//監聽 onConfigurationChanged 和 onLowMemory
application.registerComponentCallbacks(controller);
//監聽activity生命周期
application.registerActivityLifecycleCallbacks(controller);
}
可以看到在init()
方法中, application注冊了ActivityLifecycleCallbacks
和ComponentCallbacks2
這兩個監聽,并且這兩個監聽指向了同一個對象Controller
.有了這兩個監聽ActivityLifecycleCallbacks
就具有了 感知Activity生命周期和APP活動的能力。
1.3 Controller
private final class Controller implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {
@Override
public void onActivityStarted(Activity activity) {
//更新當前頁面名稱 詳見【1.4】
updateScene(activity);
//廣播 APP切換到前臺的 事件 詳見【1.5】
onDispatchForeground(getVisibleScene());
}
@Override
public void onActivityStopped(Activity activity) {
if (getTopActivityName() == null) {
//廣播 APP切換到后臺的 事件 詳見【1.6】
onDispatchBackground(getVisibleScene());
}
}
.....
@Override
public void onTrimMemory(int level) {
MatrixLog.i(TAG, "[onTrimMemory] level:%s", level);
if (level == TRIM_MEMORY_UI_HIDDEN && isAppForeground) { // fallback
//廣播 APP切換到后臺的 事件
onDispatchBackground(visibleScene);
}
}
}
可以看到Controller
是真正感知APP狀態的類。
1.4 Controller .updateScene()
private void updateScene(Activity activity) {
//記錄當前activity的名稱
visibleScene = activity.getClass().getName();
}
1.5 Controller .onDispatchForeground()
private void onDispatchForeground(String visibleScene) {
//如果APP已經是可見的,就不做任何操作
if (isAppForeground || !isInit) {
return;
}
handler.post(new Runnable() {
@Override
public void run() {
//修改APP狀態為可見
isAppForeground = true;
synchronized (listeners) {
for (IAppForeground listener : listeners) {
//通知給各個監聽者
listener.onForeground(true);
}
}
}
});
}
1.6 Controller .onDispatchBackground()
private void onDispatchBackground(String visibleScene) {
//如果APP已經是不可見的,就不做任何操作
if (!isAppForeground || !isInit) {
return;
}
handler.post(new Runnable() {
@Override
public void run() {
isAppForeground = false;
synchronized (listeners) {
for (IAppForeground listener : listeners) {
//通知給各個監聽者
listener.onForeground(false);
}
}
}
});
}
2.1Plugin.init()
Matrix
的構造方法中AppActiveMatrixDelegate
對象初始化完成后就調用了Plugin.init()
方法
@Override
public void init(Application app, PluginListener listener) {
....
//將plugin當前的狀態切換到 PLUGIN_INITED
status = PLUGIN_INITED;
this.application = app;
this.pluginListener = listener;
//將自己注冊到 AppActiveMatrixDelegate 中 詳見【2.2】
AppActiveMatrixDelegate.INSTANCE.addListener(this);
}
2.2 AppActiveMatrixDelegate.INSTANCE.addListener(this);
可以看到Plugin
在init的時候將自己注冊到了AppActiveMatrixDelegate
中,當APP前后臺狀態改變是 Plugin就能感知到
public void addListener(IAppForeground listener) {
synchronized (listeners) {
//添加監聽器
listeners.add(listener);
}
}
3.1 Matrix.startAllPlugins()
startAllPlugins
這個方法比較簡單就是啟動所有的插件,Matrix作為插件的管理者理還具有其他類似的方法如 stopAllPlugins
,destroyAllPlugins
//啟動所有插件
public void startAllPlugins() {
for (Plugin plugin : plugins) {
plugin.start();
}
}
Plugin.onDetectIssue()
//組織 問題的 Json數據 并調用 監聽的 onReportIssue 方法
@Override
public void onDetectIssue(Issue issue) {
if (issue.getTag() == null) {
// set default tag
issue.setTag(getTag());
}
issue.setPlugin(this);
JSONObject content = issue.getContent();
// add tag and type for default
try {
if (issue.getTag() != null) {
content.put(Issue.ISSUE_REPORT_TAG, issue.getTag());
}
if (issue.getType() != 0) {
content.put(Issue.ISSUE_REPORT_TYPE, issue.getType());
}
content.put(Issue.ISSUE_REPORT_PROCESS, MatrixUtil.getProcessName(application));
content.put(Issue.ISSUE_REPORT_TIME, System.currentTimeMillis());
} catch (JSONException e) {
MatrixLog.e(TAG, "json error", e);
}
//MatrixLog.e(TAG, "detect issue:%s", issue);
pluginListener.onReportIssue(issue);
}
Plugin
提供了簡單的統一的數據上報方法,并對上報數據封裝成統一格式的Json字符串。
總結:
-
Matrix
是整個框架的入口也是所有插件的管理者 - 所有的插件都需要繼承
Plugin
,Plugin
本身已經具備了 問題上報和感知APP前后臺狀態的能力。
系列文章
- 騰訊 Apm 框架 Matrix 源碼閱讀 - gradle插件
- 騰訊 Apm 框架 Matrix 源碼閱讀 - 架構解析
- 騰訊 Apm 框架 Matrix 源碼閱讀 - TracePlugin 架構解析
- 騰訊 Apm 框架 Matrix 源碼閱讀 - TracePlugin 之 FrameTracer
- 騰訊 Apm 框架 Matrix 源碼閱讀 - TracePlugin 之 StartupTracer
- 騰訊 Apm 框架 Matrix 源碼閱讀 - TracePlugin 之 AnrTracer
- 騰訊 Apm 框架 Matrix 源碼閱讀 - TracePlugin 之 上報字段含義