【问题标题】:android statistic 3g traffic for each APP, how?android统计每个APP的3g流量,如何?
【发布时间】:2012-09-18 18:25:58
【问题描述】:

统计每个APP的网络流量,我现在用的是Android TrafficStats

我可以得到如下结果:

  • Youtube 50.30 MB
  • Facebook 21.39 MB
  • Google Play 103.38 MB
  • (以及更多...)

据我所知,“Android Trafficstats”只是一个指向 c 文件的本机指针。 (也许是 .so ?)

但它混合了 Wifi 和 3g 流量,有什么办法只获得非 WiFi 流量统计?

【问题讨论】:

  • 你用的是什么系统?至少从 ICS 开始,您可以看到 3g/mobile 的数据使用情况;无线局域网;或全部合并。

标签: android 3g traffic network-traffic traffic-measurement


【解决方案1】:

晚安,我有办法做到这一点......

首先我必须创建一个扩展 BroadcasrReceiver 的类,如下所示:

清单定义:

<receiver android:name=".core.CoreReceiver" android:enabled="true" android:exported="false">
  <intent-filter>
    <action android:name="android.net.ConnectivityManager.CONNECTIVITY_ACTION" />
    <action android:name="android.net.wifi.STATE_CHANGE" />
  </intent-filter>
</receiver>

代码:

/**
 * @author me
 */
public class CoreReceiver extends BroadcastReceiver {
  public void onReceive(Context context, Intent intent) {
    if (Constants.phone == null) {
      // Receive [network] event
      Constants.phone=new PhoneListen(context);
      TelephonyManager telephony=(TelephonyManager) 
      context.getSystemService(Context.TELEPHONY_SERVICE);
      telephony.listen(Constants.phone, PhoneStateListener.LISTEN_DATA_CONNECTION_STATE);
    }

    WifiManager wifi=(WifiManager)context.getSystemService(Context.WIFI_SERVICE);
    boolean b=wifi.isWifiEnabled();
    if (Constants.STATUS_WIFI != b) {
       // WiFi status changed...
    }
  }
}

下面还有一个电话统计监听器...

public class PhoneListen extends PhoneStateListener {
  private Context context;    
  public PhoneListen(Context c) {
     context=c;
  }    
  @Override
  public void onDataConnectionStateChanged(int state) {
    switch(state) {
      case TelephonyManager.DATA_DISCONNECTED:// 3G
        //3G has been turned OFF
      break;
      case TelephonyManager.DATA_CONNECTING:// 3G
        //3G is connecting
      break;
      case TelephonyManager.DATA_CONNECTED:// 3G
        //3G has turned ON
      break;
    }
  }
}

最后,这是我的逻辑

  1. 将计数收集到 SQLite DB 中。
  2. 每 1 分钟通过 TrafficStats 收集所有应用网络使用情况,仅在 3G 开启时。
  3. 如果 3G 关闭,则停止收集。
  4. 如果 3G 和 WiFi 都开启,请停止收集。

据我所知,如果 3G 和 WiFi 都可用,网络流量将仅通过 WiFi。

【讨论】:

    【解决方案2】:

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

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

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

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

    1. 建立一个“INetworkStatsSession”会话

      import android.net.INetworkStatsSession;
      INetworkStatsSession mStatsSession = mStatsService.openSession();
      
    2. 根据您要测量的接口创建一个网络模板..

      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()));
      
    3. 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);
      }
      
    4. 通过传递应用程序 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;
      
      }
      
    5. 获取总消费数据:

      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()));
      
      }
      

    【讨论】:

    • 你有这个内部类的链接吗?它需要编译还是只是简单的复制和粘贴?
    • @Pedram 正如我在这个解决方案中提到的那样..我们正在使用内部 API 来实现这一点,所以我们必须将应用程序构建为系统应用程序,并且它在编译时需要所有相关的包导入......
    【解决方案3】:

    我找到了只获取 wifi 流量的方法

    long totalbyte = Trafficstats.getTotalRxBytes();
    long mobilenetworkbyte = Trafficstats.getMobileRxBytes();
    String total = Long.toString(totalbyte);
    String mobile = Long.toString(mobilenetworkbyte);
    String wifibyte = total - mobile + "kb";
    

    现在 wifibyte 字符串显示 wifi 总字节 它对我有用,我希望对你有用

    【讨论】:

      【解决方案4】:

      尝试以下代码并关闭“WIFI”并仅使用“3G”进行检查

      1. 在 Eclipse 中创建一个新的 Android 项目。请记住使用 TrafficStats 类,您必须针对 Android 2.2 (Froyo) 或更高版本的 API。

      2. 在 /res/layout 文件夹中,我们将创建一个 main.xml 资源。对于这个项目,我们只是在垂直堆叠的线性布局中使用了一系列文本视图。

              main.xml
        
             <?xml version="1.0" encoding="utf-8"?>
        
            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        
             android:layout_width="fill_parent"
        
             android:layout_height="fill_parent"
        
             android:orientation="vertical" >
        
             <TextView
        
             android:layout_width="fill_parent"
        
             android:layout_height="wrap_content"
        
             android:textSize="16sp"
        
             android:textStyle="bold"
        
             android:gravity="center"
        
             android:paddingBottom="20dip"
        
             android:text="Traffic Stats Demo" />
        
             <TextView
        
             android:layout_width="fill_parent"
        
             android:layout_height="wrap_content"
        
             android:textSize="14sp"
        
             android:textColor="#00ff00"
        
             android:gravity="center"
        
             android:text="Transmit Bytes" />
        
             <TextView
        
             android:layout_width="fill_parent"
        
             android:layout_height="wrap_content"
        
             android:textSize="14sp"
        
             android:gravity="center"
        
             android:text="0"
        
             android:id="@+id/TX"/>
        
            <TextView
        
            android:layout_width="fill_parent"
        
            android:layout_height="wrap_content"
        
            android:textSize="14sp"
        
            android:textColor="#ff0000"
        
            android:gravity="center"
        
            android:text="Receive Bytes" />
        
            <TextView
        
            android:layout_width="fill_parent"
        
            android:layout_height="wrap_content"
        
            android:textSize="14sp"
        
            android:gravity="center"
        
            android:text="0"
        
            android:id="@+id/RX"/>
        
            </LinearLayout>
        
      3. 布局到位后,我们可以移动到 /src 文件夹。通过扩展 Activity 类创建 Main.java。让我们继续声明三个私有类变量。

      Main.java

           package com.authorwjf;
      
           import android.app.Activity;
      
           import android.app.AlertDialog;
      
           import android.net.TrafficStats;
      
           import android.os.Bundle;
      
           import android.os.Handler;
      
           import android.widget.TextView;
      
           public class Main extends Activity {
      
           private Handler mHandler = new Handler();
      
           private long mStartRX = 0;
      
           private long mStartTX = 0;
      
            }
      
      1. 我们将使用 on create override 来初始化我们的私有变量,并在 UI 线程上安排回调。记下对枚举 TrafficStats.UNSUPPORTED 的检查。虽然我对 TrafficStats 类的体验一帆风顺,但 Google 官方文档指出,某些设备可能不支持这种类型的报告,在这种情况下,调用会返回上述值。出于这个原因,防御性地编写代码是一个好主意,正如我在这里所展示的那样。

              Main.java
        
             @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);
        
             }
        
               }
        
      2. 最后但并非最不重要的一点是,我们需要更新显示并重新安排可运行文件。

              Main.java
        
              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);
        
                   }
        
                   };
        

      【讨论】:

      • 谢谢,但要获得非 WiFi 网络流量使用,我可以只使用 TrafficStats.getMobileTxBytes() 和TrafficStats.getMobileRxBytes()。还有就是不能让每个APP都使用3g,这才是我真正需要的。
      • 实际上它需要整个电话流量统计,对于应用程序使用情况我仍在尝试找到解决方案,如果我得到了,我会为你发布
      • 为此,我正在尝试另一种解决方案,即:1)检测 3G 是否打开 2)使用 TrafficStats 开始获取每个 APP 的流量计数 3)当 WiFi 打开时停止获取流量计数... ........另一个问题是如果3G和WiFi都打开了怎么办?还在摸索中......
      • 你能得到每个APP的TrafficStats吗?
      • 是的,但返回值是 3G 和 WiFi 计数的摘要。所以我决定在 3G 开启时数自己,在 3G 关闭时停止数。但是还是不知道怎么监听 3G ON/OFF 事件...
      猜你喜欢
      • 2011-11-09
      • 2012-02-12
      • 1970-01-01
      • 2011-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-05
      • 1970-01-01
      相关资源
      最近更新 更多