【问题标题】:How can I find the data usage on a per-application basis on Android?如何在 Android 上查找每个应用程序的数据使用情况?
【发布时间】:2012-08-13 18:14:38
【问题描述】:

我正在尝试根据每个应用程序找出 Android 上的数据使用情况。类似于 Android Data Usage Apps and Quota / Cap Monitor Widgets: never get charged extra for data or get capped again!

我查看了 Stack Overflow 问题How to go about detecting data usage in the Android environment

但这并没有太大帮助。


ActivityManager activityManager = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
ActivityManager.MemoryInfo mInfo = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo( mInfo );
List<RunningAppProcessInfo> listOfRunningProcess = activityManager.getRunningAppProcesses();
Log.d(TAG, "XXSize: " + listOfRunningProcess.size());

for (RunningAppProcessInfo runningAppProcessInfo : listOfRunningProcess) {

    if (runningAppProcessInfo.uid > 1026)
    {
        Log.d(TAG, "ANS " + runningAppProcessInfo.processName +
                   " Id :" + runningAppProcessInfo.pid +
                   " UID: " + runningAppProcessInfo.uid);
    }
}

我将上面的代码尝试为suggested by Akos Cz。然而,所有UIDs 都是数字,不像你上面提到的app_79。这样可以吗?

【问题讨论】:

  • 您是希望将此信息放入应用程序(以编程方式),还是只是好奇?什么设备?
  • 糟糕。我想以编程方式执行此操作。

标签: android usage-statistics


【解决方案1】:

以下链接可以帮助您了解如何以编程方式确定每个应用程序的数据使用情况。

您需要实现代码以使用 TraficStats API 并跟踪每个 UID(应用程序)发送/接收的字节数。

【讨论】:

  • 谢谢。我刚刚想通了这件事。我正要发布更新。你能解释一下 UID 和 PID 之间的区别吗?根据我的理解,UID 是基于用户的。对于我设备上运行的每个应用程序,UID 不都是一样的吗???并且 PID 应该因每个应用程序进程而异。我可能不正确。请澄清。谢谢。 :)
  • 谢谢。我只是想通了这件事。每个应用程序的 UID 是否不同?我假设在我的设备上运行的每个进程都是相同的。你能澄清一下吗?谢谢。
  • - 每个应用程序(包)在安装时都被分配了一个任意但不同的操作系统用户 ID。通常类似于 app_XX(例如 app_79) - 在设备上的应用程序生命周期内不会更改 - 所有应用程序资源都由其 UID 拥有 - 每个应用程序进程在其自己的 UID 下运行 - 使用相同证书签名的应用程序可以共享数据,用户ID,以及在单个进程中运行。他们只需要指定相同的 sharedUserId 和 process
  • 我的错误。是的,UID 是数字。
  • TrafficStats 不能再用于监控其他应用。您应该改用 NetworkStatsManager:developer.android.com/reference/android/net/…。我认为您应该在那里使用“queryDetailsForUid”,如下所示:groups.google.com/forum/embed/#!topic/android-developers/…
【解决方案2】:

在创建新类 PackageInformationTotal 后使用此方法。

public void getPakagesInfoUsingHashMap() {
    final PackageManager pm = getPackageManager();
    // get a list of installed apps.
    List<ApplicationInfo> packages = pm.getInstalledApplications(0);

    // loop through the list of installed packages and see if the selected
    // app is in the list
    for (ApplicationInfo packageInfo : packages) {
        // get the UID for the selected app
        UID = packageInfo.uid;
        String package_name = packageInfo.packageName;
        ApplicationInfo app = null;
        try {
            app = pm.getApplicationInfo(package_name, 0);
        } catch (NameNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        String name = (String) pm.getApplicationLabel(app);
        Drawable icon = pm.getApplicationIcon(app);
        // internet usage for particular app(sent and received)
        double received = (double) TrafficStats.getUidRxBytes(UID)

                / (1024 * 1024);
        double send = (double) TrafficStats.getUidTxBytes(UID)
                / (1024 * 1024);
        double total = received + send;

        if(total>0)
        {
            PackageInformationTotal pi=new PackageInformationTotal();
            pi.name=name;
            pi.packageName=package_name;
            pi.icon=icon;               
            pi.totalMB=String.format( "%.2f", total )+" MB";
            pi.individual_mb=String.format( "%.2f", total );
            totalData+=Double.parseDouble(String.format( "%.2f", total ));
            dataHash.add(pi);
        Log.e(name,String.format( "%.2f", total )+" MB");
        }

    }
    Editor edit=shared.edit();
    edit.putString("Total",String.format( "%.2f", totalData));
    edit.commit();
}

之后,您可以以 MB 为单位跟踪所有进程使用情况。

【讨论】:

  • 这不适用于所有设备。每个应用的电池使用情况是否有类似情况?
  • 在PackageInformationTotal中我们应该实现什么,你可以发布代码吗?
  • 这也不是 100% 的解决方案 - 并不总是有效,例如。 api 23
【解决方案3】:

以编程方式:

您可以为ACTION_MANAGE_NETWORK_USAGE 操作(在 Android 4.0 中引入)声明意图过滤器,以表明您的应用程序定义了一个提供控制数据使用的选项的活动。 ACTION_MANAGE_NETWORK_USAGE 显示用于管理特定应用程序的网络数据使用的设置。当您的应用具有允许用户控制网络使用的设置活动时,您应该为该活动声明此意图过滤器。 查看此内容以了解有关管理数据使用的更多信息manage usage per application

ACTION_MANAGE_NETWORK_USAGE 的正确定义是你可以看到here

【讨论】:

    【解决方案4】:
     public class Main extends Activity {
    
        private Handler mHandler = new Handler();
        private long mStartRX = 0;
        private long mStartTX = 0;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            mStartRX = TrafficStats.getTotalRxBytes();
            mStartTX = TrafficStats.getTotalTxBytes();
            if (mStartRX == TrafficStats.UNSUPPORTED || mStartTX == TrafficStats.UNSUPPORTED) {
                AlertDialog.Builder alert = new AlertDialog.Builder(this);
                alert.setTitle("Uh Oh!");
                alert.setMessage("Your device does not support traffic stat monitoring.");
                alert.show();
            } else {
                mHandler.postDelayed(mRunnable, 1000);
            }
        }
    
        private final Runnable mRunnable = new Runnable() {
            public void run() {
                TextView RX = (TextView)findViewById(R.id.RX);
                TextView TX = (TextView)findViewById(R.id.TX);
                long rxBytes = TrafficStats.getTotalRxBytes()- mStartRX;
                RX.setText(Long.toString(rxBytes));
                long txBytes = TrafficStats.getTotalTxBytes()- mStartTX;
                TX.setText(Long.toString(txBytes));
                mHandler.postDelayed(mRunnable, 1000);
            }
         };
    }
    

    您也可以结帐https://github.com/commonsguy/cw-andtuning/tree/master/TrafficMonitor

    【讨论】:

    【解决方案5】:

    这个 sn-p 也适用于那些在您的设备中实际运行的应用程序

    final PackageManager pm = getPackageManager();
    
    ActivityManager activityManager = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE);
    List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
    //final List<ActivityManager.RunningTaskInfo> recentTasks = activityManager.getRunningTasks(Integer.MAX_VALUE);
    for (int i = 0; i < appProcesses.size(); i++) {
        Log.d("Executed app", "Application executed : " + appProcesses.get(i).processName + "\t\t ID: " + appProcesses.get(i).pid + "");
        //  String packageName = activityManager.getRunningTasks(1).get(0).topActivity.getPackageName();
        //String packageName = appProcesses.get(i)..getPackageName();
        ApplicationInfo app = null;
        try {
            app = pm.getApplicationInfo(appProcesses.get(i).processName, 0);
            if ((app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 1) {
                //it's a system app, not interested
            } else if ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 1) {
                //Discard this one
                //in this case, it should be a user-installed app
            } else {
                // tx = TrafficStats.getUidTxBytes(app.uid);
                //rx = TrafficStats.getUidRxBytes(app.uid);
                long delta_rx = TrafficStats.getUidRxBytes(app.uid) - rx;
    
                long delta_tx = TrafficStats.getUidTxBytes(app.uid) - tx;
            }
        }
    

    【讨论】:

    【解决方案6】:

    要访问单个应用的统计信息,您需要该应用的 uid,它是系统在安装时分配给每个应用的 int 值。

    PackageManager packageManager = context.getPackageManager();
    
    ApplicationInfo info = packageManager.getApplicationInfo("com.example.app", 0); 
    
    int packageUid = info.uid;
    

    获取 Mobile 的所有 Rx 和 Tx 字节用于包:

    NetworkStats.Bucket bucket = networkStatsManager.queryDetailsForUid(ConnectivityManager.TYPE_MOBILE, getSubscriberId(context, ConnectivityManager.TYPE_MOBILE), 0, System.currentTimeMillis(),packageUid);
            
            
        
    long rxBytes = 0L;
           
    long txBytes = 0L;
            
    NetworkStats.Bucket bucket = new NetworkStats.Bucket();
           
    while (networkStats.hasNextBucket()) {
            
         networkStats.getNextBucket(bucket);
         rxBytes += bucket.getRxBytes();
         txBytes += bucket.getTxBytes(); 
    }
    networkStats.close();
    

    如需更多说明,请查看: How do I programmatically show data usage of all applications?

    【讨论】:

      【解决方案7】:

      经过长时间的奋斗,我能够找到通过任何接口为每个已安装的 android 应用程序获取数据的解决方案 设备。

      由于 Android 提供了 TrafficStats API,但这些 API 为每个应用程序 uid 提供了自设备启动以来的完整数据统计信息,甚至 API 不支持通过特定应用程序的任何接口获取数据。 即使我们依赖 TraffiucStates APIS,我们也会为每个应用程序获得新的数据统计信息。

      所以我想用隐藏的 API 来使用这个..

      这里我提到了通过 Android 中的任何接口获取每个应用程序的数据统计信息的步骤...

      1. 建立一个“INetworkStatsSession”会话

        #import android.net.INetworkStatsSession;

      INetworkStatsSession mStatsSession = mStatsService.openSession();

      1. 根据您要测量的接口创建网络模板..

        #import static android.net.NetworkTemplate.buildTemplateEthernet;
        #import static android.net.NetworkTemplate.buildTemplateMobile3gLower;
        #import static android.net.NetworkTemplate.buildTemplateMobile4g;
        #import static android.net.NetworkTemplate.buildTemplateMobileAll;
        #import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
        
        #import android.net.NetworkTemplate;
        
        private NetworkTemplate mTemplate;
        
        mTemplate = buildTemplateMobileAll(getActiveSubscriberId(this
                        .getApplicationContext()));
        
      2. GetActive 订阅者 ID:

        private static String getActiveSubscriberId(Context context) {
            final TelephonyManager tele = TelephonyManager.from(context);
            final String actualSubscriberId = tele.getSubscriberId();
            return SystemProperties.get(TEST_SUBSCRIBER_PROP, actualSubscriberId);
        }
        
      3. 通过传递应用程序 UID 收集各个应用程序的网络 HIStory...

         private NetworkStatsHistory collectHistoryForUid(NetworkTemplate template,
                int uid, int set) throws RemoteException {
            final NetworkStatsHistory history = mStatsSession.getHistoryForUid(
                    template, uid, set, TAG_NONE, FIELD_RX_BYTES | FIELD_TX_BYTES);
            return history;
        
        }
        
      4. 获取总消费数据:

        public void showConsuption(int UID){
            NetworkStatsHistory history = collectHistoryForUid(mTemplate, UID,
                    SET_DEFAULT);
        
            Log.i(DEBUG_TAG, "load:::::SET_DEFAULT:.getTotalBytes:"+ Formatter.formatFileSize(context, history.getTotalBytes()));
        
            history = collectHistoryForUid(mTemplate, 10093,
                    SET_FOREGROUND);
            Log.i(DEBUG_TAG, "load::::SET_FOREGROUND::.getTotalBytes:"+ Formatter.formatFileSize(context, history.getTotalBytes()));
        
            history = collectHistoryForUid(mTemplate, 10093,
                    SET_ALL);
            Log.i(DEBUG_TAG, "load::::SET_ALL::.getTotalBytes:"+ Formatter.formatFileSize(context, history.getTotalBytes()));
        
        }
        

      【讨论】:

      • @Mysterion 您能否提供有关 INetworkSession 的更多见解,基本上需要每个应用程序每天的数据使用量
      • @SrishtiRoy 使用 INetworkSession ..您需要将您的应用程序构建为系统应用程序..如果您想根据每个应用程序计算每天的数据,您需要在数据库中维护每天的数据。在现有的内部 android API 中没有 ..所以你必须在你的应用程序中明确地维护它
      • @Anshuman 知道如何仅列出那些消耗移动数据的应用
      • @SrishtiRoy 您可以定期维护安装了移动数据历史记录(使用上述解决方案)的应用程序的统计数据库,并且随着移动数据的不同,您可以获得正在消耗移动数据的应用程序列表。
      猜你喜欢
      • 2015-10-05
      • 1970-01-01
      • 1970-01-01
      • 2016-03-16
      • 1970-01-01
      • 1970-01-01
      • 2013-06-11
      • 1970-01-01
      • 2013-11-30
      相关资源
      最近更新 更多