2013-04-11 53 views
0

我已經創建了活動,應該在用戶單擊按鈕後返回GeoPoint數組。執行http請求和解析答案的代碼被提取到AsyncTask。在onPostExecute()方法我已經分配overlayListdoInBackground()方法的返回值,但它沒有工作,AsyncTask僅在使用get()方法後返回值

overlayList.size() 

thows一個NullPointerException異常。這是我原來的代碼:

public class MyActivity extends Activity { 

Button bt; 
TextView tv1; 
List<GeoPoint> overlayList; 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    bt = (Button) findViewById(R.id.button); 
    tv1 = (TextView) findViewById(R.id.textView); 

    bt.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 

      String query = "http://maps.googleapis.com/maps/api/directions/json?origin=bla-bla&destination=bla-bla&sensor=false"; 

      Request mat = new Request(); 
      mat.execute(query); 

      if (overlayList.size() > 0){ 
       tv1.setText("List is OK!"); 
      } 

     } 
    }); 
} 

private class Request extends AsyncTask<String, Void, ArrayList<GeoPoint>> { 

    @Override 
    protected ArrayList<GeoPoint> doInBackground(String... params) { 
     return parse(connect(params[0])); 
    } 

    @Override 
    protected void onPostExecute(ArrayList<GeoPoint> geoPoints) { 
     super.onPostExecute(geoPoints); 
     overlayList = geoPoints; 
    } 

    public JSONObject connect(String url) { 
     ...  
    } 

    public ArrayList<GeoPoint> parse(JSONObject jsonObject) { 
     ... 
    } 

} 

但是,如果我將修改我的OnClickListener以這樣的方式:

HttpRequest mat = new HttpRequest(); 
mat.execute(query); 

try { 
    overlayList = mat.get(); 
} catch (InterruptedException e) { 
    e.printStackTrace(); 
} catch (ExecutionException e) { 
    e.printStackTrace(); 
} 

列表中的一切會確定,overlayList.size()返回大小。所以,我的問題 - 爲什麼onPostExecute()方法不初始化我的列表?

+0

overlayList.add(geoPoints); – Raghunandan 2013-04-11 15:37:29

+0

不要調用'super.onPostExecute(geoPoints);'。 – 2013-04-11 15:38:53

+0

可以發表你的解析(連接(...))代碼 – Raghunandan 2013-04-11 15:42:15

回答

2

AsyncTask確實如其名稱暗示的那樣 - doInBackground(...)方法在單獨的線程上異步運行,而onCreate(...)中的代碼繼續運行。

在你的代碼在這裏...

mat.execute(query); 

if (overlayList.size() > 0){ 
    tv1.setText("List is OK!"); 
} 

...你叫mat.execute(query)if條件立即檢查。換句話說,你的AsyncTask還沒有機會執行它的doInBackground(...)方法。

移動這個代碼...

if (overlayList.size() > 0){ 
    tv1.setText("List is OK!"); 
} 

...到您的AsyncTaskonPostExecute(...)方法。

編輯:由於triggers在下面的註釋中指出,調用AsyncTaskget()方法會阻塞主線程並等待返回結果。這有效地使得使用AsyncTask成爲同步操作,在這種情況下,使用AsyncTask沒有意義。

我能想到使用get()方法的唯一原因是來自除主線程(UI)之外的線程,儘管我想不出有多少理由要這樣做。

+2

除了上述原因,第二種發佈方式的原因是因爲在AsyncTask上調用'get()'方法會導致它阻塞主線程,直到任務完成。 – triggs 2013-04-11 15:50:23

+0

@triggs:同意,我應該指出這一點。 – Squonk 2013-04-11 15:52:38