当前位置: 首页 > 知识库问答 >
问题:

异步任务Android执行

严书
2023-03-14

这是在一次Android采访中被问到的。有人问我是否可以从异步任务 1 的 doInBackground() 方法(让它成为 Task1)启动另一个异步任务(让它成为 Task2)。我浏览了文档,其中说了以下内容:

必须在UI线程上创建任务实例。

必须在 UI 线程上调用 execute(Params...)。

根据这些陈述,我认为从另一个任务的后台方法启动一个任务是不可能的。此外,async任务具有UI方法(不能在后台线程上使用),因此加强了我的论点,我认为这是不可能的。

在检查一个简单的演示应用程序时,我发现确实可以这样做。一些演示代码:

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext = this;
        init();
        Log.v ("gaurav", "Thread is : " + Thread.currentThread().getName());
        Task1 task = new Task1();
        task.execute();
    }

class Task1 extends AsyncTask {
    @Override
    protected Object doInBackground(Object... params) {
        // TODO Auto-generated method stub
        Log.v ("gaurav", "Thread task 1 is : " + Thread.currentThread().getName());

        Task2 task = new Task2();

        task.execute();
        return null;
    }
}

class Task2 extends AsyncTask {
    @Override
    protected Object doInBackground(Object... params) {
        // TODO Auto-generated method stub
        Log.v ("gaurav", "Thread task 2 is : " + Thread.currentThread().getName());

        Log.v ("gaurav", "Task 2 started");
        return null;
    }
}

我得到以下日志,表明执行成功:

> 08-07 09:46:25.564: V/gaurav(2100): Thread is : main 08-07
> 09:46:25.564: V/gaurav(2100): Thread task 1 is : AsyncTask #3 08-07
> 09:46:25.564: V/gaurav(2100): Thread task 2 is : AsyncTask #4 08-07
> 09:46:25.564: V/gaurav(2100): Task 2 started

我已经在ICS,KK和L设备上检查过了,它对所有人都很好。

我能想到的一个原因是,在我的第二个任务中,我没有覆盖任何UI方法,也没有进行任何UI更新,因此这不会导致任何问题,但我不确定。即使是这样,它也违反了开发人员指南中提到的线程规则。

作为参考,我也签出了这个链接:从另一个AsyncTask doInBackground()启动AsyncTask,但答案是使用doInBackground()内的runOnUiThread()方法启动第二个任务。我想知道这里发生了什么。谢谢

共有2个答案

仲和韵
2023-03-14
public class MainActivity extends Activity {

    private final static String TAG = "ThreadingAsyncTask";
    private ImageView mImageView;
    private ProgressBar mProgressBar;
    private int mDelay = 500;

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImageView = (ImageView) findViewById(R.id.imageView);;
        mProgressBar = (ProgressBar) findViewById(R.id.progressBar);

        final Button button = (Button) findViewById(R.id.loadButton);
        button.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                new LoadIconTask().execute(R.drawable.cheetah);
            }
        });
        final Button otherButton = (Button) findViewById(R.id.otherButton);
        otherButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "I'm Working",
                        Toast.LENGTH_SHORT).show();
            }
        });
    }


    class LoadIconTask extends AsyncTask<Integer, Integer, Bitmap> {
        @Override
        protected void onPreExecute() {
            mProgressBar.setVisibility(ProgressBar.VISIBLE);
        }
        @Override
        protected Bitmap doInBackground(Integer... resId) {
            Bitmap tmp = BitmapFactory.decodeResource(getResources(), resId[0]);
            // simulating long-running operation
            for (int i = 1; i < 11; i++) {
                sleep();
                publishProgress(i * 10);
            }
            return tmp;
        }
        @Override
        protected void onProgressUpdate(Integer... values) {
            mProgressBar.setProgress(values[0]);
        }
        @Override
        protected void onPostExecute(Bitmap result) {
            mProgressBar.setVisibility(ProgressBar.INVISIBLE);
            mImageView.setImageBitmap(result);
        }
        private void sleep() {
            try {
                Thread.sleep(mDelay);
            } catch (InterruptedException e) {
                Log.e(TAG, e.toString());
            }
        }
    }
}
安星汉
2023-03-14

让我们将代码更改为以下内容:

class Task1 extends AsyncTask {
    @Override
    protected Object doInBackground(Object... params) {
        // TODO Auto-generated method stub
        Log.v ("gaurav", "Thread task 1 is : " + Thread.currentThread().getName());

        Task2 task = new Task2();
        task.execute();

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        Log.v ("gaurav", "Log after sleeping");

        return null;
    }
}

class Task2 extends AsyncTask {
    @Override
    protected Object doInBackground(Object... params) {
        // TODO Auto-generated method stub
        Log.v ("gaurav", "Thread task 2 is : " + Thread.currentThread().getName());

        Log.v ("gaurav", "Task 2 Started");
        return null;
    }
}

现在LogCat返回:

08-07 06:13:44.208    3073-3073/testapplication V/gaurav﹕ Thread is : main
08-07 06:13:44.209    3073-3091/testapplication V/gaurav﹕ Thread task 1 is : AsyncTask #1
08-07 06:13:49.211    3073-3091/testapplication V/gaurav﹕ Log after sleeping
08-07 06:13:49.213    3073-3095/testapplication V/gaurav﹕ Thread task 2 is : AsyncTask #2
08-07 06:13:49.213    3073-3095/testapplication V/gaurav﹕ Task 2 Started

如您所见,Task 2是在Task 1执行结束后执行的(即使在睡眠5秒之后)。这意味着在第一个任务完成之前不会启动第二个任务。

为什么?原因在于AsyncTask的源代码。请考虑<code>execute()

public synchronized void execute(final Runnable r) {
    mTasks.offer(new Runnable() {
        public void run() {
            try {
                r.run();
            } finally {
                scheduleNext();
            }
        }
    });
    if (mActive == null) {
        scheduleNext();
    }
}

和<code>scheduleNext()</code>方法:

protected synchronized void scheduleNext() {
    if ((mActive = mTasks.poll()) != null) {
        THREAD_POOL_EXECUTOR.execute(mActive);
    }
}

这些方法中最重要的关键字是<code>synchronized<code>这确保了这些方法只能同时在一个线程中运行。当您调用<code>execute

从其他线程执行异步任务有什么问题?从Jelly Bean开始,异步任务在UI线程上的应用程序启动时被类加载,因此回调保证会在UI线程中发生。然而,在Jelly Bean发布之前,如果另一个线程创建了异步工作,则回调可能不会在正确的线程上发生。

因此,<code>AsyncTask</code>实现只能在Jelly Bean(和)之前的平台上从UI线程调用。

澄清:请考虑以下示例,它简单地澄清了Android不同平台版本之间的差异:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main2);

    new Thread() {
        @Override
        public void run() {
            Task1 task = new Task1();
            task.execute();
        }
    }.start();
}

class Task1 extends AsyncTask {
    @Override
    protected Object doInBackground(Object... params) {
        return null;
    }
}

它在Android 5.1上运行良好,但在Android 2.3上崩溃,出现以下异常:

08-07 12:05:20.736      584-591/github.yaa110.testapplication E/AndroidRuntime﹕ FATAL EXCEPTION: Thread-8
    java.lang.ExceptionInInitializerError
            at github.yaa110.testapplication.Main2Activity$1.run(Main2Activity.java:21)
     Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
            at android.os.Handler.<init>(Handler.java:121)
            at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
            at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
            at android.os.AsyncTask.<clinit>(AsyncTask.java:152)
            at github.yaa110.testapplication.Main2Activity$1.run(Main2Activity.java:21)
 类似资料:
  • 在Server程序中如果需要执行很耗时的操作,比如一个聊天服务器发送广播,Web服务器中发送邮件。如果直接去执行这些函数就会阻塞当前进程,导致服务器响应变慢。 Swoole提供了异步任务处理的功能,可以投递一个异步任务到TaskWorker进程池中执行,不影响当前请求的处理速度。 程序代码 基于第一个TCP服务器,只需要增加onTask和onFinish 2个事件回调函数即可。另外需要设置task

  • 当用户无法登录他们的帐户时,我正在尝试执行警报。也就是说,当我尝试使用下面的代码完成此操作时,我会抛出以下错误: 原因:java.lang.RuntimeException:无法在未调用Looper.prepare()的线程[AsyncTask#1,5,main]内创建处理程序 我怎样才能解决这个问题?请参阅下面的代码。 登录活动

  • 本文向大家介绍C#异步执行任务的方法,包括了C#异步执行任务的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了C#异步执行任务的方法。分享给大家供大家参考。具体如下: 希望本文所述对大家的C#程序设计有所帮助。

  • 本文向大家介绍详解Android App中的AsyncTask异步任务执行方式,包括了详解Android App中的AsyncTask异步任务执行方式的使用技巧和注意事项,需要的朋友参考一下 基本概念 AsyncTask:异步任务,从字面上来说,就是在我们的UI主线程运行的时候,异步的完成一些操作。AsyncTask允许我们的执行一个异步的任务在后台。我们可以将耗时的操作放在异步任务当中来执行,并

  • 本文向大家介绍Android的异步任务AsyncTask详解,包括了Android的异步任务AsyncTask详解的使用技巧和注意事项,需要的朋友参考一下 AsyncTask,顾名思义,异步任务。说到异步,最简单的理解就是不同步。再复杂一点理解,就得举例子了。 假设我要去火车站买票,刚到火车站我突然发现我忘了带身份证。怎么办?怎么办! 想办法,想办法!我想我应该找个在学校的同学帮我送过来,因为我不

  • 我正在尝试使用以下代码: 是我在Android应用程序中使用的OAuth2Client的一部分。我得到这个错误: 我会提供一些帮助。 谢谢