每个应用的安卓3G流量统计,如何实现?

15

统计每个应用程序的网络流量,我现在使用的是Android TrafficStats

我可以得到以下结果:

  • Youtube 50.30 MBytes
  • Facebook 21.39 MBytes
  • Google Play 103.38 MBytes
  • (等等...)

据我所知,“Android Trafficstats”只是一个指向C文件的本机指针(可能是.so文件)。

但它混合了Wifi和3G流量,有没有办法只获取非Wifi流量的统计数据呢?


你使用的是什么系统?从ICS开始,你可以查看3G/移动网络、WLAN或所有网络的数据使用情况。 - SunnySonic
4个回答

8
晚上好,我有一些方法可以做到这一点...
首先,我必须创建一个扩展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数据库中。
  2. 每1分钟通过TrafficStats收集所有应用程序的网络使用情况,仅当3G处于开启状态时。
  3. 如果3G关闭,则停止收集。
  4. 如果3G和WiFi都开启,则停止收集。

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


5

经过长时间的努力,我终于找到了在Android设备上获取每个安装应用程序的任何接口数据的解决方案。

尽管Android提供了TrafficStats API,但这些API仅提供自设备启动以来每个应用程序UID的编译数据统计,并且甚至不支持在特定应用程序上获取任何接口的数据。即使我们依靠TrafficStates API,我们也只能获得每个应用程序的新数据统计。

因此,我想使用隐藏的API来解决这个问题。

以下是在Android中获取每个应用程序在任何接口上的数据统计的步骤:

  1. Establish a "INetworkStatsSession" session

    import android.net.INetworkStatsSession;
    INetworkStatsSession mStatsSession = mStatsService.openSession();
    
  2. Create a Network Template according to interface which you want to measure..

    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 SubscriberID:

    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. Collect the network HIStory of respective application byt passing application UIDs...

    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. Get the total Consumption data:

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

您有这些内部类的链接吗?需要编译还是只需简单复制粘贴即可? - M. Reza Nasirloo
@Pedram,正如我在这个解决方案中提到的那样...我们正在使用内部API来实现这一点,因此我们必须将应用程序构建为系统应用程序,并在编译时引入所有相关的包。 - Anshuman

2

我找到了一种方法来获取仅限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总字节,对我有用,希望对你也有用。


-2

尝试以下代码,并关闭您的“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演示" />
    
         <TextView
    
         android:layout_width="fill_parent"
    
         android:layout_height="wrap_content"
    
         android:textSize="14sp"
    
         android:textColor="#00ff00"
    
         android:gravity="center"
    
         android:text="传输字节数" />
    
         <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="接收字节数" />
    
        <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”重写来初始化私有变量,以及在 UI 线程上调度回调。请注意 enum 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("噢哦!");
    
         alert.setMessage("您的设备不支持流量统计监控。");
    
         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()。此外,这无法获取每个应用程序的3G使用情况,而这正是我真正需要的。 - RRTW
实际上,它获取了整个手机的流量统计信息,至于应用程序的使用情况,我仍在努力寻找解决方案,如果我找到了,我会为您发布。 - G M Ramesh
您能否获取每个应用的流量统计数据? - G M Ramesh
是的,但返回值是3G和WiFi计数的摘要。所以我决定在3G开启时自己进行计数,并在3G关闭时停止计数。但仍然不知道如何监听3G开/关事件... - RRTW
@RRTW:实际上,当3G和WiFi都开启时,设备会优先选择WiFi。因此,您可以反转逻辑:如果WiFi打开,则getUidRxBytes(...)和getUidTxBytes(...)将返回WiFi流量,否则为3G。 - Paolo Rovelli
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接