美文网首页
Android中获取到进程名字的最优解

Android中获取到进程名字的最优解

作者: dashingqi | 来源:发表于2020-10-19 23:43 被阅读0次
Android_Banner.jpg

简介

在多进程开发的时候我们可能需要知道当前进程是主进程还是子进程,这是就需要我们取获取到当前所处进程的名字了。

  • 以下是获取到进程名字的几种方式,以及区别和对比

获取方式

使用ActivityManager获取
  • 该方式也是我们能查阅资料看见最多的实现方式
  • 代码如下
object ProcessUtils {

    /**
     * 通过ActivityManager获取到进程名字
     */
    fun getCurrentProcessName(context:Context):String?{
        var myPid = Process.myPid()
        var activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager

        var runningAppProcesses = activityManager.runningAppProcesses
        if (!runningAppProcesses.isNullOrEmpty()){
            runningAppProcesses.forEach {
                if (it.pid == myPid){
                    return it.processName
                }
            }
        }
        return null
    }
}
  • 测试代码如下
class AppApplication : Application() {

    init {
        //初始化打印
        //initLog()
        ApplicationController.init(this, true)
    }

    override fun onCreate() {
        super.onCreate()
        initARouter()
        ApplicationController.transformOnCreate()
       if (ProcessUtils.getCurrentProcessName(this) == BuildConfig.APPLICATION_ID){
           DQLog.d("init main application")
       }
    }
}
  • 打印结果如下
2020-10-19 22:43:38.154 24073-24073/com.dashingqi.mvvmcomponent D/AppApplication: init main application
分析一下
// activityManager.runningAppProcesses ---> ActivityManager # getRunningAppProcess()
 public List<RunningAppProcessInfo> getRunningAppProcesses() {
        try {
            return getService().getRunningAppProcesses();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
// 其中getService() ---> IActivityManager,而IActivityManager是一个AIDL文件,作为和ActivytMangerServie通信,也就是跨进程通信发生了。

  • 所以经过以上分析,可以得出有跨进程通信,就会有响应的耗时
  • 再者我们是通过获取到所以运行的进程,然后一个一个比对,这样循环调用也会有相应的性能损耗。
  • 以上使用ActivityManager获取进程名称是属于常规操作了,下面使用下骚操作。
API28 新增方法 Application # getProcessName()
  • 代码如下
 /**
     * AP28以上才能使用
     * 直接获取到进程名称,不会有跨进程,反射的耗时操作
     */
    fun getCurrentProcessNameOnP():String?{
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P){
            return Application.getProcessName()
        }
        return null
    }
  • 测试代码
 override fun onCreate() {
        super.onCreate()

        initARouter()
        ApplicationController.transformOnCreate()

        var name = ProcessUtils.getCurrentProcessName(this)
        Log.d(TAG,"name $name")
        var pName = ProcessUtils.getCurrentProcessNameOnP()
        Log.d(TAG,"pName === $pName")
        
        if (ProcessUtils.getCurrentProcessName(this) == BuildConfig.APPLICATION_ID){
            Log.d(TAG,"init main application")
        }
    }

  • 打印结果如下
2020-10-19 23:03:31.400 26933-26933/com.dashingqi.mvvmcomponent D/AppApplication: pName === com.dashingqi.mvvmcomponent
分析一下
// Application # getProcessName() ----> ActivityThread.currentProcessName()

 public static String currentProcessName() {
        ActivityThread am = currentActivityThread();
        return (am != null && am.mBoundApplication != null)
            ? am.mBoundApplication.processName : null;
    }

//我们可以看到 currentProcessName() 是 public static 
// 但是我们看到注解描述 ActivityThread 是@hide

//那么有没有其他的操作可以搞一下呢?
  • 通过反射调用ActivityThread中的currentProcessName()
  fun getCurrentProcessNameByAT(): String? {
        var processName: String? = null
        try {
            val declaredMethod: Method = Class.forName("android.app.ActivityThread", false, Application::class.java.classLoader)
                    .getDeclaredMethod("currentProcessName")
            declaredMethod.isAccessible = true
            val invoke: Any = declaredMethod.invoke(null)
            if (invoke is String) {
                processName = invoke
            }
        } catch (e: Throwable) {
            e.printStackTrace()
        }
        return processName
    }
    
// 执行结果如下
// 2020-10-19 23:21:36.487 28594-28594/com.dashingqi.mvvmcomponent D/AppApplication: atName == com.dashingqi.mvvmcomponent
  • 该方法是采用了反射调用了,并没有进行IPC通信,所以耗时通常不会比第一个要长
进行一下耗时的比较
  • 测试代码
val nameStart = SystemClock.elapsedRealtimeNanos()
        var name = ProcessUtils.getCurrentProcessName(this)
        Log.d(TAG,"getCurrentProcessName cost == ${SystemClock.elapsedRealtimeNanos()-nameStart}")

        val pNameStart = SystemClock.elapsedRealtimeNanos()
        var pName = ProcessUtils.getCurrentProcessNameOnP()
        Log.d(TAG,"getCurrentProcessNameOnP cost == ${SystemClock.elapsedRealtimeNanos() - pNameStart}")

        val atNameStart = SystemClock.elapsedRealtimeNanos()
        var atName = ProcessUtils.getCurrentProcessNameByAT()
        Log.d(TAG,"getCurrentProcessNameByAT cost == ${SystemClock.elapsedRealtimeNanos()-atNameStart}")

  • 运行结果
2020-10-19 23:31:24.867 29657-29657/com.dashingqi.mvvmcomponent D/AppApplication: getCurrentProcessName cost == 641875
2020-10-19 23:31:24.867 29657-29657/com.dashingqi.mvvmcomponent D/AppApplication: getCurrentProcessNameOnP cost == 28229
2020-10-19 23:31:24.867 29657-29657/com.dashingqi.mvvmcomponent D/AppApplication: getCurrentProcessNameByAT cost == 119792

总的说来,直接获取要好于反射的方式,放射的方式要好于IPC方式

相关文章

网友评论

      本文标题:Android中获取到进程名字的最优解

      本文链接:https://www.haomeiwen.com/subject/rvhrmktx.html