简体   繁体   English

Android 定时器更新 textview (UI)

[英]Android timer updating a textview (UI)

I'm using a timer to create a stop watch.我正在使用计时器来创建秒表。 The timer works by increasing a integer value.计时器通过增加 integer 值来工作。 I want to then display this value in the activity by constantly updating a textview.然后我想通过不断更新 textview 在活动中显示这个值。

Here's my code from the service where I try and update the activity's textview:这是我尝试更新活动的 textview 的服务中的代码:

protected static void startTimer() {
    isTimerRunning = true; 
    timer.scheduleAtFixedRate(new TimerTask() {
        public void run() {
            elapsedTime += 1; //increase every sec
            StopWatch.time.setText(formatIntoHHMMSS(elapsedTime)); //this is the textview
        }
    }, 0, 1000);
}

I got some kind of error about updating the UI in the wrong thread.我在错误的线程中更新 UI 时遇到了某种错误。

How can I adapt my code to accomplish this task of constantly updating the textview?如何调整我的代码以完成不断更新 textview 的任务?

protected static void startTimer() {
    isTimerRunning = true; 
    timer.scheduleAtFixedRate(new TimerTask() {
        public void run() {
            elapsedTime += 1; //increase every sec
            mHandler.obtainMessage(1).sendToTarget();
        }
    }, 0, 1000);
}

public Handler mHandler = new Handler() {
    public void handleMessage(Message msg) {
        StopWatch.time.setText(formatIntoHHMMSS(elapsedTime)); //this is the textview
    }
};

Above code will work...上面的代码将工作...

Note: Handlers must be created in your main thread so that you can modify UI content.注意:处理程序必须在您的主线程中创建,以便您可以修改 UI 内容。

You should use Handler instead to update UI every X seconds.您应该使用Handler每 X 秒更新一次 UI。 Here is another question that show an example: Repeat a task with a time delay?这是另一个显示示例的问题: 重复一个有时间延迟的任务?

Your approach doesn't work because you are trying to update UI from non-UI thread.您的方法不起作用,因为您正在尝试从非 UI 线程更新 UI。 This is not allowed.这是不允许的。

StopWatch.time.post(new Runnable() {
    StopWatch.time.setText(formatIntoHHMMSS(elapsedTime));
});

this code block is based on Handler but you don't need to create your own Handler instance.此代码块基于 Handler,但您不需要创建自己的 Handler 实例。

You can use the following utility:您可以使用以下实用程序:

/**
 * Created by Ofek on 19/08/2015.
 */
public class TaskScheduler extends Handler {
    private ArrayMap<Runnable,Runnable> tasks = new ArrayMap<>();
    public void scheduleAtFixedRate(final Runnable task,long delay,final long period) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                task.run();
                postDelayed(this, period);
            }
        };
        tasks.put(task, runnable);
        postDelayed(runnable, delay);
    }
    public void scheduleAtFixedRate(final Runnable task,final long period) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                task.run();
                postDelayed(this, period);
            }
        };
        tasks.put(task, runnable);
        runnable.run();
    }
    public void stop(Runnable task) {
        Runnable removed = tasks.remove(task);
        if (removed!=null) removeCallbacks(removed);
    }

}

Then anywhere in code that runs by the UI Thread you can use it simply like this:然后在由 UI 线程运行的代码中的任何地方,您都可以像这样简单地使用它:

TaskScheduler timer = new TaskScheduler();
        timer.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                time.setText(simpleDateFormat.format(GamePlay.instance().getLevelTime()));
            }
        },1000);

you can use Handler .你可以使用处理程序。

this code increase a counter every one second and show and update counter value on a textView .此代码每秒增加一个计数器,并在textView显示和更新计数器值。

public class MainActivity extends Activity {


    private Handler handler = new Handler();
    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView) findViewById(R.id.text);
        startTimer();
    }


    int i = 0;
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            i++;
            textView.setText("counter:" + i);
            startTimer();
        }
    };

    public void startTimer() {
        handler.postDelayed(runnable, 1000);
    }

    public void cancelTimer() {
        handler.removeCallbacks(runnable);
    }

    @Override
    protected void onStop() {
        super.onStop();
        handler.removeCallbacks(runnable);
    }
}

TimerTask implements Runnable, which would make it a thread. TimerTask 实现了 Runnable,这将使它成为一个线程。 You can not update the main UI thread directly from a different thread without some work.如果不做一些工作,您无法直接从不同的线程更新主 UI 线程。 One thing you could do is use Async Task to create the timer and publish an update every second that will update the UI.您可以做的一件事是使用 Async Task 创建计时器并每秒发布一次更新,以更新 UI。

I'm assuming StopWatch.time is some static or public reference to your TextView.我假设StopWatch.time是一些 static 或对您的 TextView 的公共引用。 Instead of doing this, you should implement a BroadcastReceiver to communicate between your timer (which runs from a separate thread) and your TextView.而不是这样做,您应该实现BroadcastReceiver以在您的计时器(从单独的线程运行)和您的 TextView 之间进行通信。

I use this way:我用这种方式:

String[] array = {"man", "for", "think"}; 
int j;

Then add more onCreate :然后添加更多onCreate

TextView t = findViewById(R.id.textView);

new CountDownTimer(5000,1000) {

    @Override
    public void onTick(long millisUntilFinished) {}

    @Override
    public void onFinish() {
        t.setText("I " + array[j] + " You");
        j++;
        if (j == array.length - 1) j = 0;
        start();
    }
}.start();
 timer.schedule(new TimerTask() {
            @Override
            public void run() {

                //your actions

            }
        },1*1000);//1 sec

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM