2011-03-21 89 views
2

嘿傢伙 我在我的android應用程序的oncreate之外使用了runnable,我已經使用線程來設置ProgressBar的進度。我不知道的是,當停止按鈕被按下時,如何停止/取消線程,因爲thread.stop不是一個方法,以及如何從該方法恢復,甚至如何破壞線程。如何銷燬一個線程,暫停/掛起一個線程,恢復/運行一個線程?

我知道我必須在runnable中創建一些方法和成員,但我不完全知道是什麼?

+0

你有沒有想過使用的AsyncTask呢?它具有更新進度指示器的內置方法,如果需要也可以輕鬆取消。 – Squonk 2011-03-21 22:06:16

回答

3

Thread.stop()不再使用,因爲它被認爲是危險的:http://download.oracle.com/javase/1.4.2/docs/guide/misc/threadPrimitiveDeprecation.html

您必須讓線程由於變量變化而自然結束。該鏈接還提供了一些關於如何實現這一目標的建議。

public class MyThread extends Thread { 

    private boolean threadDone = false; 

    public void done() { 
     threadDone = true; 
    } 

    public void run() { 
     while (!threadDone) { 
      // work here 
      // modify common data 
     } 
    } 

}

警告:請確保您無論是在循環代碼中使用guarded block,一個方法阻止自己,或Thread.sleep(..)。如果你不瞭解保護區塊,Thread.sleep是最原始的,但它會起作用。您也可以永遠等待,並使用中斷機制取消當您使用等待或睡眠時在try-catch塊中以InterruptedException形式拋出的線程。爲此,請使用!Thread.currentThread().isInterrupted()作爲環路保護條件,然後使用Thread對象並調用thread.interrupt()

0

讓其他線程定期檢查一個布爾標誌(isCancelled,或類似的東西)。最初是錯誤的。

從您的停止按鈕代碼,將此值設置爲true。

當您的線程接下來檢查標誌並發現它爲真時,線程應該自行終止。

+1

從外部調用'interrupt()',然後使用'isInterrupted()'進行檢查就像設置自己的標誌一樣。另外它的優點是可以喚醒睡眠線,以便及時結束。 – 2011-03-21 21:04:05

+0

@Ted - 我以前一直覺得可能會有線程被任意中斷(這會使這種方法不安全) - 我誤解了嗎? – Cephron 2011-03-21 21:07:15

+0

你錯了。 'Thread.interrupt()'不會任意中斷一個線程。事實上,它*只會*中斷*一些*阻止庫調用。其餘的,它只是設置一個標誌。 – 2011-03-21 21:16:31

2

你有幾個選擇,它們取決於你如何定義線程的各種狀態。

線程在退出run()方法時有效停止。

要「暫停」和「恢復」線程的執行,您可以使用wait()和notify()。

爲了說明這一點,這裏有一個簡單的例子:

class MyThread implements Runnable { 
    private boolean keepRunning = false; 
    private boolean isPaused = false; 

    public void run() { 
     keepRunning = true; 
     try { 
      while (keepRunning) { 
       // do stuff here 
       if (isPaused) { 
        synchronized (this) { 
         // wait for resume() to be called 
         wait(); 
         isPaused = false; 
        } 
       } 
      } 
     } catch (Exception ex) { 
      // do stuff 
     } 
    } 

    // note that as-is this won't do anything to a paused thread until 
    // it is resumed. 
    public void stop() { 
     keepRunning = false; 

    } 

    public void pause() { 
     isPaused = true; 
    } 

    public synchronized void resume() { 
     // notify anybody waiting on "this" 
     notify(); 
    } 
} 
+4

在上面的代碼中還要記住一點:pause()和stop()方法是非阻塞調用,因此它們會立即返回。您可以通過使用等待和通知來阻止呼叫。也取決於你在主循環中做什麼,線程可能永遠不會暫停或停止。這是在socket.accept沒有超時設置的套接字服務器的初學者實現中的一個常見錯誤。 – Nick 2011-03-21 21:11:20

+0

我不認爲這是正確的方式來調用通知,因爲我得到這個錯誤 - > 03-22 14:17:53.328:錯誤/ AndroidRuntime(2628):java.lang.IllegalMonitorStateException: 03-22 14:17:53.328:ERROR/AndroidRuntime(2628):at java.lang.Object.notify(Native Method) – abhishek 2011-03-22 08:50:42

+0

你是從同步方法還是同步塊中調用notify()?如果沒有,你會得到這個消息。 – Nick 2011-03-22 16:40:18

2

要控制Java線程,你應該補充的方法,可以通過設置你的run()方法來讀取變量其他對象調用的對象。你不給你在做什麼太多的信息,但這裏有一個可能的模式:

public class ProgressBarUpdater implements Runnable{ 
    private volatile boolean paused = false; 
    private volatile boolean finished = false; 

    /* other fields, constructor etc. */ 

    public void run(){ 
     while(!finished){ 
      updateProgressBar(); 

      while(paused && !finished){ 
       try{ 
        Thread.sleep(1000); //Busy wait - should really use wait/notify, but that's another lesson 
       } 
       catch(InterruptedException e){ 

       } 
      } 
     } 
    } 

    public synchronized void pauseProgressBar(){ 
     paused = true; 
    } 

    public synchronized void unPauseProgressBar(){ 
     paused = false; 
     //call notify() here when you switch to wait/notify. 
    } 

    public void stopProgressBar(){ 
     finished = true; 
     //call notify() here too. 
    } 
} 

你可能會想用周圍的控制變量更強大的同步,並且,如在評論中提到的,等待/通知而不是忙碌的等待。

使用像這樣:

ProgressBarUpdater pbu = new ProgressBarUpdater(); 

Thread t = new Thread(pbu); 

t.start(); 
Thread.sleep(10000); //let the progress bar run for ten seconds. 

pbu.pauseProgressBar(); 
Thread.sleep(10000); //pause it for ten seconds. 

pbu.unPauseProgressBar(); 
Thread.sleep(10000); //restart for another ten seconds. 

pbu.stopProgressBar(); //stop progress bar. 
+0

嘿感謝您的支持,但是當我試圖停止與您的代碼的線程我得到03-22 14:17:53.328:錯誤/ AndroidRuntime(2628):java.lang.IllegalMonitorStateException:對象未通過線程鎖定通知) 03-22 14:17:53.328:ERROR/AndroidRuntime(2628):at java.lang.Object.notify(Native Method) 錯誤 – abhishek 2011-03-22 08:50:07