看我一波,Android获取进程名函数,代码优化到极致的操作!

}

}

return null;

}

但是,大叔要说,这个方法不是最优解。

但是,大叔要说,这个方法不是最优解。

但是,大叔要说,这个方法不是最优解。

二、通过ActivityManager获取当前进程名的弊端

  1. ActivityManager.getRunningAppProcesses() 方法需要跨进程通信,效率不高

需要 和 系统进程的 ActivityManagerService 通信。必然会导致该方法调用耗时。

  1. 拿到RunningAppProcessInfo的列表之后,还需要遍历一遍找到与当前进程的信息。

显然额外的循环也会增加耗时;

当然这个耗时影响很小。

  1. 最恐怖的是 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;

}

}

四、将三种方法结合得到一个更优方案

于是我们将三个方法结合。

  1. 我们优先通过 Application.getProcessName() 方法获取进程名。

  2. 如果获取失败,我们再反射ActivityThread.currentProcessName()获取进程名

  3. 如果失败,我们才通过常规方法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架构视频解析,都已整理成文档,全部都已打包好了,希望能够对大家有所帮助,在面试中能顺利通过。

image

image

喜欢本文的话,不妨顺手给我点个小赞、评论区留言或者转发支持一下呗

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

理了一份Android大厂常见面试题,和一些Android架构视频解析,都已整理成文档,全部都已打包好了,希望能够对大家有所帮助,在面试中能顺利通过。

[外链图片转存中…(img-a810EtVP-1714671162611)]

[外链图片转存中…(img-2Xg7YEX7-1714671162612)]

喜欢本文的话,不妨顺手给我点个小赞、评论区留言或者转发支持一下呗

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值