【问题标题】:Start AsyncTask from another AsyncTask doInBackground()从另一个 AsyncTask doInBackground() 启动 AsyncTask
【发布时间】:2013-10-22 14:27:59
【问题描述】:

我正在尝试从另一个 AsyncTask 的 doInBackground()-method 启动一个 AsyncTask...

这甚至可能吗?如果是,我该如何实现?

稍后编辑:

我的想法是我启动一个异步任务,它将从 Tweeter 获取我的状态......直到这里一切都好......但是当我遇到一些特定的推文时,我需要使用来自我的服务器的一些信息来修改它们,在这里我会进行另一个网络操作,因为我需要等到我从服务器获取信息,所以我这样做:

GetContent getContentServiceAsyncTask = new GetContent(context);
try {
    tweetText = Uri.decode(getContentServiceAsyncTask.execute(
            URL_GET_CONTENT, jsonRequest).get());
} catch (InterruptedException e) {
    Log.e(TAG_DEBUG, "InterruptedException: ", e);
} catch (ExecutionException e) {
    Log.e(TAG_DEBUG, "ExecutionException: ", e);
}

这是从doInBackground()方法中已经启动的AsyncTask开始的...

我知道我可以在 AsyncTask 中添加方法并在 doInBackground() 方法中调用它们,但我需要在其他地方使用它们,我从 onPostExecute 启动这些 AsyncTasks ...

如果你们认为有一个简单的解决方法,这不会影响我的表现,那就太好了......如果不是,我将创建一些静态方法,我将在我需要的所有 AsyncTasks 中调用(但这需要我修改很多代码)

【问题讨论】:

  • 您为什么要这样做? developer.android.com/reference/android/os/AsyncTask.html。检查主题线程规则
  • 这是可能的,但如果您尝试从第二个任务的 onPostExecute 修改 UI,它会崩溃,因为它不在主线程中执行。
  • 如果你的第二个任务不包含UI操作,你可以开始。
  • 建议在第一个异步执行后启动异步。
  • 嗨,Negru,您的第一个异步任务必须在并行任务架构上运行。因此,您使用 executor ==> "new FirstTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, );" 开始您的第一个任务第二个任务在您的第一个任务的 doInbackgreound() 中运行。我将创建示例应用程序并编写答案。

标签: android android-asynctask


【解决方案1】:

AsyncTasks 应该从 ma​​in (UI) 线程运行。您不应从 doInBackground 运行另一个 AsyncTask,因为此方法是在非 UI 线程上执行的。

在你的情况下,我可以建议你两件事:

  1. 将两个 AsyncTaks 的处理合并到一个请求中
  2. 从您的第一个任务的 onPostExecute 启动您的第二个 AsyncTask。

【讨论】:

  • @downvoter:介意解释一下投反对票的原因吗?
  • 我做不到……我需要一个阻塞的 AsyncTask,我用 .get() 调用它……我不能等到当前的 AsyncTask 完成并在onPostExecute().
【解决方案2】:

根据下面的帖子,您可以执行 Activity.runOnUiThread() 在主线程(从另一个线程)上运行 Runnable。

所以理论上你可以这样做:

  • 运行异步任务
  • 在您的 AsyncTask 中执行 Activity.runOnUiThread(Runnable) 并从该可运行对象中启动一个新的 AsyncTask

顾名思义,Activity.runOnUiThread() 在主线程上执行 runnable

但这有点老套。

代码应该是这样的:(没有测试)

// first task
    (new AsyncTask<String, String, String>() {

        @Override
        protected String doInBackground(String... params) {
            ParentActitity.this.runOnUiThread(new Runnable() {

                @Override
                public void run() {
                    //second async stared within a asynctask but on the main thread
                    (new AsyncTask<String, String, String>() {

                        @Override
                        protected String doInBackground(String... params) {
                            // TODO Auto-generated method stub
                            return null;
                        }

                    }).execute();

                }
            });
            return null;
        }

    }).execute();

这个嵌套示例在生产环境中不是一个好的样式,因为(恕我直言)它几乎不可读。

补充说明:

Activity.runOnUiThread(Runnable) 不是静态的!这就是为什么我的示例使用 ParentActivity(.this).runOnUiThread(Runnable)。

【讨论】:

  • 我应该如何运行它?请记住,我在这样的 AsyncTask 类中:public class DoSomeBackgroundWork extends AsyncTask&lt;String, String, Boolean&gt; {...}
  • 谢谢 jmeier,但我收到以下警告:“范围内无法访问 TwitterActivity 类型的封闭实例”
  • 您必须在引用您的 TwitterActivity 实例时调用它。你会这样做吗?
  • 不,但最后我认为这会太麻烦而且对性能不利,所以我创建了我需要在这个 AsyncTask 中直接调用的方法......不过,我想你会回答最接近我正在寻找的东西,所以我会接受它。谢谢。
【解决方案3】:

您不能在 doInBackground() 中执行此操作,但您可以从 onProgressUpdate() 执行此操作,例如,因为它在 UI 线程上运行。请记住,在 3.0 之后它们将被放在同一个队列中并且不会并行运行,请参阅executeOnExecutor

【讨论】:

  • 我知道 executeOnExecutor,但我需要我的应用在所有版本的 Android(> 8) 上保持一致。
【解决方案4】:

请参阅 AsyncTask()AsyncTask#execute() 的文档。两者都声明必须在主 UI 线程上调用它们。

【讨论】:

  • 我知道,这就是为什么我问你们是否知道一些解决方法!
  • @lonutNegru 您的问题是“这是否可能”。我的回答是“不”(至少不是直接的)。您必须在主线程上发布一个可运行文件,其中包含执行新 AsyncTask 的代码。 jmeier 的回答提供了一种可能的方法。
  • 是的,谢谢Alex Lockwood,最后我选择修改结构以避免这个问题并在未来安全:) ...
【解决方案5】:

基本上是我写的样本;

public class MainActivity extends Activity {

View view;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    view = new View(this);
    setContentView(view);

    view.setBackgroundColor(Color.RED);

    new FirstTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null);
}

private class FirstTask extends AsyncTask<Void, Void, Void>
{
    @Override
    protected Void doInBackground(Void... params) {

        new SecondTask().execute();
        try {
            Thread.currentThread().sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        Log.e("task","first");
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        view.setBackgroundColor(Color.GREEN);   
    }

}

private class SecondTask extends AsyncTask<Void, Void, Void>
{
    @Override
    protected Void doInBackground(Void... params) {
        Log.e("task","second");
        return null;
    }
}

}

【讨论】:

  • 正如 Penna 所说,Executor 是在 API 级别 11 中添加的......所以这不是我这样做的方式。
【解决方案6】:

很简单,你必须使用 Executor:

new AsyncTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new String[]{"param 1", "param 2"});

此方法通常与 THREAD_POOL_EXECUTOR 一起使用,以允许多个任务在 AsyncTask 管理的线程池上并行运行,但是您也可以使用自己的 Executor 来进行自定义行为。

警告:允许多个任务从线程池并行运行通常不是人们想要的,因为它们的操作顺序没有定义。例如,如果这些任务用于修改任何共同的状态(例如由于单击按钮而写入文件),则无法保证修改的顺序。如果不仔细工作,在极少数情况下,较旧版本的数据可能会覆盖较新版本的数据,从而导致难以理解的数据丢失和稳定性问题。此类更改最好​​按顺序执行;为了保证无论平台版本如何都可以序列化此类工作,您可以将此函数与 SERIAL_EXECUTOR 一起使用。

【讨论】:

  • 这是一个非常古老的问题。现在有更好,更简单的解决方案:D
【解决方案7】:

通过启动一个单独的线程来处理这部分数据管理,采取这几个 inet 操作并让它们参与不是更好吗? google 到处放它的模式,如果你看起来最接近它们都是从简单的类派生的……这个 API 使 android 像一个涉及回调的蜘蛛网回调……试着理解 java 的基础知识,写一篇文章并不难好的代码。服务/内容解析器/接收器/加载器以某种方式受到限制...线程几乎能够实现您想要的任何东西...

你们中的大多数人在使用代码时不加思考,甚至​​没有尝试了解它是如何工作的,也不了解编程的关键是什么。我尽量不使用我不知道基础的代码。如果我需要,我会彻底研究它。我现在使用 Java 进行黑魔法,我认为它是 DATA FLOW A-> B-> C 等 .. 良好的 FLOW 是必不可少的

编辑:

是的,我为您的问题编写了解决方案

有很多方法可以实现你想要的,但这不是我对你编写器代码的回应

  • 您可以使用 IntentService 类,它有一个内置队列 --- 只需为每次传输使用单独的 startService() 调用。

  • 您可以使用 Thread - 我的首选方式

  • 您可以使用服务

  • 你可以使用 AsyncTaskLoader

  • 但不要使用 ASYNC TASK,如果您需要多于 两个同时连接的 ONCE 他们都在 MODERN PHONES 上作为 QUEUE 运行单线程(ps。您可以在 EXECUOR 上运行它们作为解决方法)

由于 JAVA 1.5 任务与线程分离 - 添加了

自定义线程是什么意思

线程(正如我们所说的)不是线程类对象,但它是在线程类的 run() 方法中定义的任务,因此任何从线程派生的类仍然开始线程(又名任务)

    public synchronized void start() {
        checkNotStarted();

        hasBeenStarted = true;
        /** 
         * look at this line i'ts rerouting run() code of youre thread class  
         * to native method from there thread is created in pure C code 
         */
        nativeCreate(this, stackSize, daemon);
    }

例如在 POSIX 中是这样的:

int  pthread_create(pthread_t  *  thread, pthread_attr_t * attr, void *
   (*start_routine)(void *), void * arg);

从这一点我们可以讨论MULTITASKING,当操作系统通过同时执行多个任务在一段时间内执行它们时

JAVA 1.5 开始,有一个 Executor 接口,它提供了一种将任务提交与每个任务将如何运行的机制(包括线程使用的详细信息)分离的方法,调度等。通常使用执行器而不是显式创建线程。你有很多执行者,其中之一是:ThreadPerTaskExecutor

class ThreadPerTaskExecutor implements Executor {
      public void execute(Runnable r) {
          new Thread(r).start();
      }
  }

此执行器为每个任务生成一个新线程。

回到 AsyncTask:

AsyncTaskM<P, P, R>.executeOnExecutor(Executor,P);

允许多个任务在 AsyncTask 管理的线程池上并行运行,但是您也可以使用自己的 Executor 进行自定义行为。

是的,如果你不喜欢它并且不知道足够的啤酒给别人做它:)

我希望这个补充能改变你对投票的看法。

【讨论】:

  • 您的回复没有给出任何实现这一目标的方法,这就是我投反对票的原因。有一些方法可以做得更好,接口、自定义线程、广播,但在我发布这个问题时,我并不知道其中有很多。我还推荐使用 EventBus 来解耦组件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多