线程规则AsyncTask

时间:2018-09-16 01:53:06

标签: android multithreading android-asynctask

AsyncTask具有5个线程规则:

  

该类必须遵循一些线程规则   正常工作:

     
      
  1. 必须在UI线程上加载AsyncTask类。这个做完了   自动从Build.VERSION_CODES.JELLY_BEAN开始。

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

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

  6.   
  7. 请勿调用onPreExecute(),onPostExecute(Result),   doInBackground(Params ...),onProgressUpdate(Progress ...)手动。

  8.   
  9. 该任务只能执行一次(如果出现以下情况,则会引发异常:   尝试执行第二次。)

  10.   

但是,我对规则2和3不太了解。我已经在以下代码上尝试过它们:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    log(Thread.currentThread().getName());

    new Thread(new Runnable() {
        @Override
        public void run() {
            log(Thread.currentThread().getName());
            Task task = new Task();
            task.execute();
        }
    }).start();
}

public class Task extends AsyncTask<Void, Void, Void> {

    @Override
    protected Void doInBackground(Void... voids) {
        return null;
    }
}

这是结果:

09-15 21:27:10.179 3310-3310/com.xxx.test D/com.xxx.test.MainActivity: main
09-15 21:27:10.179 3310-3329/com.xxx.test D/com.xxx.test.MainActivity: Thread-264

我有一个问题: 为什么我可以创建任务实例并在UI线程(主线程)之外的另一个线程(线程264)中调用execute()方法?

我读了this post,但没有解释原因。非常感谢!

2 个答案:

答案 0 :(得分:0)

来自Android official site

  

异步任务由运行在   后台线程,其结果发布在UI线程上。

我们需要澄清一些要点。

  1. 我们的计算将在后台线程上运行
  2. 计算结果将发布在UI线程上
  3. 它们不会阻止开发人员从非UI线程创建或调用AsyncTask

第1步:当您致电

Task task = new Task();

看看AsyncTask source code

public AsyncTask(@Nullable Looper callbackLooper) {
    mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
        ? getMainHandler()
        : new Handler(callbackLooper);

    mWorker = new WorkerRunnable<Params, Result>() {
        public Result call() throws Exception {
            mTaskInvoked.set(true);
            Result result = null;
            try {
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                result = doInBackground(mParams);
                Binder.flushPendingCommands();
            } catch (Throwable tr) {
                mCancelled.set(true);
                throw tr;
            } finally {
                postResult(result);
            }
            return result;
        }
    };

    mFuture = new FutureTask<Result>(mWorker) {
        @Override
        protected void done() {
            try {
                postResultIfNotInvoked(get());
            } catch (InterruptedException e) {
                android.util.Log.w(LOG_TAG, e);
            } catch (ExecutionException e) {
                throw new RuntimeException("An error occurred while executing doInBackground()",
                        e.getCause());
            } catch (CancellationException e) {
                postResultIfNotInvoked(null);
            }
        }
    };
}

首先,他们创建一个处理程序,该处理程序引用UI线程的处理程序,然后创建一个Runnable,该方法调用doInBackground方法(此处为我们的计算),然后返回Future(将返回计算结果)未来)。

第2步:然后您致电

task.execute();

看看AsyncTask source code

public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) {
    if (mStatus != Status.PENDING) {
        switch (mStatus) {
            case RUNNING:
                throw new IllegalStateException("Cannot execute task:"
                        + " the task is already running.");
            case FINISHED:
                throw new IllegalStateException("Cannot execute task:"
                        + " the task has already been executed "
                        + "(a task can be executed only once)");
        }
    }

    mStatus = Status.RUNNING;

    onPreExecute();

    mWorker.mParams = params;

    exec.execute(mFuture);

    return this;
}

onPreExecute()将在调用AsyncTask的调用线程(在本例中为您的匿名线程)中被调用。然后,它在其执行器中执行Future。

计算完成后,它将调用postResult方法。

private Result postResult(Result result) {
    @SuppressWarnings("unchecked")
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
            new AsyncTaskResult<Result>(this, result));
    message.sendToTarget();
    return result;
}

private static class InternalHandler extends Handler {
    public InternalHandler(Looper looper) {
        super(looper);
    }

    @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
    @Override
    public void handleMessage(Message msg) {
        AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
        switch (msg.what) {
            case MESSAGE_POST_RESULT:
                // There is only one result
                result.mTask.finish(result.mData[0]);
                break;
            case MESSAGE_POST_PROGRESS:
                result.mTask.onProgressUpdate(result.mData);
                break;
        }
    }
}

private void finish(Result result) {
    if (isCancelled()) {
        onCancelled(result);
    } else {
        onPostExecute(result);
    }
    mStatus = Status.FINISHED;
}

getHandler在此情况下是指UI线程的处理程序,因此onPostExecute将始终在UI线程上被调用。

结论:

  

AsyncTask允许正确且轻松地使用UI线程。这个班   允许您执行后台操作并在   UI线程,而无需操纵线程和/或处理程序。

答案 1 :(得分:0)

有3种保护方法,用户代码可以期望它们可以从UI运行

  1. onPreExecute()
  2. onProgressUpdate(Progress...)
  3. onPostExecute(Result)

尽管onPreExecute()将在调用execute()的任何线程上运行,其余2种方法将由Handler运行。

Handler类将与创建它的线程关联,它允许用户代码发布Runable在该特定线程上运行。在AsyncTask出现之前,想要更新UI(必须在UI线程上更新)的用户代码必须首先在UI线程上创建Handler,然后将Runable发布到该{{1} }在UI线程上执行任务。

Handler旨在简化这些繁琐的工作,它们的内部静态AsyncTask是在创建Handler实例之前由UI /主线程创建的。

即使可以在工作线程中使用AsyncTaskAsyncTask除外),我还是建议您遵循文档并在UI线程上创建/运行onPreExecute()