Как получить правильное количество байтов, отправленных и полученных в TrafficStats?

Мое приложение пытается подсчитать количество байтов, отправляемых и полученных по WiFi/LAN и мобильным соединениям данных. Для этого я получаю значения счетчиков TrafficStats в один момент времени и вычитаю из своих значений при следующем проверке.

// get current values of counters
long currentMobileTxBytes = TrafficStats.getMobileTxBytes();
long currentMobileRxBytes = TrafficStats.getMobileRxBytes();
long totalTxBytes = TrafficStats.getTotalTxBytes();
long totalRxBytes = TrafficStats.getTotalRxBytes();

// to get mobile data count, subtract old from current
long currentMobileSent = currentMobileTxBytes - oldMobileTxBytes;
long currentMobileReceived = currentMobileRxBytes - oldMobileRxBytes;

// to get WiFi/LAN data count, subtract total from mobile
long currentNetworkSent = totalTxBytes - currentMobileTxBytes;
long currentNetworkReceived = totalRxBytes - currentMobileRxBytes;

Я считаю, что приведенный выше алгоритм является разумным, однако я не уверен, как проверить точность этих счетчиков. Например, когда я попытался загрузить 2,7 МБ файл в Dropbox через WiFi, значение currentMobileSent, которое я получил, составляло около 10 МБ. И даже без серфинга в сети до следующей проверки я получаю ненулевые значения, указывающие, что я получил несколько байтов данных за период ожидания.

Есть ли способ проверить, как TrafficStats поступает на эти цифры? Я знаю, что помимо моего браузера могут быть другие приложения, работающие в фоновом режиме, которые подключаются к Интернету, но от 2,7 МБ до 10 МБ просто кажется огромным прыжком - я даже "получил" 90 МБ один раз, ничего не делая. Или что-то не так с тем, как я вычисляю байты, отправленные и полученные?

Ответ 1

От TechRepublic:

  • Создайте новый проект Android в Eclipse. Не забудьте использовать класс TrafficStats, для которого вы должны настроить API для Android 2.2 (Froyo) или выше.

  • В папке /res/layout мы создадим ресурс activity_main.xml. Для этого проекта мы просто используем серию текстовых представлений в вертикальном сложенная линейная компоновка.

activity_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:gravity="center"
       android:paddingBottom="20dip"
       android:text="Traffic Stats Demo"
       android:textSize="16sp"
       android:textStyle="bold" />

   <TextView
       android:layout_width="fill_parent"
       android:layout_height="wrap_content"
       android:gravity="center"
       android:text="Transmit Bytes"
       android:textColor="#00ff00"
       android:textSize="14sp" />

   <TextView
       android:id="@+id/TX"
       android:layout_width="fill_parent"
       android:layout_height="wrap_content"
       android:gravity="center"
       android:text="0"
       android:textSize="14sp" />

   <TextView
       android:layout_width="fill_parent"
       android:layout_height="wrap_content"
       android:gravity="center"
       android:text="Receive Bytes"
       android:textColor="#ff0000"
       android:textSize="14sp" />

   <TextView
       android:id="@+id/RX"
       android:layout_width="fill_parent"
       android:layout_height="wrap_content"
       android:gravity="center"
       android:text="0"
       android:textSize="14sp" />
</LinearLayout>

С нашей компоновкой на месте мы можем перейти в папку /src. Создайте MainActivity.java, расширив класс Activity/AppCompatActivity. Давайте также продолжим и объявить три переменные частного класса.

MainActivity.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;
}

Мы будем использовать функцию create override для инициализации нашего частного переменные, а также запланировать обратный вызов в потоке пользовательского интерфейса. Делать примечание проверки для перечисления TrafficStats.UNSUPPORTED. Хотя моя опыт работы с классом TrafficStats прошел без задержек, официальная документация Google утверждает, что некоторые устройства могут не поддерживать этот тип отчетности, и в этом случае вызов возвращает вышеупомянутое значение. По этой причине хорошая идея написать защищайте код, как показано здесь Ive.

MainActivity.java

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_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);
    }
}

Наконец, не в последнюю очередь нам нужно обновить наш дисплей и перенести работоспособной.

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