2014-09-21 105 views
1

編輯:我發現我在下面描述的只發生在我的模擬設備上(Nexus 5,目標api 19,4.4.2與Intel Atom(x86)cpu ),但不是在我的物理設備(宏達電一)...Android:暫停並恢復活動中的線程

編輯2:編輯1是由於IllegalStateException我沒有捕獲。添加了一些代碼來檢查線程是否已經運行,然後再嘗試啓動它。這與接受的答案相結合解決了我的問題。

我已實施啓動一個新的線程在活動的onCreate方法,像這樣的activty:

... 

private boolean running; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 

    running = true; 
    new Thread(null, work, "myThread").start(); 
} 

Runnable work = new Runnable() { 

    @Override 
    public void run() { 
     while (running) { 
      //Doing work 
     } 
    } 
}; 

我「暫停」我與我的活動的的onPause方法線程,就像這樣:

@Override 
protected void onPause() { 
    running = false; 
    super.onPause(); 
} 

所以我認爲,恢復這將是一樣容易...¨

@Override 
protected void onResume(){ 
    running = true; 
    super.onResume(); 
} 

,但我的日閱讀不恢復。任何想法爲什麼?感謝任何幫助。

馬庫斯

回答

1

所有我認爲答案有關於一些問題的運行變量,因爲你不能寫入和讀取從兩個不同的Threads的變量,而不synchronized block,所以我發表我自己的答案:

package com.example.threadandtoast; 

import android.os.Bundle; 
import android.support.v7.app.ActionBarActivity; 
import android.widget.Toast; 

public class MainActivity extends ActionBarActivity { 
    public class MonitorObject{ 
      public boolean running = true; 
      public String message = ""; 
      public boolean mustBePost = true; 
    } 

    Thread t; 
    int threadNameCounter = 0; // i use this variable to make sure that old thread is deleted 
           // when i pause, you can see it and track it in DDMS 

    Runnable work = new Runnable() { 
     boolean myRunning; 
     @Override 
     public void run() { 
      synchronized(mSync) { 
       myRunning = mSync.running; 
      } 
      while (myRunning) { 
       runOnUiThread(new Runnable() { // in order to update the UI (create Toast) 
       @Override      // we must switch to main thread 
       public void run() { 
        // i want to read the message so i must use synchronized block 
        synchronized(mSync) { 
        // i use this variable to post a message just for one time because i am in an infinite loop 
        // if i do not set a limit on the toast i create it infinite times 
         if(mSync.mustBePost){  
          Toast.makeText(MainActivity.this, mSync.message, Toast.LENGTH_SHORT).show(); 
          // the message post so i must set it to false 
          mSync.mustBePost = false; 
          // if i am going to pause set mSync.running to false so at the end of infinite loop 
          //of thread he reads it and leaves the loop 
          if(mSync.message.equals("Main Activity is going to pause")){ 
           mSync.running=false;    
          } 
         } 
        } 
       } 
       }); 

      synchronized(mSync) { 
       myRunning = mSync.running; 
      } 
     } 
     } 
    }; 

    final MonitorObject mSync = new MonitorObject(); 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 

     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

    } 

    @Override 
    protected void onPause() { 
     super.onPause(); 
     synchronized(mSync) { 
      // mSync.running = false; you can not set it here because 
      // it is possible for the thread to read it and exit the loop before he posts your message 
      mSync.mustBePost=true; 
      mSync.message = "Main Activity is going to pause"; 
     }  
    } 

    @Override 
    protected void onResume(){ 
     super.onResume(); 
     threadNameCounter++; 
     synchronized(mSync) { 
      mSync.running = true; 
      mSync.mustBePost=true; 
      mSync.message = "Main Activity is going to resume"; 
     } 
     t = new Thread(work,"My Name is " + String.valueOf(threadNameCounter)); 
     t.start(); 
    } 

} 

或者您可以使用此代碼:

public class MainActivity extends ActionBarActivity { 

    Thread t; 
    int threadNameCounter = 0; // i use this variable to make sure that old thread is deleted 
           // when i pause, you can see it in DDMS 

    String message = ""; 
    boolean isPost = false; 

    Runnable work = new Runnable() { 

     @Override 
     public void run() { 

      while (true) { 
       runOnUiThread(new Runnable() { 
       @Override      
       public void run() { 
        if(!isPost){ 
         Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show(); 
         isPost = true; 
         if(message.equals("Main Activity is going to pause")){ 
          t.interrupt(); 
         } 

        } 
       } 
       }); 
      if(Thread.currentThread().isInterrupted()){ 
       break; 
      } 
     } 
     } 
    }; 


    @Override 
    protected void onCreate(Bundle savedInstanceState) { 

     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

    } 

    @Override 
    protected void onPause() { 
     super.onPause(); 
     message = "Main Activity is going to pause"; 
     isPost = false; 
    } 

    @Override 
    protected void onResume(){ 
     super.onResume(); 
     message = "Main Activity is going to resume"; 
     isPost = false; 
     threadNameCounter++; 
     t = new Thread(work,"My Name is " + String.valueOf(threadNameCounter)); 
     t.start(); 
    } 

} 

你也可以使用旗語或等待通知的方式。

我把public String message = "";public boolean mustBePost = true;中的msync對象,但它是 沒有必要的,因爲只有main thread必須將它們的訪問。

如果您有任何問題,請詢問。

+0

檢查我的編輯請 – Marcus 2014-09-21 15:57:43

+0

你的代碼甚至不工作。布爾值不是同步語句的有效類型的參數。 – Marcus 2014-09-21 17:13:38

+0

修復它看起來再次感謝 – mmlooloo 2014-09-21 17:17:58

0

這是因爲你Runnable對象while循環停止時停止。你可以試試這個:

Runnable work = new Runnable() { 

    @Override 
    public void run() { 
     while() { 
      if(running){ 
      //Doing work 
      } 
     } 
    } 
}; 
+0

檢查我的編輯請 – Marcus 2014-09-21 15:57:15

1

聲明running = false;將停止Thread的執行,而不是暫停它。使用兩個變量:一是停止當前Thread,另一個是暫停和繼續Thread,如下:

boolean isThreadPause=false; 
Runnable work = new Runnable() {  
    @Override 
    public void run() { 
     while (running) { 
      if (!isThreadPause) { 
       // Doing work 
      } 
     } 
    } 
}; 

在事件的活動,設置isThreadPausetrue,並在onResume事件,設置isThreadPausefalse

+0

檢查我的編輯請 – Marcus 2014-09-21 15:56:32