views:

33

answers:

1

I'm trying to figure out the correct way to create an AsyncTask to retrieve some data from the internet and then to take that data and bundle it up in an Intent and pass it to a new activity(A list display). So in the first activity I just have an EditText and Button. In the event of an OnClick the task should be called and when it is finished the data should be bundled inside an Intent and passed to the next Activity. The problem is when I take the results from onPostExecute and set them to an instance variable of the main activity, that instance variable is still null when the task is complete. Here is the barebones version of the code:

public class SearchActivity extends Activity implements OnClickListener
{
    static final String TAG = "SearchActivity";
    private EditText searchInput;
    private Button searchBtn;
    private PlacesList places;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.search_activity);

        searchBtn = (Button) findViewById(R.id.button_search);  
        searchInput = (EditText) findViewById(R.id.search_input);

        searchBtn.setOnClickListener(this);
    }

    public void onClick(View v) {
        if(v == searchBtn)
        {
            String input = searchInput.getText().toString();
            if(input != null && input.length() != 0)
            {

                try {
                    new TestTask().execute(input);
                    Bundle bundle = new Bundle();
                    bundle.putParcelable("places", places);
                    Intent i = new Intent(this, SearchResultsActivity.class);
                    i.putExtras(bundle);

                    startActivity(i);
                } catch(Exception ex) {
                    ex.printStackTrace();
                } 
            }
        }
    }

    private class TestTask extends AsyncTask<String, Void, PlacesList>
    {
        private ProgressDialog dlg = new ProgressDialog(SearchActivity.this);

        @Override
        protected void onPreExecute()
        {
            dlg.setMessage("test");
            dlg.show();
        }

        @Override
        protected PlacesList doInBackground(String...args)
        {
            try 
            {
                return new PlaceLocator().retrieveResults(args[0]);
            } 
            catch (Exception e) 
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return new PlacesList();
        }

        @Override
        protected void onPostExecute(PlacesList results)
        {
            SearchActivity.this.places = results;
            if(dlg.isShowing())
                dlg.dismiss();
        }
    }
}

When I debug the application I see onPostExecute does contain a valid PlacesList full of results, so why is the instance variable places set to null after the task is executed? I am going about "returning data" from an AsyncTask incorrectly?

+2  A: 

An AsyncTask is, by definition, executed in a different thread. Thus, you cannot expect the results to be immediatly available after you call execute. Instead, you should trigger the new intent off of the completion of the AsyncTask:

public void onClick(View v) {
        if(v == searchBtn)
        {
            String input = searchInput.getText().toString();
            if(input != null && input.length() != 0)
            {

                try {
                    new TestTask().execute(input);

                } catch(Exception ex) {
                    ex.printStackTrace();
                } 
            }
        }
    }

private void startSearch(PlaceList places) {
  Bundle bundle = new Bundle();
  bundle.putParcelable("places", places);
  Intent i = new Intent(this, SearchResultsActivity.class);
  i.putExtras(bundle);

  startActivity(i);
}

private class TestTask extends AsyncTask<String, Void, PlacesList>
{
...

        @Override
        protected void onPostExecute(PlacesList results)
        {
           startSearch(results);
           if(dlg.isShowing())
                dlg.dismiss();
        }

}
Mayra
Thanks for the explanation, that works great.
AJ