目录
?1.IAppForeground前台监听接口
?2.IPlugin?接口,功能插件需要实现的接口
?3.Plugin 抽象插件实现
?4.PluginListener插件状态监听
?5.DefaultPluginListener插件状态监听默认实现
?6.Issue问题,可以细化todo
?7.IssuePublisher问题发布者,发布给OnIssueDetectListener
?8.FilePublisher用于一天之内只上报一次问题
?9.MatrixHandlerThread 开辟了一个单独线程处理,getDefaultHandler,getNewHandlerThread
?10.AppActiveMatrixDelegate 监听是否前台,获取场景,这里可以设置fragment名字todo,获取topactivity
?11.Matrix,Builder用于创建,单例模式
?1.IAppForeground前台监听接口
public interface IAppForeground {
//是否是前台
void onForeground(boolean isForeground);
}
?2.IPlugin?接口,功能插件需要实现的接口
//IPlugin接口,功能插件需要实现的接口
public interface IPlugin {
Application getApplication();
void init(Application application, PluginListener pluginListener);
void start();
void stop();
void destroy();
String getTag();
void onForeground(boolean isForeground);
}
?3.Plugin 抽象插件实现
//Plugin 抽象插件实现
public abstract class Plugin implements IPlugin, IssuePublisher.OnIssueDetectListener, IAppForeground {
private static final String TAG = "Matrix.Plugin";
//状态
public static final int PLUGIN_CREATE = 0x00;
public static final int PLUGIN_INITED = 0x01;
public static final int PLUGIN_STARTED = 0x02;
public static final int PLUGIN_STOPPED = 0x04;
public static final int PLUGIN_DESTROYED = 0x08;
//监听器
private PluginListener pluginListener;
//Application
private Application application;
//isSupported默认是true
private boolean isSupported = true;
//最初是PLUGIN_CREATE
private int status = PLUGIN_CREATE;
@Override
public void init(Application app, PluginListener listener) {
if (application != null || pluginListener != null) {
throw new RuntimeException("plugin duplicate init, application or plugin listener is not null");
}
status = PLUGIN_INITED;
this.application = app;
this.pluginListener = listener;
AppActiveMatrixDelegate.INSTANCE.addListener(this);//用于监听是否是前台会调用onForeground
}
//上报问题
@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);
}
@Override
public Application getApplication() {
return application;
}
@Override
public void start() {
if (isPluginDestroyed()) {
throw new RuntimeException("plugin start, but plugin has been already destroyed");
}
if (isPluginStarted()) {
throw new RuntimeException("plugin start, but plugin has been already started");
}
status = PLUGIN_STARTED;
if (pluginListener == null) {
throw new RuntimeException("plugin start, plugin listener is null");
}
pluginListener.onStart(this);
}
@Override
public void stop() {
if (isPluginDestroyed()) {
throw new RuntimeException("plugin stop, but plugin has been already destroyed");
}
if (!isPluginStarted()) {
throw new RuntimeException("plugin stop, but plugin is never started");
}
status = PLUGIN_STOPPED;
if (pluginListener == null) {
throw new RuntimeException("plugin stop, plugin listener is null");
}
pluginListener.onStop(this);
}
@Override
public void destroy() {
// destroy前先stop,stop first
if (isPluginStarted()) {
stop();
}
if (isPluginDestroyed()) {
throw new RuntimeException("plugin destroy, but plugin has been already destroyed");
}
status = PLUGIN_DESTROYED;
if (pluginListener == null) {
throw new RuntimeException("plugin destroy, plugin listener is null");
}
pluginListener.onDestroy(this);
}
@Override
public String getTag() {
return getClass().getName();
}
//是否前台监听
@Override
public void onForeground(boolean isForeground) {
}
//是否前台获取
public boolean isForeground() {
return AppActiveMatrixDelegate.INSTANCE.isAppForeground();
}
public int getStatus() {
return status;
}
public boolean isPluginStarted() {
return (status == PLUGIN_STARTED);
}
public boolean isPluginStopped() {
return (status == PLUGIN_STOPPED);
}
public boolean isPluginDestroyed() {
return (status == PLUGIN_DESTROYED);
}
public boolean isSupported() {
return isSupported;
}
public void unSupportPlugin() {
isSupported = false;
}
public JSONObject getJsonInfo() {
return new JSONObject();
}
}
?4.PluginListener插件状态监听
//PluginListener插件状态监听
public interface PluginListener {
void onInit(Plugin plugin);
void onStart(Plugin plugin);
void onStop(Plugin plugin);
void onDestroy(Plugin plugin);
void onReportIssue(Issue issue);
}
?5.DefaultPluginListener插件状态监听默认实现
public class DefaultPluginListener implements PluginListener {
private static final String TAG = "Matrix.DefaultPluginListener";
private final Context context;
public DefaultPluginListener(Context context) {
this.context = context;
}
@Override
public void onInit(Plugin plugin) {
MatrixLog.i(TAG, "%s plugin is inited", plugin.getTag());
}
@Override
public void onStart(Plugin plugin) {
MatrixLog.i(TAG, "%s plugin is started", plugin.getTag());
}
@Override
public void onStop(Plugin plugin) {
MatrixLog.i(TAG, "%s plugin is stopped", plugin.getTag());
}
@Override
public void onDestroy(Plugin plugin) {
MatrixLog.i(TAG, "%s plugin is destroyed", plugin.getTag());
}
@Override
public void onReportIssue(Issue issue) {
MatrixLog.i(TAG, "report issue content: %s", issue == null ? "" : issue);
}
}
?6.Issue问题,可以细化todo
//ok 问题,可以细化todo
public class Issue {
private int type;
private String tag;
private String key;
private JSONObject content;
private Plugin plugin;
public static final String ISSUE_REPORT_TYPE = "type";
public static final String ISSUE_REPORT_TAG = "tag";
public static final String ISSUE_REPORT_PROCESS = "process";
public static final String ISSUE_REPORT_TIME = "time";
public Issue() {
}
public Issue(int type) {
this.type = type;
}
public Issue(JSONObject content) {
this.content = content;
}
public JSONObject getContent() {
return content;
}
public void setContent(JSONObject content) {
this.content = content;
}
@Override
public String toString() {
String strContent = "";
if (null != content) strContent = content.toString();
return String.format("tag[%s]type[%d];key[%s];content[%s]", tag, type, key, strContent);
}
public void setKey(String key) {
this.key = key;
}
public void setTag(String tag) {
this.tag = tag;
}
public int getType() {
return type;
}
public String getKey() {
return key;
}
public String getTag() {
return tag;
}
public void setType(int type) {
this.type = type;
}
public Plugin getPlugin() {
return plugin;
}
public void setPlugin(Plugin plugin) {
this.plugin = plugin;
}
}
?7.IssuePublisher问题发布者,发布给OnIssueDetectListener
//IssuePublisher问题发布者,发布给OnIssueDetectListener
public class IssuePublisher {
private final OnIssueDetectListener mIssueListener;
//用于标记这个问题是否已经发布了
private final HashSet<String> mPublishedMap;
public interface OnIssueDetectListener {
void onDetectIssue(Issue issue);
}
public IssuePublisher(OnIssueDetectListener issueDetectListener) {
mPublishedMap = new HashSet<>();
this.mIssueListener = issueDetectListener;
}
protected void publishIssue(Issue issue) {
if (mIssueListener == null) {
throw new RuntimeException("publish issue, but issue listener is null");
}
if (issue != null) {
mIssueListener.onDetectIssue(issue);
}
}
protected boolean isPublished(String key) {
if (key == null) {
return false;
}
return mPublishedMap.contains(key);
}
protected void markPublished(String key) {
if (key == null) {
return;
}
mPublishedMap.add(key);
}
protected void unMarkPublished(String key) {
if (key == null) {
return;
}
mPublishedMap.remove(key);
}
}
?8.FilePublisher用于一天之内只上报一次问题
public class FilePublisher extends IssuePublisher {
private static final String TAG = "Matrix.FilePublisher";
private final long mExpiredTime;//过期日期一天
private final SharedPreferences.Editor mEditor;
private final HashMap<String, Long> mPublishedMap;//activity名字和发生泄漏的时间
private final Context mContext;
public FilePublisher(Context context, long expire, String tag, OnIssueDetectListener issueDetectListener) {
super(issueDetectListener);
this.mContext = context;
mExpiredTime = expire;//1天过期日期
final String spName = "Matrix_" + tag + MatrixUtil.getProcessName(context);
SharedPreferences sharedPreferences = context.getSharedPreferences(spName, Context.MODE_PRIVATE);
mPublishedMap = new HashMap<>();//activity名字和发生泄漏的时间
long current = System.currentTimeMillis();
mEditor = sharedPreferences.edit();
HashSet<String> spKeys = null;
if (null != sharedPreferences.getAll()) {
spKeys = new HashSet<>(sharedPreferences.getAll().keySet());
}
if (null != spKeys) {
for (String key : spKeys) {
try {
long start = sharedPreferences.getLong(key, 0);
long costTime = current - start;
if (start <= 0 || costTime > mExpiredTime) {
mEditor.remove(key);//超时则删除
} else {
mPublishedMap.put(key, start);//没有的话,添加到map里
}
} catch (ClassCastException e) {
MatrixLog.printErrStackTrace(TAG, e, "might be polluted - sp: %s, key: %s, value : %s", spName, key, sharedPreferences.getAll().get(key));
}
}
}
if (null != mEditor) {
mEditor.apply();
}
}
public void markPublished(String key, boolean persist) {
if (key == null) {
return;
}
if (mPublishedMap.containsKey(key)) {//如果含有则返回
return;
}
final long now = System.currentTimeMillis();
mPublishedMap.put(key, now);
//如果保存文件里则保存到SharedPreferences里
if (persist) {
SharedPreferences.Editor e = mEditor.putLong(key, now);
if (null != e) {
e.apply();
}
}
}
@Override
public void markPublished(String key) {
markPublished(key, true);
}
@Override
public void unMarkPublished(String key) {
if (key == null) {
return;
}
if (!mPublishedMap.containsKey(key)) {
return;
}
mPublishedMap.remove(key);
SharedPreferences.Editor e = mEditor.remove(key);
if (null != e) {
e.apply();
}
}
@Override
public boolean isPublished(String key) {
if (!mPublishedMap.containsKey(key)) {
return false;
}
long start = mPublishedMap.get(key);
if (start <= 0 || (System.currentTimeMillis() - start) > mExpiredTime) {
SharedPreferences.Editor e = mEditor.remove(key);
if (null != e) {
e.apply();
}
mPublishedMap.remove(key);
return false;
}
return true;
}
public Context getContext() {
return mContext;
}
}
?9.MatrixHandlerThread 开辟了一个单独线程处理,getDefaultHandler,getNewHandlerThread
//MatrixHandlerThread 开辟了一个单独线程处理,getDefaultHandler,getNewHandlerThread
public class MatrixHandlerThread {
private static final String TAG = "Matrix.HandlerThread";
public static final String MATRIX_THREAD_NAME = "default_matrix_thread";
/**
* unite defaultHandlerThread for lightweight work,
* if you have heavy work checking, you can create a new thread
*/
private static volatile HandlerThread defaultHandlerThread;//开辟一个单独线程这个线程支持Handler,Looper.prepare();Looper.loop();
private static volatile Handler defaultHandler;//单独线程的Handler
private static volatile Handler defaultMainHandler = new Handler(Looper.getMainLooper());//main线程的
private static HashSet<HandlerThread> handlerThreads = new HashSet<>();
public static boolean isDebug = false;
public static Handler getDefaultMainHandler() {
return defaultMainHandler;
}
//获取默认的HandlerThread
public static HandlerThread getDefaultHandlerThread() {
synchronized (MatrixHandlerThread.class) {
if (null == defaultHandlerThread) {
defaultHandlerThread = new HandlerThread(MATRIX_THREAD_NAME);
defaultHandlerThread.start();
defaultHandler = new Handler(defaultHandlerThread.getLooper());
defaultHandlerThread.getLooper().setMessageLogging(isDebug ? new LooperPrinter() : null);
MatrixLog.w(TAG, "create default handler thread, we should use these thread normal, isDebug:%s", isDebug);
}
return defaultHandlerThread;
}
}
public static Handler getDefaultHandler() {
if (defaultHandler == null) {
getDefaultHandlerThread();
}
return defaultHandler;
}
public static HandlerThread getNewHandlerThread(String name, int priority) {
for (Iterator<HandlerThread> i = handlerThreads.iterator(); i.hasNext(); ) {
HandlerThread element = i.next();
if (!element.isAlive()) {
i.remove();
MatrixLog.w(TAG, "warning: remove dead handler thread with name %s", name);
}
}
HandlerThread handlerThread = new HandlerThread(name);
handlerThread.setPriority(priority);
handlerThread.start();
handlerThreads.add(handlerThread);
MatrixLog.w(TAG, "warning: create new handler thread with name %s, alive thread size:%d", name, handlerThreads.size());
return handlerThread;
}
?10.AppActiveMatrixDelegate 监听是否前台,获取场景,这里可以设置fragment名字todo,获取topactivity
//AppActiveMatrixDelegate 监听是否前台,获取场景,这里可以设置fragment名字todo,获取topactivity
public enum AppActiveMatrixDelegate {
INSTANCE;
private static final String TAG = "Matrix.AppActiveDelegate";
private final Set<IAppForeground> listeners = new HashSet();
private boolean isAppForeground = false;
private String visibleScene = "default";
private Controller controller = new Controller();
private boolean isInit = false;
private String currentFragmentName;//todo
private Handler handler;
//step 1 init,注册了controller
public void init(Application application) {
if (isInit) {
MatrixLog.e(TAG, "has inited!");
return;
}
this.isInit = true;
if (null != MatrixHandlerThread.getDefaultHandlerThread()) {
this.handler = new Handler(MatrixHandlerThread.getDefaultHandlerThread().getLooper());
}
application.registerComponentCallbacks(controller);
application.registerActivityLifecycleCallbacks(controller);
}
public String getCurrentFragmentName() {
return currentFragmentName;
}
/**
* must set after {@link Activity#onStart()}
*
* @param fragmentName
*/
public void setCurrentFragmentName(String fragmentName) {
MatrixLog.i(TAG, "[setCurrentFragmentName] fragmentName:%s", fragmentName);
this.currentFragmentName = fragmentName;
updateScene(fragmentName);
}
public String getVisibleScene() {
return visibleScene;
}
//step 3
private void onDispatchForeground(String visibleScene) {
if (isAppForeground || !isInit) {
return;
}
MatrixLog.i(TAG, "onForeground... visibleScene[%s]", visibleScene);
handler.post(new Runnable() {
@Override
public void run() {
isAppForeground = true;
synchronized (listeners) {
for (IAppForeground listener : listeners) {
listener.onForeground(true);
}
}
}
});
}
//step 4
private void onDispatchBackground(String visibleScene) {
if (!isAppForeground || !isInit) {
return;
}
MatrixLog.i(TAG, "onBackground... visibleScene[%s]", visibleScene);
handler.post(new Runnable() {
@Override
public void run() {
isAppForeground = false;
synchronized (listeners) {
for (IAppForeground listener : listeners) {
listener.onForeground(false);
}
}
}
});
}
public boolean isAppForeground() {
return isAppForeground;
}
public void addListener(IAppForeground listener) {
synchronized (listeners) {
listeners.add(listener);
}
}
public void removeListener(IAppForeground listener) {
synchronized (listeners) {
listeners.remove(listener);
}
}
//step 2
private final class Controller implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {
@Override
public void onActivityStarted(Activity activity) {
updateScene(activity);
onDispatchForeground(getVisibleScene());
}
@Override
public void onActivityStopped(Activity activity) {
if (getTopActivityName() == null) {
onDispatchBackground(getVisibleScene());
}
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
}
@Override
public void onLowMemory() {
}
@Override
public void onTrimMemory(int level) {
MatrixLog.i(TAG, "[onTrimMemory] level:%s", level);
if (level == TRIM_MEMORY_UI_HIDDEN && isAppForeground) { // fallback
onDispatchBackground(visibleScene);
}
}
}
private void updateScene(Activity activity) {
visibleScene = activity.getClass().getName();
}
private void updateScene(String currentFragmentName) {
StringBuilder ss = new StringBuilder();
ss.append(TextUtils.isEmpty(currentFragmentName) ? "?" : currentFragmentName);
visibleScene = ss.toString();
}
//获取顶部activity名字
public static String getTopActivityName() {
long start = System.currentTimeMillis();
try {
Class activityThreadClass = Class.forName("android.app.ActivityThread");
Object activityThread = activityThreadClass.getMethod("currentActivityThread").invoke(null);
Field activitiesField = activityThreadClass.getDeclaredField("mActivities");
activitiesField.setAccessible(true);
Map<Object, Object> activities;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
activities = (HashMap<Object, Object>) activitiesField.get(activityThread);
} else {
activities = (ArrayMap<Object, Object>) activitiesField.get(activityThread);
}
if (activities.size() < 1) {
return null;
}
for (Object activityRecord : activities.values()) {
Class activityRecordClass = activityRecord.getClass();
Field pausedField = activityRecordClass.getDeclaredField("paused");
pausedField.setAccessible(true);
if (!pausedField.getBoolean(activityRecord)) {
Field activityField = activityRecordClass.getDeclaredField("activity");
activityField.setAccessible(true);
Activity activity = (Activity) activityField.get(activityRecord);
return activity.getClass().getName();
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
long cost = System.currentTimeMillis() - start;
MatrixLog.d(TAG, "[getTopActivityName] Cost:%s", cost);
}
return null;
}
}
?11.Matrix,Builder用于创建,单例模式
//Matrix,Builder用于创建,单例模式
public class Matrix {
private static final String TAG = "Matrix.Matrix";
private static volatile Matrix sInstance;
private final HashSet<Plugin> plugins;
private final Application application;
private final PluginListener pluginListener;
private Matrix(Application app, PluginListener listener, HashSet<Plugin> plugins) {
this.application = app;
this.pluginListener = listener;
this.plugins = plugins;
AppActiveMatrixDelegate.INSTANCE.init(application);
for (Plugin plugin : plugins) {
plugin.init(application, pluginListener);
pluginListener.onInit(plugin);
}
}
public static void setLogIml(MatrixLog.MatrixLogImp imp) {
MatrixLog.setMatrixLogImp(imp);
}
public static boolean isInstalled() {
return sInstance != null;
}
//测试里用了
public static Matrix init(Matrix matrix) {
if (matrix == null) {
throw new RuntimeException("Matrix init, Matrix should not be null.");
}
synchronized (Matrix.class) {
if (sInstance == null) {
sInstance = matrix;
} else {
MatrixLog.e(TAG, "Matrix instance is already set. this invoking will be ignored");
}
}
return sInstance;
}
//获取实例
public static Matrix with() {
if (sInstance == null) {
throw new RuntimeException("you must init Matrix sdk first");
}
return sInstance;
}
public void startAllPlugins() {
for (Plugin plugin : plugins) {
plugin.start();
}
}
public void stopAllPlugins() {
for (Plugin plugin : plugins) {
plugin.stop();
}
}
public void destroyAllPlugins() {
for (Plugin plugin : plugins) {
plugin.destroy();
}
}
public Application getApplication() {
return application;
}
public HashSet<Plugin> getPlugins() {
return plugins;
}
public Plugin getPluginByTag(String tag) {
for (Plugin plugin : plugins) {
if (plugin.getTag().equals(tag)) {
return plugin;
}
}
return null;
}
public <T extends Plugin> T getPluginByClass(Class<T> pluginClass) {
String className = pluginClass.getName();
for (Plugin plugin : plugins) {
if (plugin.getClass().getName().equals(className)) {
return (T) plugin;
}
}
return null;
}
//创建Matrix的Builder
public static class Builder {
private final Application application;
private PluginListener pluginListener;
private HashSet<Plugin> plugins = new HashSet<>();
public Builder(Application app) {
if (app == null) {
throw new RuntimeException("matrix init, application is null");
}
this.application = app;
}
public Builder plugin(Plugin plugin) {
String tag = plugin.getTag();
for (Plugin exist : plugins) {
if (tag.equals(exist.getTag())) {
throw new RuntimeException(String.format("plugin with tag %s is already exist", tag));
}
}
plugins.add(plugin);
return this;
}
public Builder pluginListener(PluginListener pluginListener) {
this.pluginListener = pluginListener;
return this;
}
public Matrix build() {
if (pluginListener == null) {
pluginListener = new DefaultPluginListener(application);
}
return new Matrix(application, pluginListener, plugins);
}
}
}
|