騰訊 Apm 框架 Matrix 源碼閱讀 - 架構解析

版本

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.OnIssueDetectListenerIAppForeground。是所有插件的父類,本身兼具插件的 生命周期,感知 問題和 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的構造方法中,做了三件事

  1. 首先是將builder中傳入的參數保存到自己的成員變量中,其中最重要的就是HashSet中存儲的各個Plugin.
  2. 初始化 AppActiveMatrixDelegate 這個Application的代理對象
  3. 循環調用所有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注冊了ActivityLifecycleCallbacksComponentCallbacks2這兩個監聽,并且這兩個監聽指向了同一個對象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字符串。

總結:

  1. Matrix是整個框架的入口也是所有插件的管理者
  2. 所有的插件都需要繼承PluginPlugin本身已經具備了 問題上報和感知APP前后臺狀態的能力。

系列文章

參考資料

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容