}
}
return null;
}
但是,大叔要说,这个方法不是最优解。
但是,大叔要说,这个方法不是最优解。
但是,大叔要说,这个方法不是最优解。
二、通过ActivityManager获取当前进程名的弊端
- ActivityManager.getRunningAppProcesses() 方法需要跨进程通信,效率不高
需要 和 系统进程的 ActivityManagerService 通信。必然会导致该方法调用耗时。
- 拿到RunningAppProcessInfo的列表之后,还需要遍历一遍找到与当前进程的信息。
显然额外的循环也会增加耗时;
当然这个耗时影响很小。
- 最恐怖的是 ActivityManager.getRunningAppProcesses() 有可能调用失败,返回null,也可能 AIDL 调用失败。
当然ActivityManager.getRunningAppProcesses()调用失败是极低的概率。
当你的APP用户量达到一定的数量级别时,一定会有用户遇到ActivityManager.getRunningAppProcesses()调用失败的情况。
在我们开头描述的使用场景中,出现进程名获取失败的情况,将会是非常恐怖。
一旦导致进程中的某些组件没有初始化,整个进程大概率是要gg了。
三、寻求更优解
方法一:大叔发现,在android api28的时候新增了一个方法:Application.getProcessName()
Application.getProcessName()方法直接返回当前进程名。这不就是我们想要的API吗!
但是这个方法只有在android9【也就是aip28】之后的系统才能调用。
public class ProcessUtil {
/**
- 通过Application新的API获取进程名,无需反射,无需IPC,效率最高。
*/
public static String getCurrentProcessNameByApplication() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
return Application.getProcessName();
}
return null;
}
}
android9以前的系统怎么办呢?
android9以前的系统怎么办呢?
android9以前的系统怎么办呢?
方法二:ActivityThread.currentProcessName() 方法
于是大叔好奇,看了看Application.getProcessName()的源码,他是如何实现的?
public class Application extends ContextWrapper implements ComponentCallbacks2 {
public static String getProcessName() {
return ActivityThread.currentProcessName();
}
}
我们发现了ActivityThread.currentProcessName()这个方法。
于是大叔继续翻了下源码:
/**
- {@hide}
*/
public final class ActivityThread extends ClientTransactionHandler {
public static String currentProcessName() {
//…
}
}
奥利给,ActivityThread.currentProcessName()方法居然是public static的。
奥利给,ActivityThread.currentProcessName()方法居然是public static的。
奥利给,ActivityThread.currentProcessName()方法居然是public static的。
但是,马上就发现:
ActivityThread类是hide的,app无法直接调用。
ActivityThread类是hide的,app无法直接调用。
ActivityThread类是hide的,app无法直接调用。
于是大叔继续翻源码,看看这个方法是什么时候新增的。
大叔发现这个方法在android4.3.1上就已经有了这个方法了。
在android4.0.4上没有找到currentProcessName()方法。
那么意味着,我们是不是可以反射调用 ActivityThread.currentProcessName() ?
答案当然是可以。
于是我们在ProcessUtil工具类中实现了这个方法:
public class ProcessUtil {
/**
- 通过反射ActivityThread获取进程名,避免了ipc
*/
public static String getCurrentProcessNameByActivityThread() {
String processName = null;
try {
final Method declaredMethod = Class.forName(“android.app.ActivityThread”, false, Application.class.getClassLoader())
.getDeclaredMethod(“currentProcessName”, (Class<?>[]) new Class[0]);
declaredMethod.setAccessible(true);
final Object invoke = declaredMethod.invoke(null, new Object[0]);
if (invoke instanceof String) {
processName = (String) invoke;
}
} catch (Throwable e) {
}
return processName;
}
}
四、将三种方法结合得到一个更优方案
于是我们将三个方法结合。
-
我们优先通过 Application.getProcessName() 方法获取进程名。
-
如果获取失败,我们再反射ActivityThread.currentProcessName()获取进程名
-
如果失败,我们才通过常规方法ActivityManager来获取进程名
如下代码:
public class ProcessUtil {
private static String currentProcessName;
/**
- @return 当前进程名
*/
@Nullable
public static String getCurrentProcessName(@NonNull Context context) {
if (!TextUtils.isEmpty(currentProcessName)) {
return currentProcessName;
}
//1)通过Application的API获取当前进程名
currentProcessName = getCurrentProcessNameByApplication();
if (!TextUtils.isEmpty(currentProcessName)) {
return currentProcessName;
}
//2)通过反射ActivityThread获取当前进程名
currentProcessName = getCurrentProcessNameByActivityThread();
if (!TextUtils.isEmpty(currentProcessName)) {
return currentProcessName;
}
//3)通过ActivityManager获取当前进程名
currentProcessName = getCurrentProcessNameByActivityManager(context);
return currentProcessName;
}
/**
- 通过Application新的API获取进程名,无需反射,无需IPC,效率最高。
*/
public static String getCurrentProcessNameByApplication() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
return Application.getProcessName();
}
return null;
}
/**
- 通过反射ActivityThread获取进程名,避免了ipc
*/
public static String getCurrentProcessNameByActivityThread() {
String processName = null;
try {
final Method declaredMethod = Class.forName(“android.app.ActivityThread”, false, Application.class.getClassLoader())
.getDeclaredMethod(“currentProcessName”, (Class<?>[]) new Class[0]);
declaredMethod.setAccessible(true);
final Object invoke = declaredMethod.invoke(null, new Object[0]);
if (invoke instanceof String) {
processName = (String) invoke;
}
} catch (Throwable e) {
e.printStackTrace();
}
return processName;
}
最后
在这里小编整理了一份Android大厂常见面试题,和一些Android架构视频解析,都已整理成文档,全部都已打包好了,希望能够对大家有所帮助,在面试中能顺利通过。
喜欢本文的话,不妨顺手给我点个小赞、评论区留言或者转发支持一下呗
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
理了一份Android大厂常见面试题,和一些Android架构视频解析,都已整理成文档,全部都已打包好了,希望能够对大家有所帮助,在面试中能顺利通过。
[外链图片转存中…(img-a810EtVP-1714671162611)]
[外链图片转存中…(img-2Xg7YEX7-1714671162612)]
喜欢本文的话,不妨顺手给我点个小赞、评论区留言或者转发支持一下呗
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!