业务中有些逻辑需要根据Activity或者Application的生命周期来做对应的操作,我们知道Application提供了有关Activity的生命周期回调,可以在里面进行回调处理。
但是对于组件化开发,有没有比较方便的方式监控Activity或者Application的生命周期来做对应的操作呢?
答案就是APT+ASM埋点处理各个模块跟主工程的逻辑关系。
首先使用注解标注需要接受对应生命周期的实现类。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//注解类,只能用来对类进行注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface AppLifeCycle {
}
然后解析标记有注解的类。
import com.google.auto.service.AutoService;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.tools.JavaFileObject;
import static com.midea.base.core.lifecycle.apt.LifeCycleConfig.APP_LIFECYCLE_CLASS;
@AutoService(Processor.class)
@SupportedAnnotationTypes({APP_LIFECYCLE_CLASS})
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class AppLifeCycleProcessor extends AbstractProcessor {
private Elements mElementUtils;
private Map<String, AppLikeProxyClassCreator> mMap = new HashMap<>();
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
Logger.debug("");
Logger.debug("AppLifeCycleProcessor init");
mElementUtils = processingEnvironment.getElementUtils();
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(AppLifeCycle.class);
mMap.clear();
for (Element element : elements) {
// 如果该注解不是用在类上面,直接抛出异常,该注解用在方法、字段等上面,我们是不支持的
if (!element.getKind().isClass()) {
throw new RuntimeException("Annotation AppLifeCycle can only be used in class.");
}
// 强制转换为TypeElement,也就是类元素,可以获取使用该注解的类的相关信息
TypeElement typeElement = (TypeElement) element;
// 这里检查一下,使用了该注解的类,同时必须要实现IAppLike接口,否则会报错,因为我们要实现一个代理类
List<? extends TypeMirror> mirrorList = typeElement.getInterfaces();
TypeMirror typeMirror = typeElement.getSuperclass();
Logger.debug("element:" + element + " mirrorList:" + mirrorList + " typeMirror:" + typeMirror);
if (mirrorList.isEmpty() && !LifeCycleConfig.APP_LIKE_DEFAULT_CLASS.equals(typeMirror.toString())) {
throw new RuntimeException(typeElement.getQualifiedName() + " must implements interface " + LifeCycleConfig.APP_LIKE_INTERFACE + " or extend " + LifeCycleConfig.APP_LIKE_DEFAULT_CLASS);
}
boolean checkInterfaceFlag = false;
for (TypeMirror mirror : mirrorList) {
if (LifeCycleConfig.APP_LIKE_INTERFACE.equals(mirror.toString())) {
checkInterfaceFlag = true;
}
}
if (LifeCycleConfig.APP_LIKE_DEFAULT_CLASS.equals(typeMirror.toString())) {
checkInterfaceFlag = true;
}
if (!checkInterfaceFlag) {
throw new RuntimeException(typeElement.getQualifiedName() + " must implements interface " + LifeCycleConfig.APP_LIKE_INTERFACE + " or extend " + LifeCycleConfig.APP_LIKE_DEFAULT_CLASS);
}
// 该类的全限定类名
String fullClassName = typeElement.getQualifiedName().toString();
if (!mMap.containsKey(fullClassName)) {
// 创建代理类生成器
AppLikeProxyClassCreator creator = new AppLikeProxyClassCreator(mElementUtils, typeElement);
mMap.put(fullClassName, creator);
}
}
for (Map.Entry<String, AppLikeProxyClassCreator> entry : mMap.entrySet()) {
String className = entry.getKey();
AppLikeProxyClassCreator creator = entry.getValue();
Logger.debug("generate proxy class for " + className);
// 生成代理类,并写入到文件里,生成逻辑都在AppLikeProxyClassCreator里实现
try {
JavaFileObject jfo = processingEnv.getFiler().createSourceFile(creator.getProxyClassFullName());
Writer writer = jfo.openWriter();
writer.write(creator.generateJavaCode());
writer.flush();
writer.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return true;
}
}
生成代理类的工具。
package com.midea.base.core.lifecycle.apt;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
public class AppLikeProxyClassCreator {
private Elements mElementUtils;
private TypeElement mTypeElement;
private String mProxyClassSimpleName;
public AppLikeProxyClassCreator(Elements elements, TypeElement typeElement) {
mElementUtils = elements;
mTypeElement = typeElement;
//代理类的名称,用到了之前定义过的前缀、后缀
mProxyClassSimpleName = LifeCycleConfig.PROXY_CLASS_PREFIX
+ mTypeElement.getSimpleName().toString()
+ LifeCycleConfig.PROXY_CLASS_SUFFIX;
}
/**
* 获取要生成的代理类的完整类名
*
* @return
*/
public String getProxyClassFullName() {
String name = LifeCycleConfig.PROXY_CLASS_PACKAGE_NAME + "." + mProxyClassSimpleName;
return name;
}
/**
* 生成java代码,其实就是手动拼接,没有什么技术含量,比较繁琐,且容易出错
* 可以采用第三方框架javapoet来实现,看自己需求了
*/
public String generateJavaCode() {
StringBuilder sb = new StringBuilder();
//设置包名
sb.append("package ").append(LifeCycleConfig.PROXY_CLASS_PACKAGE_NAME).append(";\n\n");
//设置import部分
sb.append("import android.content.Context;\n\n");
sb.append("import com.midea.base.core.lifecycle.api.IAppLike;\n");
sb.append("import ").append(mTypeElement.getQualifiedName()).append(";\n\n");
sb.append("public class ").append(mProxyClassSimpleName)
.append(" implements ").append("IAppLike").append(" {\n\n");
//设置变量
sb.append(" private ").append(mTypeElement.getSimpleName().toString()).append(" mAppLike;\n\n");
//构造函数
sb.append(" public ").append(mProxyClassSimpleName).append("() {\n");
sb.append(" mAppLike = new ").append(mTypeElement.getSimpleName().toString()).append("();\n");
sb.append(" }\n\n");
//getPriority()方法
sb.append(" public int getPriority() {\n");
sb.append(" return mAppLike.getPriority();\n");
sb.append(" }\n\n");
//onCreate()方法
sb.append(" public void onCreate(Context context) {\n");
sb.append(" mAppLike.onCreate(context);\n");
sb.append(" }\n\n");
//onCreate()方法
sb.append(" public void onCreate(Context context, int timeType) {\n");
sb.append(" mAppLike.onCreate(context, timeType);\n");
sb.append(" }\n\n");
//onTerminate方法
sb.append(" public void onTerminate() {\n");
sb.append(" mAppLike.onTerminate();\n");
sb.append(" }\n\n");
//onEnterBackground方法
sb.append(" public void onEnterBackground() {\n");
sb.append(" mAppLike.onEnterBackground();\n");
sb.append(" }\n\n");
//onEnterForeground方法
sb.append(" public void onEnterForeground() {\n");
sb.append(" mAppLike.onEnterForeground();\n");
sb.append(" }\n\n");
//onEnterForeground方法
sb.append(" public void onLowMemory() {\n");
sb.append(" mAppLike.onLowMemory();\n");
sb.append(" }\n\n");
sb.append("}");
return sb.toString();
}
}
注解配置类。
class LifeCycleConfig {
/**
* 要生成的代理类的包名,该包名下不要有其他不相关的业务类
*/
static final String PROXY_CLASS_PACKAGE_NAME = "com.midea.base.core.lifecycle.apt.proxy";
/**
* 生成代理类统一的后缀
*/
static final String PROXY_CLASS_SUFFIX = "$$Proxy";
/**
* 生成代理类统一的前缀
*/
static final String PROXY_CLASS_PREFIX = "Midea$$";
/**
* IAppLike的package name
*/
static final String APP_LIKE_INTERFACE = "com.midea.base.core.lifecycle.api.IAppLike";
static final String APP_LIKE_DEFAULT_CLASS = "com.midea.base.core.lifecycle.api.DefaultAppLike";
static final String APP_LIFECYCLE_CLASS = "com.midea.base.core.lifecycle.annotation.AppLifeCycle";
}
经过APT处理将会生成对应的代理类。
import android.content.Context;
import com.midea.base.core.lifecycle.api.IAppLike;
import com.example.myapplication.MyAppLike;
public class Midea$$MyAppLike$$Proxy implements IAppLike {
private MyAppLike mAppLike;
public Midea$$MyAppLike$$Proxy() {
mAppLike = new MyAppLike();
}
public int getPriority() {
return mAppLike.getPriority();
}
public void onCreate(Context context) {
mAppLike.onCreate(context);
}
public void onCreate(Context context, int timeType) {
mAppLike.onCreate(context, timeType);
}
public void onTerminate() {
mAppLike.onTerminate();
}
public void onEnterBackground() {
mAppLike.onEnterBackground();
}
public void onEnterForeground() {
mAppLike.onEnterForeground();
}
public void onLowMemory() {
mAppLike.onLowMemory();
}
}
有了代理类之后,我们需要动态的再APP编译的时候插入生成的代理类的逻辑,进行Activity或者Application的生命周期监听。这里需要使用transform的方式进行。
import com.android.build.gradle.AppExtension
import org.gradle.api.Plugin
import org.gradle.api.Project
class LifeCyclePlugin implements Plugin<Project> {
@Override
void apply(Project project) {
def android = project.extensions.getByType(AppExtension)
android.registerTransform(new LifeCycleTransform(project))
}
}
import com.android.build.api.transform.*
import com.android.build.gradle.internal.pipeline.TransformManager
import org.apache.commons.codec.digest.DigestUtils
import org.apache.commons.io.FileUtils
import org.gradle.api.Project
class LifeCycleTransform extends Transform {
Project project
LifeCycleTransform(Project project) {
this.project = project
}
@Override
String getName() {
return "LifeCycleTransform"
}
@Override
Set<QualifiedContent.ContentType> getInputTypes() {
return TransformManager.CONTENT_CLASS
}
@Override
Set<? super QualifiedContent.Scope> getScopes() {
return TransformManager.SCOPE_FULL_PROJECT
}
@Override
boolean isIncremental() {
return true
}
@Override
void transform(Context context, Collection<TransformInput> inputs, Collection<TransformInput> referencedInputs,
TransformOutputProvider outputProvider, boolean isIncremental) throws IOException, TransformException, InterruptedException {
Logger.debug("")
Logger.debug("Transform: start...")
def appLikeProxyClassList = []
inputs.each { TransformInput input ->
input.directoryInputs.each { DirectoryInput directoryInput ->
if (directoryInput.file.isDirectory()) {
directoryInput.file.eachFileRecurse { File file ->
//形如 Midea$$****$$Proxy.class 的类,是我们要找的目标class
if (ScanUtil.isTargetProxyClass(file)) {
appLikeProxyClassList.add(file.name)
}
}
}
def dest = outputProvider.getContentLocation(directoryInput.name, directoryInput.contentTypes, directoryInput.scopes, Format.DIRECTORY)
FileUtils.copyDirectory(directoryInput.file, dest)
}
input.jarInputs.each { JarInput jarInput ->
// Logger.debug("jarInput = ${jarInput}")
def jarName = jarInput.name
def md5 = DigestUtils.md5Hex(jarInput.file.getAbsolutePath())
if (jarName.endsWith(".jar")) {
jarName = jarName.substring(0, jarName.length() - 4)
}
def dest = outputProvider.getContentLocation(jarName + md5, jarInput.contentTypes, jarInput.scopes, Format.JAR)
if (jarInput.file.getAbsolutePath().endsWith(".jar")) {
//处理jar包里的代码
File src = jarInput.file
if (ScanUtil.shouldProcessPreDexJar(src.absolutePath)) {
List<String> list = ScanUtil.scanJar(src, dest)
if (list != null) {
appLikeProxyClassList.addAll(list)
}
}
}
FileUtils.copyFile(jarInput.file, dest)
}
}
appLikeProxyClassList.forEach({ fileName ->
Logger.debug(" found file name:" + fileName)
})
Logger.debug(" 包含AppLifeCycleManager类的jar文件:" + ScanUtil.FILE_CONTAINS_INIT_CLASS.getAbsolutePath())
Logger.debug(" 开始自动注册")
new AppLikeCodeInjector(appLikeProxyClassList).execute()
Logger.debug("Transform: end...")
}
}
收集到所有代理类之后,将这些代理类都注入到管理者的初始化逻辑中。
package com.midea.base.core.lifecycle.plugin
import org.apache.commons.io.IOUtils
import org.objectweb.asm.*
import org.objectweb.asm.commons.AdviceAdapter
import java.util.jar.JarEntry
import java.util.jar.JarFile
import java.util.jar.JarOutputStream
import java.util.zip.ZipEntry
class AppLikeCodeInjector {
List<String> proxyAppLikeClassList
AppLikeCodeInjector(List<String> list) {
proxyAppLikeClassList = list
}
void execute() {
Logger.debug(" 开始执行ASM方法======>>>>>>>>")
File srcFile = ScanUtil.FILE_CONTAINS_INIT_CLASS
// 创建一个临时jar文件,要修改注入的字节码会先写入该文件里
def optJar = new File(srcFile.getParent(), srcFile.name + ".opt")
if (optJar.exists())
optJar.delete()
def file = new JarFile(srcFile)
Enumeration<JarEntry> enumeration = file.entries()
JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(optJar))
while (enumeration.hasMoreElements()) {
JarEntry jarEntry = enumeration.nextElement()
String entryName = jarEntry.getName()
ZipEntry zipEntry = new ZipEntry(entryName)
InputStream inputStream = file.getInputStream(jarEntry)
jarOutputStream.putNextEntry(zipEntry)
// 找到需要插入代码的class,通过ASM动态注入字节码
if (ScanUtil.REGISTER_CLASS_FILE_NAME == entryName) {
Logger.debug " insert register code to class >> " + entryName
ClassReader classReader = new ClassReader(inputStream)
// 构建一个ClassWriter对象,并设置让系统自动计算栈和本地变量大小
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS)
ClassVisitor classVisitor = new AppLikeClassVisitor(classWriter)
// 开始扫描class文件
classReader.accept(classVisitor, ClassReader.EXPAND_FRAMES)
byte[] bytes = classWriter.toByteArray()
// 将注入过字节码的class,写入临时jar文件里
jarOutputStream.write(bytes)
} else {
// 不需要修改的class,原样写入临时jar文件里
jarOutputStream.write(IOUtils.toByteArray(inputStream))
}
inputStream.close()
jarOutputStream.closeEntry()
}
jarOutputStream.close()
file.close()
// 删除原来的jar文件
if (srcFile.exists()) {
srcFile.delete()
}
// 重新命名临时jar文件,新的jar包里已经包含了我们注入的字节码了
optJar.renameTo(srcFile)
}
class AppLikeClassVisitor extends ClassVisitor {
AppLikeClassVisitor(ClassVisitor classVisitor) {
super(Opcodes.ASM5, classVisitor)
}
@Override
MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exception) {
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exception)
// 找到 AppLifeCycleManager里的loadAppLike()方法
if ("loadAppLike" == name) {
mv = new LoadAppLikeMethodAdapter(mv, access, name, desc)
}
return mv
}
}
class LoadAppLikeMethodAdapter extends AdviceAdapter {
LoadAppLikeMethodAdapter(MethodVisitor mv, int access, String name, String desc) {
super(Opcodes.ASM5, mv, access, name, desc)
}
@Override
protected void onMethodEnter() {
super.onMethodEnter()
// Logger.debug "-------onMethodEnter------"
proxyAppLikeClassList.forEach({ proxyClassName ->
Logger.debug " 开始注入代码:${proxyClassName}"
def fullName = ScanUtil.PROXY_CLASS_PACKAGE_NAME.replace("/", ".") + "." + proxyClassName.substring(0, proxyClassName.length() - 6)
// Logger.debug "full classname = ${fullName}"
mv.visitLdcInsn(fullName)
mv.visitMethodInsn(INVOKESTATIC, "com/midea/base/core/lifecycle/api/AppLifeCycleManager", "registerAppLike", "(Ljava/lang/String;)V", false)
})
}
@Override
protected void onMethodExit(int opcode) {
super.onMethodExit(opcode)
// Logger.debug "-------onMethodExit------"
}
}
}
对应的工具类。
import java.util.jar.JarEntry
import java.util.jar.JarFile
class ScanUtil {
static final PROXY_CLASS_PREFIX = "Midea$$"
static final PROXY_CLASS_SUFFIX = "$$Proxy.class"
static final PROXY_CLASS_PACKAGE_NAME = "com/midea/base/core/lifecycle/apt/proxy"
static final REGISTER_CLASS_FILE_NAME = "com/midea/base/core/lifecycle/api/AppLifeCycleManager.class"
//包含生命周期管理初始化类的文件,及包含 com.midea.base.core.lifecycle.api.AppLifeCycleManager 类的class文件或者jar文件
static File FILE_CONTAINS_INIT_CLASS
/**
* 判断该class是否是我们的目标类
*/
static boolean isTargetProxyClass(File file) {
if (file.name.endsWith(PROXY_CLASS_SUFFIX) && file.name.startsWith(PROXY_CLASS_PREFIX)) {
return true
}
return false
}
/**
* 扫描jar包里的所有class文件:
* 1.通过包名识别所有需要注入的类名
* 2.找到注入管理类所在的jar包,后面我们会在该jar包里进行代码注入
*/
static List<String> scanJar(File jarFile, File destFile) {
def file = new JarFile(jarFile)
Enumeration<JarEntry> enumeration = file.entries()
List<String> list = null
while (enumeration.hasMoreElements()) {
JarEntry jarEntry = enumeration.nextElement()
String entryName = jarEntry.getName()
if (entryName == REGISTER_CLASS_FILE_NAME) {
//标记这个jar包包含 AppLifeCycleManager.class
//扫描结束后,我们会生成注册代码到这个文件里
FILE_CONTAINS_INIT_CLASS = destFile
} else {
if (entryName.startsWith(PROXY_CLASS_PACKAGE_NAME)) {
if (list == null) {
list = new ArrayList<>()
}
list.addAll(entryName.substring(entryName.lastIndexOf("/") + 1))
}
}
}
return list
}
static boolean shouldProcessPreDexJar(String path) {
return !path.contains("com.android.support") && !path.contains("/android/m2repository")
}
}
在这里我们必须将需要监听的类实现对应的接口或者继承对应的父类。
import android.content.Context;
public interface IAppLike {
// Application主线程立刻初始化
int MAX_PRIORITY = 10;
int NORM_PRIORITY = 5;
int MIN_PRIORITY = 1;
// Application主线程延迟初始化
int PRIORITY_MAIN_DELAY_MAX = 10 - 11;
int PRIORITY_MAIN_DELAY = 5 - 11;
int PRIORITY_MAIN_DELAY_MIN = 1 - 11;
// Application子线程延迟初始化
int PRIORITY_SUB_DEALY_MAX = 10 - 21;
int PRIORITY_SUB_DEALY = 5 - 21;
int PRIORITY_SUB_DEALY_MIN = 1 - 21;
// 初始化优先级
@Deprecated
int getPriority();
@Deprecated
void onCreate(Context context);
// 每个time type对应不同的初始化时机
int TIME_TYPE_MAIN = 1; // 主线程立刻初始化
int TIME_TYPE_MAIN_DELAY = 2; // 主线程延迟初始化
int TIME_TYPE_SUB_DELAY = 3; // 子线程延迟初始化
int TIME_TYPE_THIRD_SDK = 4; // 第三方SDK初始化
// onCreate,根据各time type的时机来做初始化
// 注意,不同时机,不同的timeType都会回调该函数,准确说是4次,所以需要工程师根据选择不同timeType做初始化
// 通常是用if else来区分timeType,也可以直接使用DefaultAppLike里面的4个辅助函数
void onCreate(Context context, int timeType);
// onTerminate
void onTerminate();
// onTerminate
void onLowMemory();
// 进入后台
void onEnterBackground();
// 回到前台
void onEnterForeground();
}
import android.content.Context;
public class DefaultAppLike implements IAppLike {
@Override
public int getPriority() {
return NORM_PRIORITY;
}
@Override
public void onCreate(Context context) {
}
@Override
public void onCreate(Context context, int timeType) {
if (timeType == IAppLike.TIME_TYPE_MAIN) {
onCreateByMain(context);
} else if (timeType == IAppLike.TIME_TYPE_THIRD_SDK) {
onCreateByThirdSDK(context);
} else if (timeType == IAppLike.TIME_TYPE_MAIN_DELAY) {
onCreateByMainDelay(context);
} else if (timeType == IAppLike.TIME_TYPE_SUB_DELAY) {
onCreateBySubDelay(context);
}
}
public void onCreateByMain(Context context) {
}
public void onCreateByThirdSDK(Context context) {
}
public void onCreateByMainDelay(Context context) {
}
public void onCreateBySubDelay(Context context) {
}
@Override
public void onTerminate() {
}
@Override
public void onLowMemory() {
}
@Override
public void onEnterBackground() {
}
@Override
public void onEnterForeground() {
}
}
最后对外暴露的管理类如下。
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import static com.midea.base.core.lifecycle.api.IAppLike.MIN_PRIORITY;
import static com.midea.base.core.lifecycle.api.IAppLike.PRIORITY_MAIN_DELAY_MIN;
public class AppLifeCycleManager {
private static List<IAppLike> APP_LIKE_LIST = new ArrayList<>(); // 全列表
private static List<IAppLike> MAIN_APP_LIKE_LIST = new ArrayList<>(); // 主线程立刻初始化列表
private static List<IAppLike> MAIN_DELAY_APP_LIKE_LIST = new ArrayList<>(); // 主线程延迟初始化列表
private static List<IAppLike> SUB_THREAD_APP_LIKE_LIST = new ArrayList<>(); // 子线程初始化列表
// 主线程立刻初始化
public static final int INIT_MAIN = 0;
// 主线程延迟初始化
public static final int INIT_MAIN_DELAY = 1;
// 子线程初始化
public static final int INIT_SUB_THREAD = 2;
private static final String TAG = "AppLifeCycleManager";
/**
* 通过插件加载 IAppLike 类
*/
// 所以,不要修改这个函数名和参数!
// 所以,不要修改这个函数名和参数!
// 所以,不要修改这个函数名和参数!
private static void loadAppLike() {
}
// 通过反射去加载 IAppLike 类的实例
// 所以,不要修改这个函数名和参数!
// 所以,不要修改这个函数名和参数!
// 所以,不要修改这个函数名和参数!
private static void registerAppLike(String className) {
if (TextUtils.isEmpty(className))
return;
try {
Object obj = Class.forName(className).getConstructor().newInstance();
if (obj instanceof IAppLike) {
APP_LIKE_LIST.add((IAppLike) obj);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 注册IAppLike类
*/
public static void register(IAppLike appLike) {
if (!APP_LIKE_LIST.contains(appLike)) {
APP_LIKE_LIST.add(appLike);
}
}
/**
* 初始化,需要在Application.onCreate()里调用
*/
public static void init(final Context context) {
//通过插件加载 IAppLike 类
loadAppLike();
Collections.sort(APP_LIKE_LIST, new AppLikeComparator());
for (IAppLike each : APP_LIKE_LIST) {
if (each.getPriority() >= MIN_PRIORITY) {
MAIN_APP_LIKE_LIST.add(each);
} else if (each.getPriority() >= PRIORITY_MAIN_DELAY_MIN) {
MAIN_DELAY_APP_LIKE_LIST.add(each);
} else {
SUB_THREAD_APP_LIKE_LIST.add(each);
}
}
Collections.sort(MAIN_APP_LIKE_LIST, new AppLikeComparator());
Collections.sort(MAIN_DELAY_APP_LIKE_LIST, new AppLikeComparator());
Collections.sort(SUB_THREAD_APP_LIKE_LIST, new AppLikeComparator());
}
// 初始化优先级
public static void onCreate(Context context, int type) {
if (type == INIT_MAIN) { // 主线程立刻初始化
for (IAppLike appLike : MAIN_APP_LIKE_LIST) {
initAppLike(context, appLike, " onCreate cost:");
}
} else if (type == INIT_MAIN_DELAY) { // 主线程延迟初始化
for (IAppLike appLike : MAIN_DELAY_APP_LIKE_LIST) {
initAppLike(context, appLike, " onCreate at main delay cost:");
}
} else if (type == INIT_SUB_THREAD) { // 子线程初始化
for (IAppLike appLike : SUB_THREAD_APP_LIKE_LIST) {
initAppLike(context, appLike, " onCreate at sub thread cost:");
}
}
}
private static void initAppLike(Context context, IAppLike appLike, String tag) {
long onCreateStartTime = System.currentTimeMillis();
try {
appLike.onCreate(context);
} catch (Throwable e) {
e.printStackTrace();
}
// 打印 appLike 执行onCreate耗时,用于统计各个模块初始化耗时,便于后期定位优化
Log.i(TAG, appLike.getClass().getSimpleName() + tag + (System.currentTimeMillis() - onCreateStartTime) + "ms");
}
public static void onCreateByTime(Context context, int timeType) {
for (IAppLike appLike : APP_LIKE_LIST) {
long onCreateStartTime = System.currentTimeMillis();
try {
appLike.onCreate(context, timeType);
} catch (Throwable e) {
e.printStackTrace();
}
// 打印 appLike 执行onCreate耗时,用于统计各个模块初始化耗时,便于后期定位优化
Log.i(TAG, appLike.getClass().getSimpleName() + " onCreateByTime cost:" + (System.currentTimeMillis() - onCreateStartTime) + "ms");
}
}
public static void terminate() {
for (IAppLike appLike : APP_LIKE_LIST) {
try {
appLike.onTerminate();
} catch (Throwable e) {
e.printStackTrace();
}
}
}
public static void lowMemory() {
for (IAppLike appLike : APP_LIKE_LIST) {
try {
appLike.onLowMemory();
} catch (Throwable e) {
e.printStackTrace();
}
}
}
public static void enterBackground() {
for (IAppLike appLike : APP_LIKE_LIST) {
try {
appLike.onEnterBackground();
} catch (Throwable e) {
e.printStackTrace();
}
}
}
public static void enterForeground() {
for (IAppLike appLike : APP_LIKE_LIST) {
try {
appLike.onEnterForeground();
} catch (Throwable e) {
e.printStackTrace();
}
}
}
/**
* 优先级比较器,优先级大的排在前面
*/
private static class AppLikeComparator implements Comparator<IAppLike> {
@Override
public int compare(IAppLike o1, IAppLike o2) {
int p1 = o1.getPriority();
int p2 = o2.getPriority();
return p2 - p1;
}
}
}
例如监听APP是否在前台。
AppLifeCycleManager.init(context);
AppLifecycle.Listener mAppLifeListener mAppLifeListener = new AppLifecycle.Listener() {
@Override
public void onBecameForeground() {
// 应用回到前台
AppLifeCycleManager.enterForeground();
}
}
@Override
public void onBecameBackground() {
// 应用回到后台
AppLifeCycleManager.enterBackground();
}
};
AppLifecycle.get(sApplication).addListener(mAppLifeListener);
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.Application;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* Usage:
* <p>
* 1. Get the Foreground Singleton, passing a Context or Application object unless you
* are sure that the Singleton has definitely already been initialised elsewhere.
* <p>
* 2.a) Perform a direct, synchronous check: Foreground.isForeground() / .isBackground()
* <p>
* or
* <p>
* 2.b) Register to be notified (useful in Service or other non-UI components):
* <p>
* Foreground.Listener myListener = new Foreground.Listener(){
* public void onBecameForeground(){
* // ... whatever you want to do
* }
* public void onBecameBackground(){
* // ... whatever you want to do
* }
* }
* <p>
* public void onCreate(){
* super.onCreate();
* Foreground.get(this).addListener(listener);
* }
* <p>
* public void onDestroy(){
* super.onCreate();
* Foreground.get(this).removeListener(listener);
* }
*/
public class AppLifecycle implements Application.ActivityLifecycleCallbacks {
public static final long CHECK_DELAY = 500;
public static final String TAG = AppLifecycle.class.getSimpleName();
public interface Listener {
void onBecameForeground();
void onBecameBackground();
}
@SuppressLint("StaticFieldLeak")
private static AppLifecycle instance;
private boolean foreground = false, paused = true;
private Handler handler = new Handler();
private List<Listener> listeners = new CopyOnWriteArrayList<Listener>();
private Runnable check;
private Activity mTopActivity;
private int mLivingActivityCount = 0;
/**
* Its not strictly necessary to use this method - _usually_ invoking
* get with a Context gives us a path to retrieve the Application and
* initialise, but sometimes (e.g. in test harness) the ApplicationContext
* is != the Application, and the docs make no guarantees.
*
* @param application application
* @return an initialised Foreground instance
*/
public static AppLifecycle init(Application application) {
if (instance == null) {
instance = new AppLifecycle();
application.registerActivityLifecycleCallbacks(instance);
}
return instance;
}
public static AppLifecycle get(Application application) {
if (instance == null) {
init(application);
}
return instance;
}
public static AppLifecycle get(Context ctx) {
if (instance == null) {
Context appCtx = ctx.getApplicationContext();
if (appCtx instanceof Application) {
init((Application) appCtx);
}
throw new IllegalStateException("Foreground is not initialised and cannot obtain the Application object");
}
return instance;
}
public static AppLifecycle get() {
if (instance == null) {
throw new IllegalStateException("Foreground is not initialised - invoke at least once with parameterised init/get");
}
return instance;
}
public boolean isForeground() {
return foreground;
}
public boolean isBackground() {
return !foreground;
}
public void addListener(Listener listener) {
listeners.add(listener);
}
public void removeListener(Listener listener) {
listeners.remove(listener);
}
@Override
public void onActivityResumed(Activity activity) {
paused = false;
boolean wasBackground = !foreground;
foreground = true;
this.mTopActivity = activity;
if (check != null)
handler.removeCallbacks(check);
if (wasBackground) {
Log.i(TAG, "went foreground");
for (Listener l : listeners) {
try {
l.onBecameForeground();
} catch (Exception exc) {
Log.e(TAG, "Listener threw exception!", exc);
}
}
} else {
Log.i(TAG, "still foreground");
}
}
public int getLivingActivityCount() {
return mLivingActivityCount;
}
@Override
public void onActivityPaused(Activity activity) {
paused = true;
if (this.mTopActivity == activity) {
this.mTopActivity = null;
}
if (check != null)
handler.removeCallbacks(check);
handler.postDelayed(check = () -> {
if (foreground && paused) {
foreground = false;
Log.i(TAG, "went background");
for (Listener l : listeners) {
try {
l.onBecameBackground();
} catch (Exception exc) {
Log.e(TAG, "Listener threw exception!", exc);
}
}
} else {
Log.i(TAG, "still foreground");
}
}, CHECK_DELAY);
}
public Activity getTopActivity() {
return mTopActivity;
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
mLivingActivityCount++;
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
mLivingActivityCount--;
}
}