【问题标题】:Android: Get the stack (array) of currently opened applicationsAndroid:获取当前打开的应用程序的堆栈(数组)
【发布时间】:2016-11-06 23:00:44
【问题描述】:

有什么方法可以获取当前运行或打开的android应用程序列表,以便我可以找到设备中最后运行的应用程序。谢谢

【问题讨论】:

    标签: java android


    【解决方案1】:

    我几天前一直在研究表情符号键盘。我花了三天时间获得前台应用程序包名称以发送表情符号图像,因为每当我想发送图像时,它都会弹出intentchooser 以选择可以将图像作为附加功能处理的应用程序之一。

    所有教程和链接都对我不起作用,因为 google 弃用了用于获取当前正在运行的应用程序的 getRunningTasks() 方法。

    然后我想到了使用ResolveInfo 获取设备上当前正在运行的应用程序的堆栈,但它也不起作用。

    最后,我发现 API 21 中引入了一个名为 UsageStatsManager 的新类,它对我有用。 This github link 提供如何使用该类获取正在运行的应用程序包名。

    下面是我如何让包名称应用程序在顶部运行的代码:

    public class UStats {
        public static final String TAG = UStats.class.getSimpleName();
        @SuppressLint("SimpleDateFormat")
        private static final SimpleDateFormat dateFormat = new SimpleDateFormat("M-d-yyyy HH:mm:ss");
    
        public static ArrayList<String> printCurrentUsageStatus(Context context) {
            return printUsageStats(getUsageStatsList(context));
        }
    
        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        public static ArrayList<String> printUsageStats(List<UsageStats> usageStatsList) {
            HashMap<String, Integer> lastApp = new HashMap<String, Integer>();
            for (UsageStats u : usageStatsList) {
                lastApp.put(u.getPackageName(), (int) u.getLastTimeStamp());
                /*Log.d(TAG, "Pkg: " + u.getPackageName() + "\t" + "ForegroundTime: "
                        + u.getTotalTimeInForeground() + "\t" + "LastTimeStamp: " + new Date(u.getLastTimeStamp()));*/
            }
            Map<String, Integer> sortedMapAsc = sortByComparator(lastApp);
            ArrayList<String> firstApp = new ArrayList<>();
            for (Map.Entry<String, Integer> entry : sortedMapAsc.entrySet()) {
                String key = entry.getKey();
                //Integer value = entry.getValue();
                firstApp.add(key);
                /*System.out.println("package name: " + key + ", time " + new Date(Math.abs(value)));*/
            }
    
            return firstApp;
        }
    
        // To check the USAGE_STATS_SERVICE permission
        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        public static List<UsageStats> getUsageStatsList(Context context) {
            UsageStatsManager usm = getUsageStatsManager(context);
            Calendar calendar = Calendar.getInstance();
            long endTime = calendar.getTimeInMillis();
            calendar.add(Calendar.MINUTE, -1);
            long startTime = calendar.getTimeInMillis();
    
            Log.d(TAG, "Under getUsageStateList");
            Log.d(TAG, "Range start:" + dateFormat.format(startTime));
            Log.d(TAG, "Range end:" + dateFormat.format(endTime));
    
            List<UsageStats> usageStatsList = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, startTime, endTime);
            return usageStatsList;
        }
    
        // Sort the map in the ascending order of the timeStamp
        private static Map<String, Integer> sortByComparator(Map<String, Integer> unsortMap) {
            List<Map.Entry<String, Integer>> list = new LinkedList<>(unsortMap.entrySet());
    
            // Sorting the list based on values
            Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {
                public int compare(Map.Entry<String, Integer> o1,
                                   Map.Entry<String, Integer> o2) {
                    return o2.getValue().compareTo(o1.getValue());
                }
            });
    
            // Maintaining insertion order with the help of LinkedList
            Map<String, Integer> sortedMap = new LinkedHashMap<String, Integer>();
            for (Map.Entry<String, Integer> entry : list) {
                sortedMap.put(entry.getKey(), entry.getValue());
            }
            return sortedMap;
        }
    
        @TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1)
        @SuppressWarnings("ResourceType")
        private static UsageStatsManager getUsageStatsManager(Context context) {
            UsageStatsManager usm = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
            return usm;
        }
    }
    

    然后我只需使用以下代码获取应用程序包名称的 ArrayList:

    ArrayList<String> sortedApplication = UStats.printCurrentUsageStatus(SimpleIME.this);
    Log.d("TAG", "applicationList: " + sortedApplication.toString());
    

    别忘了添加权限:

    <uses-permission android:name = "android.permission.PACKAGE_USAGE_STATS"
                         tools:ignore = "ProtectedPermissions"/>
    

    和下面的代码来检查我们的应用程序是否有权限获取其他应用程序的状态:

    if (UStats.getUsageStatsList(this).isEmpty()) {
        Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
        Toast.makeText(MainActivity.this, "Enable Usage Access for YOUR_APP_NAME to use this app", Toast.LENGTH_LONG).show();
        startActivity(intent);
    }
    

    以上代码将打开一个访问设置页面,使我们的应用程序能够获取其他应用程序的使用统计信息(一次)。

    希望这会有所帮助。

    【讨论】:

      【解决方案2】:

      我使用这段代码来查看系统中安装的包名的实际列表:

                  try {
                      Process process = Runtime.getRuntime().exec("pm list packages");
                      BufferedReader bufferedReader = new BufferedReader(
                                               new InputStreamReader(process.getInputStream()));
      
                      int read;
                      char[] buffer = new char[4096];
                      StringBuffer output = new StringBuffer();
      
                      while ((read = bufferedReader.read(buffer)) > 0) {
                          output.append(buffer, 0, read);
                      }
                      bufferedReader.close();
                      process.waitFor();
      
                      Log.d("your tag", output.toString());
                  } catch (IOException ioe) {
                      ioe.printStackTrace();
                  } catch (InterruptedException ie) {
                      ie.printStackTrace();
                  }
      

      我确信通过包和 PID,您可以在 ADB shell 控制台中调整命令以查找有关应用程序列表的时间信息,但我认为您看不到系统上最后打开的应用程序,虽然我不知道 shell 控制台使用的所有命令...

      Runtime.getRuntime().exec("top -n 1 -d 1");
      

      例如,此命令显示设备内的不同进程及其资源消耗。

      在以下文档中与他们会面:https://developer.android.com/studio/command-line

      相关:

      【讨论】:

        【解决方案3】:

        如果您希望它更具反应性,我实际上只是通过 LiveData 处理类似的场景。查看我的博客文章:https://bmcreations.dev/blog/foreground-app-observing-with-lifecycle-components

        【讨论】:

        • 为什么是-1?
        猜你喜欢
        • 2016-03-27
        • 2022-12-30
        • 1970-01-01
        • 2012-12-21
        • 2014-04-26
        • 2014-08-07
        • 2010-11-25
        • 2012-05-05
        • 1970-01-01
        相关资源
        最近更新 更多