【问题标题】:Updating time through implementation Runnable [duplicate]通过实现Runnable更新时间[重复]
【发布时间】:2017-10-14 17:35:47
【问题描述】:

我决定简化更新时间算法。到处通过Timer编写算法。但是如果你在主Activity中实现Runnable接口,就可以避免创建额外的对象。

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

我已经伤透了脑筋。 请帮帮我:(

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);
    }
}

【问题讨论】:

  • 相关? stackoverflow.com/questions/9884246 在调用 tv.setText 之前尝试记录。我怀疑那里抛出了异常
  • 我没有得到任何异常。或者日志不显示或者重新显示时间。
  • ScheduledExecutorService 抑制异常。更重要的是,在一次异常之后,runnable 默认情况下是未调度的。将你的 run 方法体包装在一个 try-catch 中并自己记录它,看看是否会发生这种情况。
  • Я выталкивал каждую секунду。 Сделал обертку исключения。 Теперь метод 运行 выглядит так: try {// мониторим код time = sdf.format (новая дата (System.currentTimeMillis ())); Log.d (TAG, время); tv.setText (время); } catch (RuntimeException e) {Log.d (TAG, "" + e); } Log.d (TAG, "1"); 我收到异常 1 次。 “android.view.ViewRootImpl$CalledFromWrongThreadException:只有创建视图层次结构的原始线程才能触及其视图。” 我该如何解决这个问题?链接呢?还是怎么做?
  • @worldsender 谢谢你,你帮助了我。我取消了禁食。

标签: java android time runtime


【解决方案1】:

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

Documentation for ScheduledExecutorService

如果任务的任何执行遇到异常,后续执行将被抑制

有一个看似矛盾的事情需要解释:它只工作一次。这是因为您的初始延迟是0。反过来,这意味着调用ScheduledExecutorService#scheduleAtFixedRate 时可能会同步运行第一次执行。


要解决这个问题,你必须从你的主线程调用tv.setText(time)。怎么做,可以在this question找到。

【讨论】:

    【解决方案2】:

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

    通过 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");
        }
    }
    

    【讨论】:

      【解决方案3】:

      我不适用于 android 但...run() 正在按原样处理...
      仅一次除非您使用:

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

      【讨论】:

      • 这个答案是错误的。 ScheduledExecutorService#scheduleAtFixedRate 应该负责重复执行
      • 我有一个函数 (scheduleAtFixedRate) 每秒执行一次 Run 方法。对我来说,一个循环不断的循环。
      猜你喜欢
      • 1970-01-01
      • 2011-02-16
      • 2023-03-18
      • 1970-01-01
      • 1970-01-01
      • 2015-04-01
      • 1970-01-01
      • 2011-01-22
      • 1970-01-01
      相关资源
      最近更新 更多