通过实现Runnable更新时间

时间:2017-10-14 17:35:47

标签: java android time runtime

我决定简化更新时间算法。无处不在通过计时器编写算法。但是,如果在主活动中实现 Runnable 接口,则可以避免创建额外的对象。

当我打开激活时我想要它,时间每秒更新一次。但这不会发生。 通过我创建的标签(ITTERATION),只有一次迭代。 使用HERE

中的示例

Screenshot of phone preview and logs

我已经打破了我的大脑。 请帮帮我:(

package pac.twoproject;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

public class Main2Activity extends AppCompatActivity implements Runnable {

    private static final String TAG = "ITTERATION";
    TextView tv;
    String time;

    final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");

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

        tv = (TextView) findViewById(R.id.textView);
        //scheduler.scheduleAtFixedRate(this, 0, 10, TimeUnit.MILLISECONDS);
    }

    @Override 
    protected void onResume() {
        super.onResume();

        scheduler.scheduleAtFixedRate(this, 0, 1000, TimeUnit.MILLISECONDS);
    }

    @Override
    public void run() {
        time = sdf.format(new Date(System.currentTimeMillis()));
        tv.setText(time);
        Log.d(TAG, time);
    }
}

3 个答案:

答案 0 :(得分:0)

您只能从应用程序的主线程(GUI线程)修改View。在您的情况下,当ScheduledExecutorService调用run时,它将在另一个线程中执行此操作。结果是tv.setText(time);抛出CalledFromWrongThreadException。反过来,调度程序看到Runnable引发了异常,将抑制未来的执行:

  

Documentation for ScheduledExecutorService

     

如果任务的任何执行遇到异常,则后续执行被禁止

有一个看似矛盾的东西需要解释:它有效一次。这是因为您的初始延迟为0。反过来,这意味着在调用ScheduledExecutorService#scheduleAtFixedRate时可以同步运行第一次执行。

要解决此问题,您必须从主线程中调用tv.setText(time)。如何执行此操作,可以在this question中找到。

答案 1 :(得分:0)

管理员帮助 @WorldSEnder !谢谢! 有一个异常" android.view.ViewRootImpl $ CalledFromWrongThreadException:只有创建视图层次结构的原始线程才能触及其视图" 。函数 scheduleAtFixedRate 调用的新线程无法更新文本字段中的文本。 通过处理程序解决了这个问题。

通过Timer实现它更容易,更优化。 或者你知道如何优化它吗?

package pac.twoproject;

import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;


public class Main2Activity extends AppCompatActivity implements Runnable {

    private static final String TAG = "ITTERATION";
    TextView tv;
    String time;
    Handler h;

    final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");

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

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

        h = new Handler() { //создаем наш хендл, в котором пропишем получение из очереди сообщения и обновление нашей переменной
            public void handleMessage(Message msg) {
                Bundle bundle = msg.getData(); // достаем их сообщение наш бондаж
                String text = bundle.getString("key"); // из бондажа уже наше сообщение
                tv.setText(text);
            }
        };

        scheduler.scheduleAtFixedRate(this, 0, 1000, TimeUnit.MILLISECONDS); // функция которая запускает метод ран в новом потоке и повторяем его запуск каждую секунду
    }


    @Override
    public void run() {

        try { // мониторим код
            time = sdf.format(new Date(System.currentTimeMillis())); // считываем время
            Log.d(TAG, time); // пишем его лог

            Message msg = Message.obtain(); // создаем новое сообщение
            Bundle bundle = new Bundle(); // создаем новый сверток (бандаж)
            bundle.putString("key", time); // в него пихаем по ключу наше время (текст)
            msg.setData(bundle); // и уже бондаж запихиваем в сообщение
            h.sendMessage(msg); //отправляем сообщение
        } catch (RuntimeException e) {
            Log.d(TAG, ""+ e);
        }
        Log.d(TAG, "1");
    }
}

答案 2 :(得分:-1)

我不适用于android但是...... run()正在处理,因为它是... 仅一次,除非您使用:

while (true) {
    time = sdf.format(new Date(System.currentTimeMillis()));
    tv.setText(time);
    Log.d(TAG, time);
}