簡體   English   中英

Android,我該如何從私有內部類(即AsyncTask)更新視圖元素

[英]Android, how can i update a view element from a private inner class which is an AsyncTask

我正在做一個android應用程序作為學校作業的一部分。

我需要能夠在hh:mm:ss顯示一個計時器,並每秒更新一次計時器。

我設法提出了我認為會產生所需結果的代碼,但是我無法使AsyncTask每秒執行一次。 這是我當前的代碼:

TimerHand timerHand = new TimerHandling(timerTextView);
Timer timer = new Timer();
    timer.scheduleAtFixedRate(new TimerTask() {

            public void run() {
                timerHand.execute();

            } },1000, 1000); // 1000ms == 1 second

這是Async任務,這是一個包含上述代碼以及TextView tv聲明的類中的嵌套類:

   class TimerHandling  extends AsyncTask<Void, Void, Void>{

        private long secs, mins, hours, millis;
        private String timeString;
        private TextView tv;
        private long startTime;
        private boolean stop;
        private Handler handler;

        public TimerHandling(TextView tv){
            this.tv = tv;
            startTime = System.currentTimeMillis();
            stop = false;
            handler = new Handler();

        }

        @Override
        protected Void doInBackground(Void... params) {
            while(stop != true){
                millis = System.currentTimeMillis() - startTime;
                hours += TimeUnit.MILLISECONDS.toHours(millis);
                mins +=  TimeUnit.MILLISECONDS.toMinutes(millis) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis));
                secs += TimeUnit.MILLISECONDS.toSeconds(millis) - TimeUnit.MILLISECONDS.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis));     

                timeString = String.format("%02d:%02d:%02d",hours, mins, secs);
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        tv.setText(timeString);
                    }
                });
            }
            return null;
        }

        public void setStopCondition(boolean condition){

            this.stop = condition;
        }
    }
        }

它產生以下logCat輸出:

01-23 18:00:27.865: E/AndroidRuntime(14458): FATAL EXCEPTION: AsyncTask #5
01-23 18:00:27.865: E/AndroidRuntime(14458): Process: dcs.aber.ac.uk.cs211.group02, PID: 14458
01-23 18:00:27.865: E/AndroidRuntime(14458): java.lang.RuntimeException: An error occured while executing doInBackground()
01-23 18:00:27.865: E/AndroidRuntime(14458):    at android.os.AsyncTask$3.done(AsyncTask.java:300)
01-23 18:00:27.865: E/AndroidRuntime(14458):    at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
01-23 18:00:27.865: E/AndroidRuntime(14458):    at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
01-23 18:00:27.865: E/AndroidRuntime(14458):    at java.util.concurrent.FutureTask.run(FutureTask.java:242)
01-23 18:00:27.865: E/AndroidRuntime(14458):    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
01-23 18:00:27.865: E/AndroidRuntime(14458):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
01-23 18:00:27.865: E/AndroidRuntime(14458):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
01-23 18:00:27.865: E/AndroidRuntime(14458):    at java.lang.Thread.run(Thread.java:841)
01-23 18:00:27.865: E/AndroidRuntime(14458): Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
01-23 18:00:27.865: E/AndroidRuntime(14458):    at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6094)
01-23 18:00:27.865: E/AndroidRuntime(14458):    at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:824)
01-23 18:00:27.865: E/AndroidRuntime(14458):    at android.view.View.requestLayout(View.java:16431)
01-23 18:00:27.865: E/AndroidRuntime(14458):    at android.view.View.requestLayout(View.java:16431)
01-23 18:00:27.865: E/AndroidRuntime(14458):    at android.view.View.requestLayout(View.java:16431)
01-23 18:00:27.865: E/AndroidRuntime(14458):    at android.view.View.requestLayout(View.java:16431)
01-23 18:00:27.865: E/AndroidRuntime(14458):    at android.widget.RelativeLayout.requestLayout(RelativeLayout.java:352)
01-23 18:00:27.865: E/AndroidRuntime(14458):    at android.view.View.requestLayout(View.java:16431)
01-23 18:00:27.865: E/AndroidRuntime(14458):    at android.widget.TextView.checkForRelayout(TextView.java:6600)
01-23 18:00:27.865: E/AndroidRuntime(14458):    at android.widget.TextView.setText(TextView.java:3813)
01-23 18:00:27.865: E/AndroidRuntime(14458):    at android.widget.TextView.setText(TextView.java:3671)
01-23 18:00:27.865: E/AndroidRuntime(14458):    at android.widget.TextView.setText(TextView.java:3646)

我知道這是由於嵌套類具有不同的View導致的,因此它無法更新TextView,我該如何克服呢?

當我運行我的代碼時,我可以看到它正在執行,大約2秒鍾后,該應用程序將因發布的錯誤消息而崩潰。

更新:

公共無效startCountingTimer(){

final Handler handler = new Handler();
final Runnable task = new Runnable() 

{ 
    @Override
    public void run() {

        millis = System.currentTimeMillis() - startTime;
        hours += TimeUnit.MILLISECONDS.toHours(millis);
        mins +=  TimeUnit.MILLISECONDS.toMinutes(millis) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis));
        secs += TimeUnit.MILLISECONDS.toSeconds(millis) - TimeUnit.MILLISECONDS.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis));     

        timeString = String.format("%02d:%02d:%02d",hours, mins, secs);
        handler.postDelayed(task, 1000); //problem on this line
    }
};
task.run();   

}

我已經指出了單行注釋的問題,“任務”未聲明。

Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

您嘗試從非ui線程更新ui,這是不可能的。 您應該從ui線程更新ui。

Timer在其他線程上運行。

另請閱讀線程規則@ http://developer.android.com/reference/android/os/AsyncTask.html

 I need to be able to display a timer in hh:mm:ss and update the timer every second.

您可以使用HandlerCountDownTimer

Handler程序與創建它的線程相關聯。

http://developer.android.com/reference/android/os/Handler.html

Handler m_handler;
Runnable m_handlerTask ; 
m_handler = new Handler(); 
m_handlerTask = new Runnable() 
{ 
@Override
public void run() {
   // do something
  m_handler.postDelayed(m_handlerTask, 1000); 
 }
 };
 m_handlerTask.run();   

對於倒數計時器

倒數計時器,以分鍾和秒為單位

編輯:

public class MainActivity extends Activity {

      Handler handler;
      Runnable task ;
      @Override
      protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        startCountingTimer();

}
      public void startCountingTimer() {

       handler = new Handler();
       task = new Runnable() 
          { 
              @Override
              public void run() {
                      // do something
                  handler.postDelayed(task, 1000); 
              }
          };
          task.run();   
          }  
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM