How to detect upload/download transfer rate in Android?

后端 未结 3 1465
借酒劲吻你
借酒劲吻你 2020-12-30 17:20

I am working on an app which uploads a large amount of data. I want to determine the transfer rate of the upload, to show in a notification.

  • One post suggests
相关标签:
3条回答
  • 2020-12-30 17:58

    What you're trying to determine is the transfer rate of the bytes being uploaded over your HTTP Client. Obviously, this depends on the HTTP client you're using.

    There's no out-of-the-box solution which applies to all HTTP clients used on Android. The Android SDK does not provide any methods for you to determine the transfer rate of a particular upload.

    Fortunately, you're using OKHttp and there is a relatively straight-forward way to do this. You're going to have to implement a custom RequestBody, and observe the bytes being written to the buffer when the request is in flight.

    There's a 'recipe' for doing this on the OkHttp Github: https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/Progress.java

    You could also refer to this StackOverflow question dealing with the exact same topic: Tracking progress of multipart file upload using OKHTTP

    Another here: OKHTTP 3 Tracking Multipart upload progress

    0 讨论(0)
  • 2020-12-30 18:07

    It is feasible to obtain the transferred traffic amount using android.net.TrafficStats. Here is an implementation of this idea which measures the up-stream and down-stream transfer rate. You can measure the rate of mobile network by passing TrafficSpeedMeasurer.TrafficType.MOBILE to the TrafficSpeedMeasurer constructor, otherwise using TrafficSpeedMeasurer.TrafficType.ALL will result in measuring general traffic (WiFi/Mobile). Also by setting SHOW_SPEED_IN_BITS = true in MainActivity you can change the unit of speed measuring to bits per second.

    MainActivity.java

    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.widget.TextView;
    
    public class MainActivity extends AppCompatActivity {
    
        private static final boolean SHOW_SPEED_IN_BITS = false;
    
        private TrafficSpeedMeasurer mTrafficSpeedMeasurer;
        private TextView mTextView;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mTextView = findViewById(R.id.connection_class);
    
            mTrafficSpeedMeasurer = new TrafficSpeedMeasurer(TrafficSpeedMeasurer.TrafficType.ALL);
            mTrafficSpeedMeasurer.startMeasuring();
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            mTrafficSpeedMeasurer.stopMeasuring();
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            mTrafficSpeedMeasurer.removeListener(mStreamSpeedListener);
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            mTrafficSpeedMeasurer.registerListener(mStreamSpeedListener);
        }
    
        private ITrafficSpeedListener mStreamSpeedListener = new ITrafficSpeedListener() {
    
            @Override
            public void onTrafficSpeedMeasured(final double upStream, final double downStream) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        String upStreamSpeed = Utils.parseSpeed(upStream, SHOW_SPEED_IN_BITS);
                        String downStreamSpeed = Utils.parseSpeed(downStream, SHOW_SPEED_IN_BITS);
                        mTextView.setText("Up Stream Speed: " + upStreamSpeed + "\n" + "Down Stream Speed: " + downStreamSpeed);
                    }
                });
            }
        };
    
    }
    

    TrafficSpeedMeasurer.java

    import android.net.TrafficStats;
    import android.os.Handler;
    import android.os.HandlerThread;
    import android.os.Looper;
    import android.os.Message;
    import android.os.SystemClock;
    
    
    public class TrafficSpeedMeasurer {
    
        private ITrafficSpeedListener mTrafficSpeedListener;
        private SamplingHandler mHandler;
    
        private TrafficType mTrafficType;
        private long mLastTimeReading;
        private long mPreviousUpStream = -1;
        private long mPreviousDownStream = -1;
    
        public TrafficSpeedMeasurer(TrafficType trafficType) {
            mTrafficType = trafficType;
            HandlerThread thread = new HandlerThread("ParseThread");
            thread.start();
            mHandler = new SamplingHandler(thread.getLooper());
        }
    
        public void registerListener(ITrafficSpeedListener iTrafficSpeedListener) {
            mTrafficSpeedListener = iTrafficSpeedListener;
        }
    
        public void removeListener(ITrafficSpeedListener iTrafficSpeedListener) {
            mTrafficSpeedListener = iTrafficSpeedListener;
        }
    
        public void startMeasuring() {
            mHandler.startSamplingThread();
            mLastTimeReading = SystemClock.elapsedRealtime();
        }
    
        public void stopMeasuring() {
            mHandler.stopSamplingThread();
            finalReadTrafficStats();
        }
    
        private void readTrafficStats() {
            long newBytesUpStream = (mTrafficType == TrafficType.MOBILE ? TrafficStats.getMobileTxBytes() : TrafficStats.getTotalTxBytes()) * 1024;
            long newBytesDownStream = (mTrafficType == TrafficType.MOBILE ? TrafficStats.getMobileRxBytes() : TrafficStats.getTotalRxBytes()) * 1024;
    
            long byteDiffUpStream = newBytesUpStream - mPreviousUpStream;
            long byteDiffDownStream = newBytesDownStream - mPreviousDownStream;
    
            synchronized (this) {
                long currentTime = SystemClock.elapsedRealtime();
                double bandwidthUpStream = 0;
                double bandwidthDownStream = 0;
    
                if (mPreviousUpStream >= 0) {
                    bandwidthUpStream = (byteDiffUpStream) * 1.0 / (currentTime - mLastTimeReading);
                }
                if (mPreviousDownStream >= 0) {
                    bandwidthDownStream = (byteDiffDownStream) * 1.0 / (currentTime - mLastTimeReading);
                }
                if (mTrafficSpeedListener != null) {
                    mTrafficSpeedListener.onTrafficSpeedMeasured(bandwidthUpStream, bandwidthDownStream);
                }
    
                mLastTimeReading = currentTime;
            }
    
            mPreviousDownStream = newBytesDownStream;
            mPreviousUpStream = newBytesUpStream;
        }
    
        private void finalReadTrafficStats() {
            readTrafficStats();
            mPreviousUpStream = -1;
            mPreviousDownStream = -1;
        }
    
        private class SamplingHandler extends Handler {
    
            private static final long SAMPLE_TIME = 1000;
            private static final int MSG_START = 1;
    
            private SamplingHandler(Looper looper) {
                super(looper);
            }
    
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case MSG_START:
                        readTrafficStats();
                        sendEmptyMessageDelayed(MSG_START, SAMPLE_TIME);
                        break;
                    default:
                        throw new IllegalArgumentException("Unknown what=" + msg.what);
                }
            }
    
            void startSamplingThread() {
                sendEmptyMessage(SamplingHandler.MSG_START);
            }
    
            void stopSamplingThread() {
                removeMessages(SamplingHandler.MSG_START);
            }
    
        }
    
        public enum TrafficType {
            MOBILE,
            ALL
        }
    
    }
    

    ITrafficSpeedListener.java

    public interface ITrafficSpeedListener {
    
        void onTrafficSpeedMeasured(double upStream, double downStream);
    }
    

    Utils.java

    import java.util.Locale;
    
    public class Utils {
    
        private static final long B = 1;
        private static final long KB = B * 1024;
        private static final long MB = KB * 1024;
        private static final long GB = MB * 1024;
    
        public static String parseSpeed(double bytes, boolean inBits) {
            double value = inBits ? bytes * 8 : bytes;
            if (value < KB) {
                return String.format(Locale.getDefault(), "%.1f " + (inBits ? "b" : "B") + "/s", value);
            } else if (value < MB) {
                return String.format(Locale.getDefault(), "%.1f K" + (inBits ? "b" : "B") + "/s", value / KB);
            } else if (value < GB) {
                return String.format(Locale.getDefault(), "%.1f M" + (inBits ? "b" : "B") + "/s", value / MB);
            } else {
                return String.format(Locale.getDefault(), "%.2f G" + (inBits ? "b" : "B") + "/s", value / GB);
            }
        }
    
    }
    

    .

    Visual Result

    0 讨论(0)
  • 2020-12-30 18:07

    I am talking in the context of your app since this makes it easier to capture the real time speed of your uploaded data. You don't need any extra libraries or sdk api's.

    You are presumably uploading the data in chunks to the server. So

    a) You know the data size of each packet
    b) You know the start time before sending the packet / before sending multiple packets
    c) You know the end time of xy packets by the server response e.g. status 200

    With that you have all parameters to calculate the upload speed

    double uploadSpeed = packet.size / (endTime - startTime) // time * 1000 to have it in seconds

    EDIT:

    Since you are using MultiPart from OkHttp you can monitor the amount of bytes uploaded. Tracking progress of multipart file upload using OKHTTP. You would replace packet.size with the current uploaded amount and the endTime would be an interval of xy seconds.

    0 讨论(0)
提交回复
热议问题