线程规则异步任务



AsyncTask 有 5 个线程规则:

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

  1. 类必须在 UI 线程上加载。这是完成的 自Build.VERSION_CODES起自动生效。JELLY_BEAN。

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

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

  4. 不要调用 onPreExecute((, onPostExecute(Result(, doInBackground(Params...(, onProgressUpdate(Progress...( 手动.

  5. 该任务只能执行一次(如果 尝试第二次执行。

但是,我不太了解规则 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 线程(主(之外的另一个线程 (Thread-264( 中调用execute()方法?

我读了这篇文章,但它没有解释为什么。非常感谢!

来自安卓官方网站

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

有几点我们需要澄清。

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

第 1 步:当您致电时

Task task = new Task();

看看AsyncTask源代码。

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 线程处理程序的处理程序,然后创建一个调用doInBackground方法的 Runnable 方法(我们在这里的计算(,然后返回一个 Future(将在将来的某个时间点返回计算结果(。

第 2 步:然后您致电

task.execute();

看看AsyncTask源代码。

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 的调用线程(在本例中为匿名线程(时调用。然后,它在其执行器中执行未来。

计算完成后,它将调用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 线程。

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

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

虽然onPreExecute()将在调用execute()的任何线程上运行,但其余 2 个方法将由Handler运行。

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

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

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

相关内容

  • 没有找到相关文章

最新更新