2

基本上,我是否必须将我想在 doInBackground 中的另一个线程上运行的代码,或者我可以在 doInBackground 中调用另一个函数/类/whatever-it-is-functions-are-call-in-JAVA 并让它异步运行?IE:(我在网上找到的示例代码)

      protected String doInBackground(String... params) {
        for(int i=0;i<5;i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        TextView txt = (TextView) findViewById(R.id.output);
        txt.setText("Executed");
        return null;
  }  

是我看到它完成的方式,但我可以这样做:

      protected String doInBackground(String... params) {
           postToServer(x,y,z,h);
      }  

并让它调用我已经编写的函数,然后让该函数在另一个线程中运行?有时我的 HTTP 服务器响应有点慢(目前它只是一个低级测试服务器),如果我的 postToServer() 调用超过 5 秒,Android 会自动弹出终止进程框,并且还会禁用我的 UI,直到postToServer() 调用完成。这是一个问题,因为我正在开发一个 GPS 跟踪应用程序(内部为我工作的公司)并且关闭跟踪的 UI 选项冻结,直到我的 postToServer() 完成,这有时不会发生。如果这个问题已经得到解答,我深表歉意,我尝试搜索,但没有找到任何可以按照我希望的方式工作的示例。

4

4 回答 4

3

您可以这样做,但您必须将 UI 更新移动到onPostExecute它在 UI 线程上运行时。

public MyAsyncTask extends AsyncTask<foo, bar, baz> {

    ...

    protected String doInBackground(String... params) {
       postToServer(x,y,z,h);
    }  

    protected void onPostExecute(Long result) {
        TextView txt = (TextView) findViewById(R.id.output);
        txt.setText("Executed");
    }

    ....

}

您可能希望将 TextView 传递给 的构造函数AsyncTask并将其存储为 WeakReference。私人最终弱参考文本视图参考;

public MyAsyncTask(TextView txt) {
    textViewReference = new WeakReference<TextView>(txt);
}

然后在 onPostExecute 中,您将确保 TextView 引用仍然存在。

protected void onPostExecute(Long result) {
    TextView txt = textViewReference.get();
    if (txt != null)
        txt.setText("Executed");
}

如果您想通知用户任务正在执行,我会在调用AsyncTask.

 myTextView.setText("Update in progress...");
 new MyAsyncTask().execute();

然后在onPostExecute设置TextView中说“更新完成”。

于 2012-11-26T22:53:55.140 回答
1

是的,您可以,对您的postToServer方法的调用(这是 java 中的名称)将在主线程之外运行。doInBackgroundan 方法中的所有内容都AsyncTask在池线程上运行,但请确保不要直接调用它!而是调用execute您的 asynktask,android 框架将为您完成工作并doInBackground在另一个线程上运行。

尝试做这样的事情:

new AsyncTask<Void, Void, Void>() {
    @Override
    // this runs on another thread
    protected Void doInBackground(Void... params) {
        // assuming x, y, z, h are visible here
        postToServer(x, y, z, h);
        return null;
    }

    @Override
    // this runs on main thread
    protected void onPostExecute(Void result) {
        TextView txt = (TextView) findViewById(R.id.output);
        txt.setText("Executed");
    }

}.execute(); // call execute, NOT doInBackGround

另外,请注意 的所有其他方法AsyncTask,例如onPostExecute在主线程上运行,因此请避免重载它们。

于 2012-11-26T22:59:31.593 回答
1

你试过第二种方法吗?

从您发布的内容看来,在第二个示例中它应该可以正常工作。

但是(可能与您的问题无关?)在您的第一个示例中,我认为它会失败,因为您试图从后台线程更改 UI。你想把操纵 TextView 的部分放在里面onPostExecute()而不是doInBackground()

于 2012-11-26T22:54:12.850 回答
-1

基本上底线是 doInBackground() 方法不能与 Ui 线程或主线程交互。这就是为什么当您尝试与 doInBackground () 中的 TextView 交互时,它会导致 UI 线程崩溃,因为这是非法的。所以如果任何时候你想与 UI 线程交互,当你在 doInBackground 上工作时,你需要重写 OnPostExecute() //这个函数在 doInBackground 函数作业完成时被调用。因此,当您在 doInBackground () 或您在 doInBackground () 中完成工作时,您可以通过此更新 UI 线程内容

于 2019-09-19T10:45:58.813 回答