AsyncTask解析

大家都知道,使用AsyncTask类,可以很方便的从子线程切换到UI线程。我们今天从源码来了解一下它的原理。

AsyncTask是一个抽象类,我们先看看AsyncTask里面的四个方法:

  • onPreExecute()(不必重写)
    在doInBackground方法之前执行,用于执行一些初始化操作,如显示一个等待框。

  • doInBackground(Params...)(必须重写)
    主要处理一些耗时操作,在子线程运行。执行过程中可以用publishProgress更新UI,如更新进度。使用publishProgress会执行onProgressUpdate方法(需要我们重写)。

  • onProgressUpdate(Progress...)(不必重写)
    在doInBackground内使用publishProgress方法会执行此处代码,可以用于更新UI。

  • onPostExecute(Result)(不必重写)
    doInBackground执行完之后就会调用这个方法,我们可以根据doInBackground返回的数据,进行UI操作。

以上是AsyncTask比较重要的方法,掌握了它,你能很好的应用这个AsyncTask类。但是身边的朋友都不推荐使用,最后我会解释一下为什么。我们先跟着源码了解一下这个类。

我们look两眼构造函数:

public AsyncTask() { 
    mWorker = new WorkerRunnable() { 
        public Result call() throws Exception { 
            mTaskInvoked.set(true);   
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 
            return postResult(doInBackground(mParams)); 
        } 
    }; 
    mFuture = new FutureTask(mWorker) { 
        @Override 
        protected void done() { 
            try { 
                final Result result = get(); 
                postResultIfNotInvoked(result); 
            } catch (InterruptedException e) { 
                android.util.Log.w(LOG_TAG, e); 
            } catch (ExecutionException e) { 
                 throw new RuntimeException("An error occured while executing doInBackground()", e.getCause()); 
            } catch (CancellationException e) { 
                postResultIfNotInvoked(null); 
            } catch (Throwable t) { 
                throw new RuntimeException("An error occured while executing " + "doInBackground()", t); 
            }
        } 
    }; 
} 

很简单,只是初始化了mWorker和mFurure两个参数。
如果我们要启动一个任务,我们需要执行execute(Params...)方法,我们look这个方法:

public final AsyncTask execute(Params... params) { 
    return executeOnExecutor(sDefaultExecutor, params); 
}

接着看executeOnExecutor方法:

public final AsyncTask 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(); 
    // 这里其实是doInBackground(Params...)的参数
    mWorker.mParams = params; 
    // 执行后台任务
    exec.execute(mFuture); 
    return this; 
} 

我们先解释一下sDefaultExecutor这个值,因为要了解 exec.execute(mFuture),我们的先知道exec,即sDefaultExecutor的值。

public static final Executor SERIAL_EXECUTOR = new SerialExecutor(); 
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

我们继续追下去,看SerialExecutor这个类:

  private static class SerialExecutor implements Executor { 
      final ArrayDeque mTasks = new ArrayDeque(); 
      Runnable mActive; 
      public synchronized void execute(final Runnable r) { 
          mTasks.offer(new Runnable() { 
              public void run() { 
                  try { 
                      r.run(); 
                  } finally { 
                      scheduleNext(); 
                  } 
              } 
          }); 
          if (mActive == null) { 
              scheduleNext(); 
          } 
    } 
    protected synchronized void scheduleNext() { 
        if ((mActive = mTasks.poll()) != null) { 
            THREAD_POOL_EXECUTOR.execute(mActive); 
        } 
    } 
} 

因为调用了exec.execute(mFuture)这个,对照源码,参数r就是我们的mFuture了,mFuture执行了run方法,这个run方法其实是调用了innerRun方法,我们直接看到innerRun这个方法:

void innerRun() { 
    if (!compareAndSetState(READY, RUNNING)) 
        return; 
    runner = Thread.currentThread(); 
    if (getState() == RUNNING) { 
        // recheck after setting thread  
        V result; 
        try { 
            result = callable.call(); 
        } catch (Throwable ex) { 
            setException(ex); 
            return; 
        } 
        set(result); 
    } else { 
        releaseShared(0); // cancel  
    } 
} 

callable是个什么鬼?其实就是我们构造函数传进来的mWorker。看到构造函数,call()方法中调用了postResult(doInBackground(mParams)),这就调用了我们重写的doInBackground(mParams)了。我们可以look一下postResult这个方法:

private Result postResult(Result result) { 
    Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult(this, result)); 
    message.sendToTarget(); 
    return result; 
} 

这里就是把获取的结果,通过handler机制,把result发用到UI线程处理。我们可以看看这个自定义的hander长咋样:

private static class InternalHandler extends Handler { 
    @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; 
} 

到这里,我们之前说的4个重要的方法也都全部调用了。还有一个方法的实现,就是在用于在doInBackground方法里通知更新UI的publishProgress,代码:

protected final void publishProgress(Progress... values) { 
    if (!isCancelled()) { 
        sHandler.obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult(this, values)).sendToTarget(); 
    } 
} 

从源码可以知道,也是通过handler来更新UI的。

以上是AsyncTask整个源码的分析。我之前说过,身边很多朋友都不推荐使用这个类,因为啥呢??我来解释一下。

  • 生命周期不稳定
    大家都以为,我创建了一个AsyncTask,等Activity销毁会自动销毁,我们不用care。并非如此,如果activity销毁时,正在子线程执行耗时任务,那么子线程会继续do下去。如果我们不去手动cancel()它的话,doInBackground()会把结果通过handler发送到UI处理,可是UI已经销毁(为空)了,这时会报crash。
    再有,我们旋转屏幕的时候,他会重新去创建,又会重新执行一遍,这样会浪费资源,还取消不掉。

  • 内存泄露
    如果AsyncTask被声明为Activity的非静态的内部类,那么AsyncTask会保留一个对创建了AsyncTask的Activity的引用。这个Handler泄露差不多一样。因为Activity要销毁了,此时AsyncTask还在执行子线程耗时操作,还是持有Activity的引用,这样Activity无法被回收。

以上也就大神们不推荐使用这个类的原因。还能用吗??看你怎么使用咯。我在这里推荐使用rxjava代替AsyncTask,这个开源框架可以不但可以帮我们很好的解决问题,还给我们带很多方便。这个框架我以后我也会总结。

你可能感兴趣的:(AsyncTask解析)