2013-07-23 86 views
0

首先我很新到Android,請與我:)裸Android的線程,處理程序的handleMessage:從運行的線程更新內外部類文件UI線程

背景: 我想轉換一個Java(非GUI)程序在Android上運行。爲簡單起見讓我們說該程序具有以下文件:

DSGen.java,SInfer.java,Main.java

在Main()方法,對象爲每個類DSGen和SInfer被初始化並通過進入新的線程並開始。同樣,每個DSGen和SInfer類都使用public void run()方法實現Runnable,並且兩個運行方法都將文本輸出到system.out.println()。

螺紋1.產生隨機數據的100個值 線索2使在100個值生成的數據(輸出100次的結果)

在我知道該程序的Android版本,該UI線程處理的所有計算UI更新。 因此,在我的MainActivity.java文件中,我試圖聲明一個處理程序來接收來自「具有輸出數據的線程2」的消息,該消息可用於更新MainActivity UI線程中的TextView。當我按下Android UI上的開始按鈕時,該應用程序開始執行。

問題: 當我運行這個應用程序時,我的TextView不會更新,直到處理結束。我還注意到,並非所有的輸出都更新爲我的TextView,只有40/100的計算實際上將其輸入到TextView中。

該程序的實際代碼很長,我認爲最好只包含與SInfer類的線程,處理程序和運行方法相關的部分。

我希望有人可以給我一個僞代碼示例或解決方案來處理多個線程,其中可運行的方法在2個不同的類文件(不是MainActivity中的內部類)中聲明,並且可以通過傳遞來自其中一個線程的消息返回到UI線程。

預先感謝您!

public class MainActivity extends Activity { 

    /* UI Elements */ 
    private TextView output; 

    /* Thread Handler */ 
    private Handler uiHandler; 

    /* Handle message override */ 
    public class UIHandler extends Handler { 

     @Override 
     public void handleMessage(Message msg) { 
      output.append(msg.obj.toString()); 
      super.handleMessage(msg); 
     } 
    } 

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

     output = (TextView) findViewById(R.id.displayTextView); 
     uiHandler = new UIHandler(); 

     setStartButtonClickListener(); 

    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     // Inflate the menu; this adds items to the action bar if it is present. 
     getMenuInflater().inflate(R.menu.activity_run_fsi, menu); 
     return true; 
    } 


    private void setStartButtonClickListener() { 
     Button startButton = (Button) findViewById(R.id.startButton); 
     startButton.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 

       runFSI(); 

      } 
     }); 
    } 

    private void runFSI() { 
     // initialize SInfer and pass uiHandler 

     SInfer inferer = SInfer.getInstance(/*other variables*/, uiHandler); 


     // initialize DSGen 
     DSGenerator dsGen; 

     Thread t1 = new Thread(dsGen); 
     Thread t2 = new Thread(inferer); 
     t1.start(); 
     t1.yield(); 
     t2.start(); 
     t2.yield(); 

     try { 
      Thread.sleep(10000); 
     } catch (Exception e) { 
     } 

     inferer.stop(); 
     dsGen.stop(); 

    } 

} 

內部SIn​​fer所述的運行方法如下(System.out的代碼被從原始Java代碼遺留)

@Override 
public void run() { 

    // System.out.println("Inference: Thread started..."); 

    while (stopFlag == false) { 
     try { 
      // System.out.println("SInference: run........."); 
      Thread.sleep(200); 
      inferenceResult = doInference(); 

      /* Send result to UI thread */ 

      Message msg = Message.obtain(uiHandler); 
      msg.obj = inferenceResult.toString(); 
      uiHandler.sendMessage(msg); 

     } catch (InterruptedException e) { 
      // System.out.println(e.getMessage()); 
     } 
    } 
} 

回答

0

正在運行的Thread.sleep(10000);在主線程中(OnClick在UI線程中被調用),所以在這10秒內UI中沒有任何東西可以被更新。 嘗試在單獨的線程中調用您的runFSI方法。

+0

謝謝你指出這一點。在更新TextView之前,睡眠肯定會停止10秒。如所建議的如果我爲FSI創建單獨的線程(調用此線程0),然後又創建兩個線程。線程2依賴於線程1生成的數據。什麼是最好的方法?爲FSI創建一個內部類?我也只是傳遞一個對uiHandler的引用,它可以反過來傳遞給線程2,以便我可以將結果作爲消息發送出去?再次感謝! – iron3rd

0

考慮使用一個AsyncTask

覆蓋doInBackground()來處理所有的後臺計算的

覆蓋onProgressUpdate(),而線程運行usingthe publishProgress()方法來頂嘴UI線程。

並重寫onPostExecute()在UI線程上做最後的事情。