Karl Jamoralin
Karl Jamoralin

Reputation: 1260

UI Hangs When While Loop is Placed Inside Runnable

I'm writing an app that will display the current download speed which will be updated every second. My Runnable class is able to update the UI with the value, but when I try to place it inside a loop so that it will continuously run and update the UI TextView every second, the app now hangs.

This is my MainActivity.java:

public class MainActivity extends Activity implements SpeedMeter.TaskRunnableSpeedMeterMethods{

    private Thread mSpeedMeterThread;
    private Handler mHandler;
    private TextView downloadSpeedOutput;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        downloadSpeedOutput = (TextView) findViewById(R.id.speed);

        mHandler = new Handler(Looper.getMainLooper()) {
            @Override
            public void handleMessage(Message inputMessage) {
                SpeedMeter speedMeter = (SpeedMeter) inputMessage.obj;
                downloadSpeedOutput.setText(Long.toString(speedMeter.getmDownloadSpeedKB()));
            }
        };

        SpeedMeter speedMeter = new SpeedMeter(this);
        speedMeter.run();

        // Creates an explicit intent for an Activity in your app
        Intent resultIntent = new Intent(this, MainActivity.class);

    }

    @Override
    public void setSpeedMeterThread(Thread currentThread) {
        mSpeedMeterThread = currentThread;
    }

    @Override
    public void setInternetSpeed(SpeedMeter speedMeter) {
        Message completeMessage = mHandler.obtainMessage(1, speedMeter);
        completeMessage.sendToTarget();
    }
}

And here's the other SpeedMeter.java:

public class SpeedMeter implements Runnable {

    final TaskRunnableSpeedMeterMethods mMainActivity;
    private long mDownloadSpeedKB;

    public SpeedMeter(TaskRunnableSpeedMeterMethods mainActivity) {
        mMainActivity = mainActivity;
    }

    @Override
    public void run() {

        mMainActivity.setSpeedMeterThread(Thread.currentThread());
        android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);

//        while(true) {

            long rxBytesPrevious = TrafficStats.getTotalRxBytes();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            long rxBytesCurrent = TrafficStats.getTotalRxBytes();

            long downloadSpeed = rxBytesCurrent - rxBytesPrevious;

            setmDownloadSpeedKB(downloadSpeed/1000);

            mMainActivity.setInternetSpeed(this);

//        }

    }

    public long getmDownloadSpeedKB() {
        return mDownloadSpeedKB;
    }

    public void setmDownloadSpeedKB(long mDownloadSpeedKB) {
        this.mDownloadSpeedKB = mDownloadSpeedKB;
    }

    interface TaskRunnableSpeedMeterMethods {
        void setSpeedMeterThread(Thread currentThread);
        void setInternetSpeed(SpeedMeter speedMeter);
    }

}

Any help will be appreciated!

Upvotes: 0

Views: 520

Answers (3)

dnl.d
dnl.d

Reputation: 1

I think your loop is always true so app hangs its better to create a boolean and use while(mboolean) and put this in your loop

if(something){
 mboolean=false;
}

you can also use CountDownTimer. for example:

new CountDownTimer(miliseconds,1000) 
//if you have download speed and download size you can find miliseconds
@Override
public void onTick(long l) {
//something you want to do every seconds
}
@Override
public void onFinish() {
//something you want to do on finish
}

Upvotes: 0

jtt
jtt

Reputation: 13541

The ideal way to do this would be to create an AsyncTask that would post a message to your UI thread, after it complete the task in the doInBackground() call.

Standards

also the interface structure you are following does not make sense and does not follow good standards. Usually an interface is used as a callback, which is basically what you are doing. But the standard is to say onSomethingChangedA() or onSomethingChangedB() from OnSomethingChangedListener interface.

Upvotes: 2

seven_seas
seven_seas

Reputation: 723

You didnt start your runnable as a new thread instead you called the run function like a normal function (so u do the while loop on ur UI thread which blocks it)

replace

speedMeter.run();<br />
SpeedMeter speedMeter = new SpeedMeter(this);


with

new Thread(new SpeedMeter(this)).start();

see https://docs.oracle.com/javase/tutorial/essential/concurrency/runthread.html for more infos on how to start a Runnable :)

Upvotes: 2

Related Questions