Android多线程通信-----AsyncTask

当用户点击某个app,Android系统会启动一个进程,该进程包含一个Thread,称为UI 线程或主线程,主线程中有很多需要处理的事件,如系统事件处理,用户输入事件处理,UI绘制,Service,Alarm等等,而默认我们自己功能的处理逻辑也是运行在主线程的,但是如果是比较耗时的计算操作,比如网络请求或是数据读取等也在主线程执行,我们可能会感觉到明显的界面卡顿,卡顿一段时间后系统就会报ANR。。。

因此,为了保证APP顺畅地运行,需要另起线程来处理耗时操作,AsyncTask就是异步线程实现的方式之一。
AsyncTask是一个轻量级地可以跟UI线程进行通信的异步线程方式,适合于耗时比较短的计算操作,最多是只有几秒钟的耗时操作。下面简单介绍下:

AsyncTask的使用

AyncTask操作一共分为四步,顺序执行:

  1. onPreExecute,在后台任务执行之前调用,运行在UI线程,一般是后台任务执行前的预备工作,比如弹后台任务执行的进度条提示给用户;
  2. doInBackground,运行在后台线程,在后台执行比较耗时的计算操作;这一步产生的计算结果可推送给onPostExecute;并且也可以通过使用publishProgress 将任务执行的进度推送给onProgressUpdate;此方法必须实现
  3. onProgressUpdate, 运行在UI线程,调用publishProgress后,此接口就会被回调到;用于展示后台计算任务的进度情况;如果任务被取消的话,此接口也不会再收到回调;
  4. onPostExecute, 运行在主线程,doInBackground后台任务执行结束,就会调用到此接口,后台计算结果也会传递到这个接口的参数中;
protected final void publishProgress(Progress... values) { 
	if (!isCancelled()) {
		getHandler().obtainMessage(MESSAGE_POST_PROGRESS,new AsyncTaskResult<Progress>(this, values)).sendToTarget();
	}
}

注: AsyncTask是一个抽象类,你必须实现执行后台任务的抽象接口doInBackground

AsyncTask任务的取消

一个AsyncTask任务在任何时候都可以通过调用cancel(boolean)来取消;

  • 调用了cancel(boolean),再调用isCancelled()会始终返回true;
  • 调用了cancel(boolean)doInBackground执行结束就不会再回调到onPostExecute里,而是回调到onCancelled(Object)
private void finish(Result result) {
      if (isCancelled()) {
            onCancelled(result);
       } else {
            onPostExecute(result);
       }
        mStatus = Status.FINISHED;
    }
  • 为了保证任务尽可能快地被取消,你可以在doInBackground中通过isCancelled()轮询检查任务是否已经被取消,取消则可直接结束后台任务的执行

任务的执行顺序,并行,串行?

AsyncTask任务从Android3.0之后为了避免并行操作引起的应用错误,后台任务都是在同一线程中执行,如果你想要并行执行的话可以通过调用executeOnExecutor(java.util.concurrent.Executor, Object[])来实现

@hide
 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);
                }
            }
       };
    }

    private void postResultIfNotInvoked(Result result) {
        final boolean wasTaskInvoked = mTaskInvoked.get();
        if (!wasTaskInvoked) {
            postResult(result);
        }
    }

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

AsyncTask 内部Handler实现

AsyncTask内部实现也有用到Handler,后台线程与UI线程的通信就是通过Handler实现的,将doInBackground执行的后台结果通过Handler post到UI线程

 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 static Handler getMainHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler(Looper.getMainLooper());
            }
            return sHandler;
        }
    }

为什么AsyncTask的创建和execute都要在主线程执行?

因为execute()实现里会直接调用onPreExecute(),这个接口定义是在主线程执行的,所以execute()也要在主线程里调用

    @MainThread
    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;
    }

写在最后:
AsyncTask适合于耗时比较短的计算操作任务,多线程通信除了AsyncTask,还有IntentService,Handler等,稍后会一一说下自己的理解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值