美文网首页Android开发经验谈Android开发半栈工程师
[Android]你不知道的Android进程化(1)--进程信

[Android]你不知道的Android进程化(1)--进程信

作者: CangWang | 来源:发表于2017-11-30 11:58 被阅读818次

    大家好,我系苍王。

    以下是我这个系列的相关文章,有兴趣可以参考一下,可以给个喜欢或者关注我的文章。

    [Android]如何做一个崩溃率少于千分之三噶应用app--章节列表

    这里是一个全新的系列--进程化

    组件化模块化延伸后,还能到达进程化。

    当你能活用组件化模块化,明白其中的关联之后,再深入探究下去,就会走到进程这一步。

    从基础出发,我们说一下进程信息,下面全部使用kotlin编写的api。

    获取内存容量

        fun getTotalMemSize():Long{
            var size=0L
            //系统内存文件
            val file = File("/proc/meminfo")
            try {
                val buffer = BufferedReader(InputStreamReader(FileInputStream(file)))
                var memInfo = buffer.readLine()
                val startIndex = memInfo.indexOf(":")
                val endIndex =memInfo.indexOf("k")
                memInfo = memInfo.substring(startIndex+1,endIndex).trim()
                size = memInfo.toLong()
                size *= 1024
                buffer.close()
            }catch (e:IOException){
                e.printStackTrace()
            }
            return size
        }
    

    获取可用内存

        fun getAviableMemSize(context:Context):Long{
            val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
            var mi = ActivityManager.MemoryInfo()
            am.getMemoryInfo(mi)
            return mi.availMem
        }
    

    获取当前进程id

    fun getCurrentProcessId():Int{
            return android.os.Process.myPid()
        }
    

    获取当前进程名

     fun getCurrentProcessName():String{
            var processName = UNKNOWN_PROCESS_NAME
            try {
                val file = File("/proc/"+ getCurrentProcessId()+"/cmdline")
                val buffer = BufferedReader(FileReader(file))
                processName = buffer.readLine().trim()
                buffer.close()
            }catch (e:Exception){
                e.printStackTrace()
            }
            return processName
        }
    
    
        fun getCurrentProcessName():String{
            var processName = UNKNOWN_PROCESS_NAME
            try {
                val file = File("/proc/"+ getCurrentProcessId()+"/cmdline")
                val buffer = BufferedReader(FileReader(file))
                processName = buffer.readLine().trim()
                buffer.close()
            }catch (e:Exception){
                e.printStackTrace()
            }
            return processName
        }
    

    获取进程名

        fun getCurrentProcessName(pid:Int):String{
            var processName = UNKNOWN_PROCESS_NAME
            try {
                val file = File("/proc/"+ pid+"/cmdline")
                val buffer = BufferedReader(FileReader(file))
                processName = buffer.readLine().trim()
                buffer.close()
            }catch (e:Exception){
                e.printStackTrace()
            }
            return processName
        }
    
        fun getProcessName(context:Context,pid:Int):String{
            var processName = getCurrentProcessName(pid)
            if (UNKNOWN_PROCESS_NAME .equals(processName)){
                val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
                val runningApps = am.runningAppProcesses
                if (runningApps!=null){
                    for (info in runningApps){
                        if(info.pid == pid) return info.processName
                    }
                }
            }
            return processName
        }
    

    使用命令获取adb手机进程

    连接电脑,使用adb shell连接手机。
    然后使用ps可以查看全部进程的信息。
    这里请注意linux目录中有个/proc的目录,这里记载运行的进程,如果没有root手机取得最高权限是无法查看到进程信息的。


    image.png

    通过代码获取全部的进程信息

    这里需要使用ActivityManager 和PackageManager获取运行进程信息的列表
    在5.0以前使用一下的方法来获取

    /**
         * 获取所有进程信息(5.0以前)
         */
        fun getTaskInfos(context:Context):List<TaskBean>?{
            val activityManager:ActivityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
            val packageManager:PackageManager = context.packageManager
            var runList:List<ActivityManager.RunningAppProcessInfo> = activityManager.runningAppProcesses
            if(runList.isEmpty()) return null
            val list = ArrayList<TaskBean>()
            try {
                for (info in runList){
                    val app =packageManager.getPackageInfo(info.processName,0).applicationInfo
                    //过滤自己当前应用
                    if (app ==null || context.packageName.equals(app.packageName)) continue
    
                    val bean = TaskBean()
                    bean.pid = info.pid
                    bean.processName = info.processName  //进程名
                    bean.pInfo = packageManager.getPackageInfo(bean.processName,0)  //包信息
                    bean.appName = app.loadLabel(packageManager).toString() //app名
                    bean.drawable  = app.loadIcon(packageManager)    //app图标
                    bean.pakcageName = app.packageName  //包名
                    //系统应用
                    if((app.flags and ApplicationInfo.FLAG_SYSTEM) >0){
                        bean.isSystem = true
                    }else{
                        bean.isUser = true
                    }
    
                    val memoryInfo = activityManager.getProcessMemoryInfo(IntArray(info.pid))
                    val memsize:Double = memoryInfo[0].dalvikPrivateDirty/1024.0
                    bean.memSize = memsize
                    list.add(bean)
    
                }
            }catch (e:PackageManager.NameNotFoundException){
                e.printStackTrace()
            }
            return list
        }
    

    在Android5.0以后,使用以上的方法,只能获取前台运行的app所在进程的的信息
    Android5.0~7.0 可以使用AndroidProcessor开源库获取
    其原理是读取/proc/里面进程号为数字的进程的信息
    7.0以后google限制了,app只能在/proc/读取到个人的进程信息。

    通过UsageStatsManager获取

    UsageStatsManager是5.0 才开始有的,用于记录应用的使用信息, 入应用在某段时间内处于前台和后台的时间,最近一次启动的时间等。
    使用它之前需要在AndroidManifest中配置 “android.permission.PACKAGE_USAGE_STATS”的权限,必须勾选安全的权限配置才能打开

    /**
         * 获取所有进程信息(5.0以后)
         */
        fun getTaskInfosL(context:Context):List<TaskBean>?{
            val list = ArrayList<TaskBean>()
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
                val packageManager:PackageManager = context.packageManager
                val usm = context.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager
                val calendar = Calendar.getInstance()
               //结束时间
                val endTime = calendar.timeInMillis
                calendar.add(Calendar.YEAR, -1)
               //开始时间
                val startTime = calendar.timeInMillis
                val usageStatsList = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, startTime, endTime)
                for(usage in usageStatsList){
                    try {
                        val bean = TaskBean()
                        val app = packageManager.getPackageInfo(usage.packageName, 0).applicationInfo
                        bean.pakcageName = usage.packageName
                        bean.processName = app.processName
                        bean.pInfo = packageManager.getPackageInfo(bean.processName, 0)
                        bean.appName = app.loadLabel(packageManager).toString() //app名
                        bean.drawable = app.loadIcon(packageManager)    //app图标
                        //系统应用
                        if ((app.flags and ApplicationInfo.FLAG_SYSTEM) > 0) {
                            bean.isSystem = true
                        } else {
                            bean.isUser = true
                        }
                        list.add(bean)
                    }catch (e:Exception){
                        e.printStackTrace()
                    }
                }
            }
            return list
    }
    

    UsageStats 中无法获取进程pid,usageStats只是记录进程运行的记录,所以这种方法没办法获得占用的内存信息,适用于7.0 以上的系统。

    打开指定包名的App

        fun openSpecifiedApp(context:Context,packageName:String){
            val manager = context.packageManager
            val lauchIntentForPackage = manager.getLaunchIntentForPackage(packageName)
            context.startActivity(lauchIntentForPackage)
        }
    

    打开指定包名的App应用信息界面

    fun showAppInfo(context: Context,packageName:String){
            val intent = Intent()
            intent.action = "android.settings.APPLICATION_DETAILS_SETTINGS"
            intent.data = Uri.parse("package:" + packageName)
            context.startActivity(intent)
        }
    

    当前app处于前台还是后台

    需添加在AndroidManifest中添加<uses-permission android:name="android.permission.GET_TASKS"/>的权限

        fun isAppForground(context: Context,packageName:String):Boolean{
            val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
            var task = am.getRunningTasks(1)
            if(!task.isEmpty()){
                val top = task.get(0).topActivity
                if (top.packageName.equals(context.packageName)){
                    return true
                }
            }
            return false
        }
    

    组件化的群里已经快满员了,这是新开的进程化的新群。
    Stay hugry ,stay foolish!


    Android进程化交流

    相关文章

      网友评论

        本文标题:[Android]你不知道的Android进程化(1)--进程信

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