Android UI线程和消息处理程序混淆

时间:2011-02-04 03:17:06

标签: android

下面的代码来自“Android Developer's Cookbook”一书的第58-61页。本书介绍了消息上下文中的代码,它是在线程之间传递信息的一种方式。它描述了代码:“计时器在后台线程中运行,因此它不会阻止UI线程,但只要时间发生变化,它就需要更新UI。”

我很困惑,因为我没有看到两个帖子。对我来说,似乎主UI线程将一个可运行的消息发布到它自己的消息队列(然后该消息以一个时间延迟重新发布自己)。我错过了什么吗?

package com.cookbook.background_timer;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class BackgroundTimer extends Activity {
    //keep track of button presses, a main thread task
    private int buttonPress=0;
    TextView mButtonLabel;

    //counter of time since app started, a background task
    private long mStartTime = 0L;
    private TextView mTimeLabel;

    //Handler to handle the message to the timer task
    private Handler mHandler = new Handler();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);        

        if (mStartTime == 0L) {
            mStartTime = SystemClock.uptimeMillis(); 
            mHandler.removeCallbacks(mUpdateTimeTask);
            mHandler.postDelayed(mUpdateTimeTask, 100);
        }

        mTimeLabel = (TextView) findViewById(R.id.text);
        mButtonLabel = (TextView) findViewById(R.id.trigger);

        Button startButton = (Button) findViewById(R.id.trigger);
        startButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view){
                mButtonLabel.setText("Pressed " + ++buttonPress + " times");
            }
        });        
    }

    private Runnable mUpdateTimeTask = new Runnable() {
        public void run() {
            final long start = mStartTime;
            long millis = SystemClock.uptimeMillis() - start;
            int seconds = (int) (millis / 1000);
            int minutes = seconds / 60;
            seconds     = seconds % 60;

            mTimeLabel.setText("" + minutes + ":" + String.format("%02d",seconds));
            mHandler.postDelayed(this, 200);
        }
    };

    @Override
    protected void onPause() {
        mHandler.removeCallbacks(mUpdateTimeTask);
        super.onPause();
    }

    @Override
    protected void onResume() {
        super.onResume();
        mHandler.postDelayed(mUpdateTimeTask, 100);
    }
}

4 个答案:

答案 0 :(得分:2)

第二个线程有点隐藏。当您在postDelayed(mUpdateTImeTask,100)中致电onCreate()时。处理程序中有一个线程,用于计算延迟时间(本例中为100毫秒),然后运行mUpdateTImeTask。请注意,在mUpdateTimeTask的run()方法的末尾,它通过再次调用postDelayed()将自身放回到处理程序的计时器线程中。

Android api有许多类,如Handler和AsyncTask,可以更轻松地进行多线程处理。这些类隐藏了许多线程的细节(这使得它们很好用)。不幸的是,这使得很难了解正在发生的事情 - 你必须知道发生了什么才能学习它。 :)

答案 1 :(得分:0)

Runnable类本质上是一个用于线程的类。 run()方法将由调用它的接口(Handler)调用,并且 - 在此实现中 - 应用程序将Handler设置为在此之后运行mUpdateTimeTask 100ms行已执行。然后,您将在run() Runnable方法中运行所有内容。

调用onCreate()后,您的应用会从视图中获取mTimeLabel对象,并使用setText()中的Runnable方法进行更新。这将更新UI线程上的时间,然后将其自身注册为另外200毫秒。

答案 2 :(得分:0)

这里没有第二个帖子!您可以通过在runnable中放入一些昂贵的代码来轻松测试,这将阻止UI线程。你必须做一个new Thread(Runnable)并从那里开始。

答案 3 :(得分:0)

这几乎是每个项目都需要的。我必须在我的开源Aniqroid库中添加一个Timer类,它在UI线程中被触发并利用Handler.postDelayed()功能,而不必编写所有的样板代码。

http://aniqroid.sileria.com/doc/api/(查看底部的下载内容或使用Google代码项目查看更多下载选项:http://code.google.com/p/aniqroid/downloads/list

课程文档在这里:http://aniqroid.sileria.com/doc/api/com/sileria/android/Timer.html