【问题标题】:Instance variable of Activity not being set in onPostExecute of AsyncTask or how to return data from AsyncTask to main UI threadActivity 的实例变量未在 AsyncTask 的 onPostExecute 中设置或如何将数据从 AsyncTask 返回到主 UI 线程
【发布时间】:2011-03-22 08:03:12
【问题描述】:

我正在尝试找出创建 AsyncTask 以从 Internet 检索一些数据然后获取该数据并将其捆绑在 Intent 中并将其传递给新活动(列表显示)的正确方法。所以在第一个活动中,我只有一个 EditText 和 Button。如果发生 OnClick,则应调用任务,完成后数据应捆绑在 Intent 中并传递给下一个 Activity。问题是当我从 onPostExecute 获取结果并将它们设置为主要活动的实例变量时,当任务完成时,该实例变量仍然为空。这是代码的准系统版本:

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();
        }
    }
}

当我调试应用程序时,我看到 onPostExecute 确实包含一个充满结果的有效 PlacesList,那么为什么在任务执行后实例变量 places 设置为 null?我要从 AsyncTask 错误地“返回数据”?

【问题讨论】:

    标签: java android multithreading android-asynctask


    【解决方案1】:

    我在寻找最终在这里找到的答案时点击了这个帖子:Common class for AsyncTask in Android?

    对于这个问题,这是一个非常优雅和通用的解决方案。

    PS。请记住,即使 AsyncTask 在不同的线程上执行,onPostExecute 也是在 UI 线程上完成的,从而允许与 UI 直接通信。

    【讨论】:

      【解决方案2】:

      根据定义,AsyncTask 在不同的线程中执行。因此,您不能期望在调用 execute 后立即获得结果。相反,您应该在 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();
              }
      
      }
      

      【讨论】:

      • startSearch 必须声明为静态吗?
      • @Eugene van der Merwe :不,TestTask 是一个内部类,因此它可以访问其父类中的所有方法和变量。如果我已将 TestTask 声明为静态内部类,那么是的,startSearch 需要是静态的,TestTask 才能访问它。有关区别的更多信息,请参阅download.oracle.com/javase/tutorial/java/javaOO/nested.html
      猜你喜欢
      • 2015-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多