当While循环放置在Runnable内时,UI挂起

时间:2016-09-04 19:46:08

标签: android

我正在编写一个应用程序,它将显示当前下载速度,该速度将每秒更新一次。我的Runnable类能够使用值更新UI,但是当我尝试将其放在循环中以便它将连续运行并每秒更新UI TextView时,应用程序现在挂起。

这是我的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();
    }
}

这是另一个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);
    }

}

任何帮助将不胜感激!

3 个答案:

答案 0 :(得分:2)

你没有将runnable作为新线程启动,而是像普通函数一样调用run函数(所以你在你的UI线程上执行while循环来阻止它)

替换

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



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

请参阅https://docs.oracle.com/javase/tutorial/essential/concurrency/runthread.html了解有关如何启动Runnable的更多信息:)

答案 1 :(得分:2)

执行此操作的理想方法是创建一个AsyncTask,在doInBackground()调用中完成任务后,将消息发布到您的UI线程。

标准

您所遵循的界面结构也没有意义,也没有遵循良好的标准。通常,接口用作回调,这基本上就是你正在做的事情。但标准是从OnSomethingChangedListener接口说onSomethingChangedA()或onSomethingChangedB()。

答案 2 :(得分:0)

我认为你的循环总是正确的,所以app更好地创建一个布尔值并使用while(mboolean)并将它放在你的循环中

if(something){
 mboolean=false;
}

您也可以使用CountDownTimer。 例如:

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
}