简体   繁体   English

不在AsyncTask的onPostExecute中设置Activity的实例变量或如何将数据从AsyncTask返回到主UI线程

[英]Instance variable of Activity not being set in onPostExecute of AsyncTask or how to return data from AsyncTask to main UI thread

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). 我正在尝试找出创建AsyncTask的正确方法,以便从Internet检索某些数据,然后获取该数据并将其捆绑在Intent中并将其传递给新活动(列表显示)。 So in the first activity I just have an EditText and Button. 所以在第一个活动中我只有一个EditText和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. 在OnClick的情况下,应该调用任务,当它完成时,数据应该捆绑在Intent中并传递给下一个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. 问题是当我从onPostExecute获取结果并将它们设置为main活动的实例变量时,该任务完成时该实例变量仍为null。 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? 当我调试应用程序时,我看到onPostExecute确实包含一个充满结果的有效PlacesList,那么为什么在执行任务后实例变量的位置设置为null? I am going about "returning data" from an AsyncTask incorrectly? 我正在从AsyncTask错误地“返回数据”?

An AsyncTask is, by definition, executed in a different thread. 根据定义,AsyncTask是在不同的线程中执行的。 Thus, you cannot expect the results to be immediatly available after you call execute. 因此,在调用execute之后,您不能指望结果立即可用。 Instead, you should trigger the new intent off of the completion of the AsyncTask: 相反,您应该触发完成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();
        }

}

I hit this thread while looking for an answer I eventually found here: Common class for AsyncTask in Android? 我在寻找我最终在这里找到的答案时遇到了这个问题: Android中AsyncTask的公共类?

It's a really elegant and generic solution for this problem. 对于这个问题,这是一个非常优雅和通用的解决方案。

PS. PS。 Keep in mind that even though AsyncTasks are performed on a different thread, the onPostExecute is done on the UI thread, allowing direct communication with the UI. 请记住,即使AsyncTasks是在不同的线程上执行的,onPostExecute也是在UI线程上完成的,允许与UI直接通信。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM