2013-10-16 63 views
2

我有一個運行無限的任務的子線程。我想(1)不斷地將數據發送回UI線程,(2)偶爾向子線程發送數據(對應於按鈕)以暫停/繼續無限任務。我的問題是,子線程卡在循環中,意味着任務不執行。Android - 循環後的代碼

我的問題是這樣的:如何讓子線程從UI線程接收消息而不阻塞無限任務?

這是我到目前爲止: 對於任務(1),我在我的UI線程中有一個處理程序,它的工作原理和子線程中的一個無限循環,它發送一條消息,它本身起作用。

在UI線程:

mMainHandler = new Handler() { 
    public void handleMessage(Message msg) { 
     Bundle b; 
     b = msg.getData(); 
     if (msg.what==1) 
      Log.i("main", "from child (running) - " + b.getBoolean("running")); 
     else if (msg.what == 2) 
      Log.i("main", "from child (count) - " + b.getInt("count")); 
    } 
}; 

在子線程(目前使用虛擬任務,直到我得到的框架制定):

while (true) { 
    if (running) { 
     try { 
      curCount += up; 
      if (curCount == maxCount) 
       up = -1; 
      else if (curCount == minCount) 
       up = 1; 
      Thread.sleep(1000); 
     } catch (InterruptedException e) { 
      Log.e("", "local Thread error", e); 
     } 

     Bundle b = new Bundle(1); 
     b.putInt("count", curCount); 
     Message toMain = mMainHandler.obtainMessage(); 
     toMain.what = 2; 
     toMain.setData(b); 
     mMainHandler.sendMessage(toMain); 
    } 
} 

有關任務(2),我有一個方法在我的UI線程中,對應於按鈕的按鈕,將消息發送到子線程,該子線程工作,並且子線程中的處理程序自行工作。

在UI線程:

private void sendRunning(boolean running) { 
    if (mChildHandler != null) { 
     Bundle b = new Bundle(1); 
     b.putBoolean("running", running); 

     Message msg = mChildHandler.obtainMessage(); 
     msg.what = 1; 
     msg.setData(b); 
     mChildHandler.sendMessage(msg); 
    } 
} 

在子線程:

Looper.prepare(); 
mChildHandler = new Handler() { 
    public void handleMessage(Message msg) { 
     Bundle b; 
     if (msg.what==1){ 
      b = msg.getData(); 
      running = b.getBoolean("running"); 
      Log.i(INNER_TAG, "from main (running) - " + b.getBoolean("running")); 
      Log.i(INNER_TAG, "running - " + running); 
      try { 
       Message toMain = mMainHandler.obtainMessage(); 
       toMain.what = 1; 
       toMain.setData(b); 
       mMainHandler.sendMessage(toMain); 
      } finally {} 
     } 
    } 
}; 
Looper.loop(); 

每個這些情況的一個正常工作獨自一人,而是試圖在同一時間做兩件事就是問題所在。如果我在Looper.loop()之後放置了無限任務,它永遠不會到達。如果我把它放在Looper.prepare()之前,它會運行一次。如果我把它放在彎鉤上,它仍然只能運行一次。

任何想法,將不勝感激:)

這裏是我完整的代碼(減去包裝/進口),僅供參考:

public class MainActivity extends Activity { 

Thread thread; 
private Handler mMainHandler, mChildHandler; 

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

    mMainHandler = new Handler() { 
     public void handleMessage(Message msg) { 
      Bundle b; 
      b = msg.getData(); 
      if (msg.what==1) 
       Log.i("main", "from child (running) - " + b.getBoolean("running")); 
      else if (msg.what == 2) 
       Log.i("main", "from child (count) - " + b.getInt("count")); 
     } 
    }; 

    thread = new ChildThread(); 
    thread.start(); 

    // Get a reference to the button 
    Button buttonStart = (Button)findViewById(R.id.btnStart); 
    Button buttonStop = (Button)findViewById(R.id.btnStop); 

    // Set the click listener to run my code 
    buttonStart.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      Toast.makeText(MainActivity.this, 
        "Starting...", Toast.LENGTH_SHORT).show(); 
      sendRunning(true); 
     } 
    }); 
    buttonStop.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      Toast.makeText(MainActivity.this, 
        "Stopping...", Toast.LENGTH_SHORT).show(); 
      sendRunning(false); 
     } 
    }); 
} 

private void sendRunning(boolean running) { 
    if (mChildHandler != null) { 
     Bundle b = new Bundle(1); 
     b.putBoolean("running", running); 

     Message msg = mChildHandler.obtainMessage(); 
     msg.what = 1; 
     msg.setData(b); 
     mChildHandler.sendMessage(msg); 
    } 
} 

@Override 
protected void onDestroy() { 

    Log.i("tag", "stop looping the child thread's message queue"); 
    mChildHandler.getLooper().quit(); 

    super.onDestroy(); 

} 

class ChildThread extends Thread { 

    private static final String INNER_TAG = "ChildThread"; 
    private boolean running = true;  
    final int maxCount = 10; 
    final int minCount = 0; 
    public int curCount = minCount; 
    private int up = 1; 

    public void run() { 

     while (true) { 
      if (running) { 
       try { 
        curCount += up; 
        if (curCount == maxCount) 
         up = -1; 
        else if (curCount == minCount) 
         up = 1; 
        Thread.sleep(1000); 
       } catch (InterruptedException e) { 
        Log.e("", "local Thread error", e); 
       } 

       Bundle b = new Bundle(1); 
       b.putInt("count", curCount); 
       Message toMain = mMainHandler.obtainMessage(); 
       toMain.what = 2; 
       toMain.setData(b); 
       mMainHandler.sendMessage(toMain); 
      } 

      this.setName("child"); 
      Looper.prepare(); 
      mChildHandler = new Handler() { 
       public void handleMessage(Message msg) { 
        Bundle b; 
        if (msg.what==1){ 
         b = msg.getData(); 
         running = b.getBoolean("running"); 
         Log.i(INNER_TAG, "from main (running) - " + b.getBoolean("running")); 
         Log.i(INNER_TAG, "running - " + running); 
         try { 
          Message toMain = mMainHandler.obtainMessage(); 
          toMain.what = 1; 
          toMain.setData(b); 
          mMainHandler.sendMessage(toMain); 
         } finally {} 
        } 
       } 
      }; 

      Log.i(INNER_TAG, "Child handler is bound to - " + 
        mChildHandler.getLooper().getThread().getName()); 
      Looper.loop(); 
     } 


    } 
} 

}

+1

備註:我花了一段時間研究並試圖弄清楚如何使用線程,並且[this](http://codinghard.wordpress.com/2009/05/16/android-thread-messaging/)頁面奠定了非常好的。 [This](http://www.biemmeitalia.net/blog/bundle-android/)頁面向我展示瞭如何使用bundle在線程之間交換數據。 – Andy

+0

如果儘可能避免無限期地運行線程... – JoxTraex

回答

0

只使用意向的服務而不是此線程所以你可以管理你的更新的所有用戶界面,以及你想要在意圖服務中做什麼,一個廣播接收器正在使用它,並且它非常容易處理線程,並且感染你的UI是在你的後臺進程運行時不需要手動或鎖定。

0

我最後只是使用線程的可變時間來避免這種情況。感謝您的建議。