Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
839 views
in Technique[技术] by (71.8m points)

multithreading - What is recommended way to update android ui from a -continuous- background thread?

I've read well enough on the subject to get well and thoroughly confused. I'm doing a workout tracker app such as RunKeeper, which tracks how long and how far the user has been say, running. I'm in the process of programming the main interface of this "workout" which shows a stopwatch-like layout which includes both a timer showing the time which is updated every second, and a counter showing how far he's run so far.

My problem is updating the interface. I have a stopwatch class keeping track of the time, and I calculate the distance based on gps locations, but I'm at a loss to find the recommended way to run a continuous thread in the background that updates the ui on a fixed time rate.

As far as I've been able to tell, I should either be implementing the Handler.Callback interface in the activity class, or have a separate Callback object together with a Thread, but I'm sort of at a loss on how to get it all to work together. I both need to update the time shown that I get from my stopwatch class (simple start/stop time calculation, nothing thread-related), and the distance calculated based on the locations received in onLocationChanged().

Here's a stripped down version of my Activity code:

public class WorkoutActivity extends Activity implements OnClickListener, LocationListener
{
    private LocationManager locManager;
    private boolean workoutStarted = false;

    // The TextViews to update
    private TextView timeLabel;
    private TextView distanceLabel;

    private Stopwatch stopwatch;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        /*
            ... Interface initialisation
        */
        stopwatch = new Stopwatch();
    }

    private void startWorkout() {/* ...*/}
    private void stopWorkout()  {/* ...*/}
    private void pauseWorkout() {/* ...*/}
    private void resumeWorkout(){/* ...*/}
    public void onClick(View v) {/* ...*/}
    public void onLocationChanged(Location location){/* ...*/}
}

According to most answers I've read around here I should use a Handler object extending the handleMessage method, but nowadays (at least according to the warning in Lint) you have to make such objects static to avoid memory leaks. That however, makes it a bit strange to directly access and change the other private objects in the activity class from within the Handler. I suppose you could solve this by making the objects you need to affect parameters in a class extending Handler, but I dunno, it feels like a bit of a "hack" (nested class within WorkoutActivity):

static class TimeHandler extends Handler
{
    static final int MSG_START_TIMER = 1;
    static final int MSG_UPDATE_TIMER = 2;
    static final int MSG_STOP_TIMER = 3;

    private static final int REFRESH_RATE = 1000;

    private Stopwatch stopwatch;
    private TextView timeLabel;

    public TimeHandler(Stopwatch stopwatch, TextView label)
    {
        this.stopwatch = stopwatch;
        this.timeLabel = label;
    }

    @Override
    public void handleMessage(Message msg)
    {
        super.handleMessage(msg);

        switch(msg.what)
        {
            case MSG_START_TIMER:
                stopwatch.start();
                this.sendEmptyMessage(MSG_UPDATE_TIMER);
                break;
            case MSG_UPDATE_TIMER:
                timeLabel.setText(stopwatch.getElapsedTimeString());
                this.sendEmptyMessageDelayed(MSG_UPDATE_TIMER, REFRESH_RATE);
                break;
            case MSG_STOP_TIMER:
                this.removeMessages(MSG_UPDATE_TIMER);
                stopwatch.stop();
                timeLabel.setText(stopwatch.getElapsedTimeString());
                break;
        }           
    }

So, could anyone please explain the "standard" way of updating the UI from a continuous background thread? Oh, and sorry for the long question, just wanted to be thorough.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Use runOnUiThread().

Define a Runnable:

private Runnable mRunnable = new Runnable() {
    @Override
    public void run() {
        mTextViewOne.setText("10 miles!");
        mTextViewTwo.setText("40 minutes!");
    }
};

Inside your continuous thread:

runOnUiThread(mRunnable);

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...