From source code analysis AsyncTask

AsyncTask is a lightweight asynchronous task class, it can perform background tasks in the thread pool, and then pass the progress and implementation of the final results to the main thread and update the UI in the main thread.
There are four main methods core, their meanings are shown in FIG.

  1. onPreExecute (): In the main thread execution, before asynchronous task execution, this method is called, is generally used to do some preparation work.
  2. doInBackground (Params ... params): In the thread pool implementation, the method used to perform asynchronous tasks, params parameter indicates the input parameters asynchronous tasks. In this method can update task progress by publishProgress method, publishProgress method calls onProgressUpdate method. Further this method needs to return the results to the onPostExecute method.
  3. onProgressUpdate (Progress ... Values): In the main thread execution, when a background task execution schedule changed this method will be called.
  4. onPostExecute (Result result): in the main thread execution, after the asynchronous task execution, this method is called, the result of which is the return value of the parameter background tasks, namely the return value of doInBackground.

AsyncTask in particular during use also certain conditions , there are the following:

  1. AsyncTask class must be loaded in the main thread, which means that the first visit AsyncTask must take place in the main thread, of course, this process has been completed automatic system Android4.1 above and in. In Android5.0 source code, you can see the main method ActivityThread, it will call the init method AsyncTask, which meets the class AsyncTask must be loaded in this condition the main thread.
  2. AsyncTask objects must be created in the main thread.
  3. execute method must be called on the UI thread.
  4. Do not call onPreExecute, onPostExecute, doInBackground and onProgressUpdate method directly in the program.
  5. A AsyncTask object can only be performed once, that can only be called once the execute method, otherwise it will report a runtime exception
    AsyncTask serial tasks, but can be performed in parallel tasks executeOnExecutor method.

AsyncTask fact, there are essentially two thread pool (SerialExecutor: for sorting tasks; THREAD_POOL_EXECUTOR: real mission) and handler composed of the following to analyze the source code.

Source code analysis

In order to analyze the working principle of AsyncTask, we start to analyze it execute, execute method will invoke executeOnExecutor method, as shown in their implementation.

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


 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 tasks There are three main state PENDING, RUNNING, FINISHED, you can see, the task of PENDING time will continue to run only when, and directly into RUNNING, through the back of the source code, you can still see in the future when the task is completed, will turn into FINISHED, which explains the fifth point conditions (Why a AsyncTask object can only be executed once)
continue to look down, onPreExecute()which is the first core method we mentioned above, it was invoked directly in the source code, we do not need to write program calls. Then mWorker.mParams = params exec.execute(mFuture), there is the emergence of two not mentioned mWorker and mFuture, we have to know what these two things yes.
First mWorker :

     private final WorkerRunnable<Params, Result> mWorker;
     
     private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
          Params[] mParams;
      }
      
    public interface Callable<V> {
        V call() throws Exception;
    }

Well, the clues broken, we have to find a place to call it. It is found in the constructor of 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);
                }
            }
        };
    }

This constructor can be divided into three instantiated, mHandler, mWorker, mFuture, the other first whether we look at mWorker.
First, look at the code in the try block

Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);	//设置子线程优先执行
result = doInBackground(mParams);

Here there was a second core code doInBackground, found to be an abstract function, we need to realize their own

protected abstract Result doInBackground(Params... params);

Then finally block in postResult(result)which the relevant code is

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

Here is very familiar, and I will be here all the relevant code stickers out, analyzed together

    1、private Handler getHandler() {
            return mHandler;
        }


    2、mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
                        ? getMainHandler()
                        : new Handler(callbackLooper);


    3、private static Handler getMainHandler() {
            synchronized (AsyncTask.class) {
                if (sHandler == null) {
                    sHandler = new InternalHandler(Looper.getMainLooper());
                }
                return sHandler;
            }
        }
       

     4、private static class InternalHandler extends Handler {
        public InternalHandler(Looper looper) {
            super(looper);
        }
        @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;
            }
        }
    }

    5、private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }
  
    6、private static class AsyncTaskResult<Data> {
        final AsyncTask mTask;
        final Data[] mData;

        AsyncTaskResult(AsyncTask task, Data... data) {
            mTask = task;
            mData = data;
        }
    }

I posted here five places in the code, one run, mainly in order to explain what is in this handler thread.
The first one is to return a handler, nothing to say.
The second block is the constructor AsyncTask in the above code is a ternary operator, also well understood.
Third and fourth are examples of this Handler, and rewrite handleMessage method.
The fifth block is the finish of the method of AsyncTask (first determines whether the current asynctask been canceled, Ruoguo not cancel onPostExecute (result), this fourth core code is executed, this time the data has been pulled back, here we are almost performed over several important methods, and then switched to the execution state asynctask fINISHED state.)
the sixth block is the result of the current data request from the network to the data stored in the result. Then message.sendToTarget, it is to send out through the handler message. Here we do not understand can go to mend the principle message queue.
At this point, mWorker on the analysis is complete, the conclusion, mWorker mainly stored doInBackground way we rewrite on the need to code at runtime thread pool. Then sent via handler.
Then mFuture , which is inherited from FutureTask, and mWorker as a parameter, FutureTask the code a bit more, mainly in its done () will call the call mWorker () method. In the done () it is also called postResultIfNotInvoked method.

void postResultIfNotInvoked Private (the Result Result) {
Final Boolean wasTaskInvoked mTaskInvoked.get = ();
IF (wasTaskInvoked!) {
postResult (Result);
}
}
In fact, the constructor mWorker, we have mTaskInvoked.set (true);
So here the postResult (result) is generally unreachable.
OK, we almost general understanding mWorker, mFuture about how to use, we can continue to see the top of the executeOnExecutormethod of exec.execute(mFuture);how it works.

public interface Executor {
    void execute(Runnable command);
}

OK, clues and broken, we keep looking exec constructor. We found that when an incoming call this executeOnExecutor parameter is sDefaultExecutor, then keep looking.

	private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
	
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    
    private static class SerialExecutor implements Executor {
            final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
            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);
            }
        }

	    static {
	        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
	                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
	                sPoolWorkQueue, sThreadFactory);
	        threadPoolExecutor.allowCoreThreadTimeOut(true);
	        THREAD_POOL_EXECUTOR = threadPoolExecutor;
	    }

SerialExecutor is an internal class two methods, namely, execute and scheduleNext is a class, read the note when needed. Then all of a sudden here comes to the two thread pool, we had mentioned that a task is responsible for ordering, for a real mission. So with this see, it is easy to find SERIAL_EXECUTOR is responsible for the task queue, and it will be runnable execute methods into mTasks the tail, and then determines whether the current mActive is empty, if not empty the call scheduleNext () method. Then remove the team's first task in the task queue scheduleNext, if not null is assigned to mActive objects and pass THREAD_POOL_EXECUTOR for execution.
The THREAD_POOL_EXECUTOR is in the static code block when he constructed, is also a thread pool.
So now the source process is over, there is a problem doInBackground in the end what is called in the thread.
We still have to look at FutureTask

public class FutureTask<V> implements RunnableFuture<V> {
    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }
     
     public void run() {
        if (state != NEW ||
            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }
}

Here shows only a few important ways, we can see, run method here has result = c.call();the c is our mWorker, which explains doInBAckgournd is running in the child thread.

Published 57 original articles · won praise 3 · Views 6219

Guess you like

Origin blog.csdn.net/qq_39830579/article/details/88751598