需求

  • Activity需要直接取得AsyncTask執行後onPostExecute()的結果,而非在onPostExecute()處理執行結果。
  • AsyncTask需要寫成獨立的class檔案,而非寫成Activity的inner class。

思路

  • Activity當中不使用AsyncTask.get()來取得結果,因為呼叫AsyncTask.get()會阻斷UI介面的操作(會有停頓的現象),故需採用別種方式來取得。
  • 宣告一個介面,在此介面當中定義取得結果的方法。
  • AsyncTask當中宣告一個此介面型態的實體變數,然後在onPostExecute()方法當中把執行結果傳給此介面型態的實體變數。
  • 在要取得結果的Activity實作此介面,如此一來此Activity就可以在實作該介面取得結果的方法來取得結果。

程式碼

宣告一個介面並且定義取得結果的方法。

public interface AsyncTaskResult<T extends Object>
{
    // T是執行結果的物件型態

    public void taskFinish( T result );
}

AsyncTask當中加入一個用此介面為型態所宣告的實體變數,並且在onPostExecute()當中把執行結果傳給此變數。
這邊採用網路連線測試做為範例程式。

public class ConnectionTestAsyncTask extends AsyncTask<String, Void, Boolean>
{
    private static final int TIME_OUT = 1000;
    private static final String TEST_URL = "http://www.google.com/blank.html";
    
    public AsyncTaskResult<Boolean> connectionTestResult = null;
  
    @Override
    protected Boolean doInBackground( String... params )
    {
        boolean connectSuccess = false;
        HttpURLConnection httpConn = null;
        try
        {
            httpConn = (HttpURLConnection) ( new URL( TEST_URL ).openConnection() );
            httpConn.setInstanceFollowRedirects( false );   
            httpConn.setConnectTimeout( TIME_OUT );
            httpConn.setReadTimeout( TIME_OUT );
            httpConn.connect();
            if ( httpConn.getResponseCode() == HttpURLConnection.HTTP_OK )
                connectSuccess = true;
        }
        catch ( IOException e )
        {
        }
        finally
        {
            if ( httpConn != null )
                httpConn.disconnect();
        }
        return connectSuccess;
    }

    @Override
    public void onPostExecute( Boolean result )
    {
        this.connectionTestResult.taskFinish( result );
    }
}

接著在要取得執行結果的Activity實作此介面,同時加入AsyncTask,記得把AsyncTask.connectionTestResult指派給this ,然後實作介面的taskFinish()來處理AsyncTask執行的結果。

public class MainActivity extends Activity implements AsyncTaskResult<Boolean>
{
    public void checkNetworkStatus()
    {
        ConnectionTestAsyncTask connectionTask = new ConnectionTestAsyncTask();
        connectionTask.connectionTestResult = this;
        connectionTask.execute( "" );
    }
  
    @Override
    public void taskFinish( Boolean result )
    {
        if ( result == true )
            Toast.makeText( this, "網路連線正常", Toast.LENGTH_LONG ).show();
        else
            Toast.makeText( this, "網路連線失敗", Toast.LENGTH_LONG ).show();
    }
  
  // ...其他Activity程式碼略!!

}  

參閱原始問答

http://stackoverflow.com/questions/12575068/how-to-get-the-result-of-onpostexecute-to-main-activity-because-asynctask-is-a

Comments

comments powered by Disqus