2012-11-26 17 views
2

基本上,我必須把代碼,我想在doInBackground內的另一個線程上運行,或者我可以調用另一個函數/類/任何它是函數被調用-JAVA在doInBackground中並讓它異步運行? IE:(示例代碼我在網上找到)AsyncTask調用類中的另一個函數

 protected String doInBackground(String... params) { 
     for(int i=0;i<5;i++) { 
      try { 
       Thread.sleep(1000); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 
     TextView txt = (TextView) findViewById(R.id.output); 
     txt.setText("Executed"); 
     return null; 
    } 

是我見過它做的,但我可以改爲做:

 protected String doInBackground(String... params) { 
      postToServer(x,y,z,h); 
     } 

,並調用它,我已經寫了一個函數,然後有函數在另一個線程中運行?有時候,我的HTTP服務器響應速度有點慢(它現在只是一個低性能的服務器),如果我的postToServer()調用需要超過5秒鐘,Android會自動彈出殺死進程框,還會禁用我的用戶界面直到postToServer()調用完成。這是一個問題,因爲我正在開發一個GPS跟蹤應用程序(內部爲我工作的公司)和用戶界面選項關閉凍結跟蹤直到我的postToServer()完成,這有時並不會發生。如果這個問題得到解答,我表示歉意,我嘗試過搜索,但還沒有找到任何能夠按照我希望完成這項工作的方式工作的例子。

+1

一個方法總是在調用者的線程中執行。直接調用不能切換線程。 – zapl

回答

3

您可以這樣做,但您必須將UI更新移至onPostExecute,因爲它在UI線程上運行。

public MyAsyncTask extends AsyncTask<foo, bar, baz> { 

    ... 

    protected String doInBackground(String... params) { 
     postToServer(x,y,z,h); 
    } 

    protected void onPostExecute(Long result) { 
     TextView txt = (TextView) findViewById(R.id.output); 
     txt.setText("Executed"); 
    } 

    .... 

} 

您可能希望在TextView中傳遞給AsyncTask的構造,並存儲爲一個WeakReference的。 private final WeakReference textViewReference;

public MyAsyncTask(TextView txt) { 
    textViewReference = new WeakReference<TextView>(txt); 
} 

然後在onPostExecute中確保TextView引用仍然存在。

protected void onPostExecute(Long result) { 
    TextView txt = textViewReference.get(); 
    if (txt != null) 
     txt.setText("Executed"); 
} 

如果您要通知該任務執行我會把那個調用AsyncTask前的用戶。

myTextView.setText("Update in progress..."); 
new MyAsyncTask().execute(); 

然後在onPostExecute設置TextView說 「更新完成。」

+0

好的,如果我真的不需要更新用戶界面,我還是應該這樣做,或者如果我不需要從它那裏返回信息,是否有其他方法可以強制它進入後臺線程?最終我需要緩存數據,如果我的HTTP請求沒有通過(即:缺乏網絡),但我可以從我的postToServer()並保持它的主線程(我認爲,這是完全的新的理由)。 –

+0

你可以使用'Thread'或'Runnable'和'Handler',但是我會堅持使用'AsyncTask',因爲它是最廣泛使用的,如果你決定要顯示進度或稍後更新UI日期將需要更少的返工。 – antew

+0

好的,非常感謝你。還有一個問題,如果你不介意的話:如果我把這個放在另一個方法裏面(onLocationChanged在這個實例中,每當GPS位置發生變化時就會出現),我怎樣才能使x,y,z和h可見? Eclipse告訴我,我能做到的唯一方法是最終聲明變量,但如果我這樣做,那麼如果位置更改,它會阻止我再次更新它們嗎? –

1

你試過第二種方法嗎?

從你發佈的內容看來,它應該可以在第二個例子中正常工作。

但是(可能與您的問題無關?)在您的第一個示例中,我認爲它會失敗,因爲您嘗試從後臺線程更改UI。你想把操縱TextView的部分放在裏面而不是doInBackground()

+0

謝謝你,那個代碼只是從另一篇文章中複製粘貼的,我正在閱讀有關asynctask的文章,所以我沒有絲毫的想法,如果它會編譯或不。只是想展示我在今天研究中看到的一個例子。到目前爲止,我還沒有嘗試過,不幸的是我現在正在離開工作,所以直到明天我才能夠進行測試,只是想測試一下水域,看看你的專業人員在想什麼。再次感謝你。 –

1

是的,你可以,調用你的postToServer方法(這是java中的名字)將會在主線程中運行。 AsyncTaskdoInBackground方法內的所有內容均在池化線程上運行,但一定不要直接調用它!請在您的asynktask上撥打execute,android框架將爲您完成工作並在另一個線程上運行doInBackground

嘗試做這樣的事情:

new AsyncTask<Void, Void, Void>() { 
    @Override 
    // this runs on another thread 
    protected Void doInBackground(Void... params) { 
     // assuming x, y, z, h are visible here 
     postToServer(x, y, z, h); 
     return null; 
    } 

    @Override 
    // this runs on main thread 
    protected void onPostExecute(Void result) { 
     TextView txt = (TextView) findViewById(R.id.output); 
     txt.setText("Executed"); 
    } 

}.execute(); // call execute, NOT doInBackGround 

另外,還要注意的AsyncTask所有其他方法,如onPostExecute在主線程上運行,因此避免重加載它們。

+0

非常感謝(在頭重複:方法,方法,方法)。我對你在說什麼感到困惑,所以讓我看看我能否在我的noob頭上清楚一點。如果我從doInBackground調用方法,那麼postToServer中的HTTP請求將在主線程中運行,還是在獨立的池AsyncTask線程中運行? IE:從最基本的角度來看,如果我的服務器沒有很快響應,我的用戶界面是否仍然凍結? –

+0

我添加了一個代碼示例,如果你關注它,你的UI不會凍結 – TeamBanana

+0

非常感謝。 –