Android查缺补漏(线程篇)-- AsyncTask的使用及原理详细分析

本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8515304.html

一、AsyncTask的使用

AsyncTask是一种轻量级的异步任务类,可以很方便的在线程池中执行异步任务,并且将进度和结果传递给主线程。其底层由Thread+handler实现。

AsyncTask是一个抽象的泛型类,其类的声明如下:

public abstract class AsyncTask<Params, Progress, Result>

其中三个泛型参数代表的意义如下:

  • Parmas:参数类型
  • Progress:异步任务的执行进度类型
  • Result:异步任务执行完毕后返回结果的类型

在使用AsyncTask执行异步任务需要创建一个类,让这个类继承AsyncTask,并实现相关方法,具体形式如下,在下面代码中实现了几个重要的方法,每个方法代表的意义可以见注释:

/**
 * Created by liuwei on 18/2/28.
 */
public class MyAsyncTask extends AsyncTask<String, Integer, String> {

    /**
     * 在异步任务执行之前调用
     * 执行在主线程中
     */
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }

    /**
     * 执行异步任务
     * 执行在线程池中
     * @param params
     * @return
     */
    @Override
    protected String doInBackground(String... params) {
        return null;
    }

    /**
     * 当异步任务被取消时执行此方法,此时将不会再调用onPostExecute方法
     */
    @Override
    protected void onCancelled() {
        super.onCancelled();
    }

    /**
     * 当异步任务执行进度改变时执行此方法
     * 执行在主线程中
     * @param values
     */
    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
    }

    /**
     * 当异步任务执行完成后执行此方法
     * 执行在主线程中
     * @param s
     */
    @Override
    protected void onPostExecute(String s) {
        super.onPostExecute(s);
    }
}

要注意的是,需要在doInBackground方法中调用publishProgress()发送任务执行进度,onProgressUpdate才能被回调。

执行AsyncTask是需要在主线程中调用:

new MyAsyncTask().execute();

在使用AsyncTask时有一些限制我们要注意:

  • AsyncTask类必须在主线程中加载。这是因为在AsyncTask中存在这个一个静态类型的Handler对象成员,在AsyncTask被加载时,该静态类型的Handler对象就会被初始化,所以这就要求了首次访问AsyncTask要发送在主线程中。这一点在Android 4.1及以上版本中已经被系统自动完成。
  • AsyncTask的对象必须在主线程中创建。
  • AsyncTask的execute必须在主线程中调用。
  • 不能直接调用onPreExecute()、doInBackground()、onProgressUpdate()、onPostExecute()方法。
  • 一个AsyncTask对象只能调用一次execute,即每个对象只能被执行一次,否则会出异常。

1、使用AsyncTask执行异步任务的小例子

接下类使用AsyncTask,借助循环模拟一个耗时任务的小例子,还是用上面的MyAsyncTask类,并在其相关方法上面添加一些辅助代码,详细代码如下:

public class MyAsyncTask extends AsyncTask<String, Integer, String> {

    private final static String TAG = MyAsyncTask.class.getSimpleName();

    private int taskSize = 10;

    /**
     * 在异步任务执行之前调用
     * 执行在主线程中
     */
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        Log.i(TAG, "onPreExecute: ");
    }

    /**
     * 执行异步任务
     * 执行在线程池中
     * @param params
     * @return
     */
    @Override
    protected String doInBackground(String... params) {
        Log.i(TAG, "doInBackground: ");
        int i;
        for (i = 0; i < taskSize; i++) {
            SystemClock.sleep(1000);
            int progress = (int)((i / (float)taskSize) * 100);
            publishProgress(progress);

            if (isCancelled()) {
                break;
            }
        }
        return "执行结果:" + (i / (float)taskSize) * 100 + "%";
    }

    /**
     * 当异步任务被取消时执行此方法,此时将不会再调用onPostExecute方法
     */
    @Override
    protected void onCancelled() {
        super.onCancelled();
        Log.i(TAG, "onCancelled: ");
    }

    @Override
    protected void onCancelled(String s) {
        super.onCancelled(s);
        Log.i(TAG, "onCancelled: result=" + s);
    }

    /**
     * 当异步任务执行进度改变时执行此方法
     * 执行在主线程中
     * @param values
     */
    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
        Log.i(TAG, "onProgressUpdate: 执行进度:" + values[0] + "%");
    }

    /**
     * 当异步任务执行完成后执行此方法
     * 执行在主线程中
     * @param s
     */
    @Override
    protected void onPostExecute(String s) {
        super.onPostExecute(s);
        Log.i(TAG, "onPostExecute: result=" + s);
    }
}

在Activity中调用new MyAsyncTask().execute();执行Log如下:

.../cn.codingblock.thread I/MyAsyncTask: onPreExecute:
.../cn.codingblock.thread I/MyAsyncTask: doInBackground:
.../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:0%
.../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:10%
.../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:20%
.../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:30%
.../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:40%
.../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:50%
.../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:60%
.../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:70%
.../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:80%
.../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:90%
.../cn.codingblock.thread I/MyAsyncTask: onPostExecute: result=执行结果:100.0%

2、多个AsyncTask对象在执行异步任务时,默认是串行执行的,也可以通过executeOnExecutor让其并发执行。

  • 在Android 1.6之前,AsyncTask处理任务时是采用串行方式,Android 1.6时,AsyncTask处理任务时是在线程池中并行处理任务。但在Android 3.0开始,AsyncTask又开始采用串行方式处理任务。

我们稍加改造一下上面的示例,在构造方法中传入一个taskId,然后在关键log中输出这个taskId,以便于区分:

private int taskId;

public MyAsyncTask(int taskId) {
    this.taskId = taskId;
}

/**
 * 在异步任务执行之前调用
 * 执行在主线程中
 */
@Override
protected void onPreExecute() {
    super.onPreExecute();
    Log.i(TAG, "taskId= " + taskId + ": onPreExecute: ");
}

// 其他方法类比onPreExecute方法中的log增加taskId,就不贴出了

在Activity中初始化两个AsyncTask对象,并调用excute执行任务:

public class AsyncTaskActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_async_task);
        MyAsyncTask task1 = new MyAsyncTask(1);
        MyAsyncTask task2 = new MyAsyncTask(2);
        task1.execute();
        task2.execute();
    }
}

log如下:

.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onPreExecute:
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onPreExecute:
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: doInBackground:
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:0%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:10%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:20%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:30%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:40%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:50%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:60%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:70%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:80%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:90%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onPostExecute: result=taskId= 1: 执行结果:100.0%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: doInBackground:
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:0%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:10%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:20%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:30%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:40%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:50%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:60%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:70%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:80%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:90%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onPostExecute: result=taskId= 2: 执行结果:100.0%

可以看到两个任务是串行执行的。

  • 使用executeOnExecutor方法

AsyncTask

executorOnExecutor方法有两个参数,第一个是Executor,第二个是任务参数。

第一个参数有两种类型:

  • AsyncTask.SERIAL_EXECUTOR : 表示串行执行
  • AsyncTask.THREAD_POOL_EXECUTOR :表示并发执行

在执行task2时调用executeOnExecutor,观察执行结果:

public class AsyncTaskActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_async_task);
        MyAsyncTask task1 = new MyAsyncTask(1);
        MyAsyncTask task2 = new MyAsyncTask(2);
        task1.execute();
        task2.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }
}

log如下:

.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onPreExecute:
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onPreExecute:
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: doInBackground:
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: doInBackground:
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:0%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:0%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:10%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:10%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:20%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:20%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:30%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:30%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:40%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:40%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:50%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:50%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:60%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:60%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:70%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:70%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:80%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:80%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:90%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onPostExecute: result=taskId= 2: 执行结果:100.0%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:90%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onPostExecute: result=taskId= 1: 执行结果:100.0%

从log可以看到,两个任务在并发执行。

二、AsyncTask的原理

  • 1、首先在AsyncTask被初始化时构建一个WorkerRunnable(mWorker)和一个FutureTask(mFuture),后面在执行的过程中会将封装好的mFuture放入一个线程池中执行。
  • 2、在外界调用AsyncTask.execute方法之后,开始启动AsyncTask任务,根据代码查看调用过程如下:
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
    return executeOnExecutor(sDefaultExecutor, params);
}
  • 3、在execute方法中又调用了executeOnExecutor方法:
@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任务有三种状态:PENDING(未开始)、RUNNING(运行中)、FINISHED(已完成)。
从上面源码我们可以看到,一个AsyncTask实例任务只能运行一次,只有是在PENDING状态下,任务才能正常运行,否则就会抛出异常。

接着在执行任务前先调用了onPreExecute方法,并将参数赋值给mWorker的参数数组,然后使用exec执行在AsyncTask初始化阶段封装好的mFuture。

  • 4、从第二步可以知道exec就是sDefaultExecutor,它是一个Executor对象,相关的源码如下:
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

/**
 * An {@link Executor} that executes tasks one at a time in serial
 * order.  This serialization is global to a particular process.
 */
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);
        }
    }
}

从源码可以进一步看出,sDefaultExecutor是SerialExecutor对象,是一个串行的线程池,同一个进程中的所有的AsyncTask任务都在这个线程池中排队执行。

SerialExecutor的execute方法首先会将FutureTask任务加入到mTasks队列中,此时如果没有正在活动的任务就会调用scheduleNext执行下一个AsyncTask任务。

  • 5、接下来我们再回过头来看AsyncTask的构造器中在创建mWorker和mFuture时都做了些什么:
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);
            }
        }
    };
}
  • 6、先来分析一下上面源码中的WorkerRunnable的call方法:

WorkerRunnable的call方法中的代码很好理解,首先调用了mTaskInvoked.set(true),将任务的设为已调用状态。接着调用了doInBackground方法并获取了返回值,然后将返回值传递给postResult()方法,再看postResult方法的源码如下:

private Result postResult(Result result) {
    @SuppressWarnings("unchecked")
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
            new AsyncTaskResult<Result>(this, result));// 在这里将doInBackground的返回结果result封装到AsyncTaskReuslt对象里面通过handler发送给主线程
    message.sendToTarget();
    return result;
}

在此方法中通过handler发送了一条MESSAGE_POST_RESULT的消息。此handler的相关代码如下(为方便查看,适当调整了代码顺序):

private final Handler mHandler;

private Handler getHandler() {
    return mHandler;
}

/**
 * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
 */
public AsyncTask() {
    this((Looper) null);  // 在这里传入了null
}

/**
 * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
 *
 * @hide
 */
public AsyncTask(@Nullable Handler handler) {
    this(handler != null ? handler.getLooper() : null); // 根据上一步调用可知,handler为null
}

/**
 * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
 *
 * @hide
 */
public AsyncTask(@Nullable Looper callbackLooper) {
    mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
        ? getMainHandler()                              // 根据上一步调用可知,callbackLooper为null,在此会调用getMainHandler()
        : new Handler(callbackLooper);
        ...
}

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

private static InternalHandler sHandler;

在上面的源码中可知,最终getHandler()方法最终是为sHandler,而sHandler是一个静态的Handler对象,sHandler的作用是将执行环境切换到主线程中,所以这就要求sHandler要在主线程中被初始化,而由于静态成员会在类加载时被初始化,这就又要求了AsyncTask类必须在主线程中加载,否则该进程中的AsyncTask任务都无法正常工作。InternalHandler相关的源码如下:

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]); // 调用AsyncTask的finish方法。
                break;
            ...
        }
    }
}

private void finish(Result result) {
    if (isCancelled()) {
        onCancelled(result);     // 如果任务被取消了就去调用onCancelled方法。
    } else {
        onPostExecute(result);   // 任务完成后就将执行结果传递给onPostExecute方法
    }
    mStatus = Status.FINISHED;   // 最后将状态置为FINISHED
}
  • 7、接着再来看一下第五步中的FutureTask的源码
mFuture = new FutureTask<Result>(mWorker) {
    @Override
    protected void done() {     // 1、在执行完mWorker的call方法之后会执行done方法。2、或者在FutureTask任务被取消后也会执行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); // 在Future任务被取消时,在此段代码中就会抛出CancellationException异常,即会执行此方法。
        }
    }
};

我们知道Future被执行后,会调用传入的mWorker的call方法,在执行完mWorker的call方法之后或者FutureTask被取消时会调用done方法,我们看到源码中在done方法中调用postResultIfNotInvoked():

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

在这个方法中可以看到,只有当wasTaskInvoked为false是才会发送结果,也就是说,这一步是在WorkerRunnable任务未被执行并取消的情况下才发送结果给主线程,在前几步中我们就已经知道了postResult()方法中的调用过程,最终会调用到finish方法。

private void finish(Result result) {
    if (isCancelled()) {
        onCancelled(result);     // 如果任务被取消了就去调用onCancelled方法。
    } else {
        onPostExecute(result);   // 任务完成后就将执行结果传递给onPostExecute方法
    }
    mStatus = Status.FINISHED;   // 最后将状态置为FINISHED
}

在任务被取消的情况下回调了onCancelled方法,至此AsyncTask异步任务执行流程基本分析完了。

三、小结

最后简单总结一下AsyncTask的原理:

  • 在AsyncTask类中有两个线程池(SerialExecutor、THREAD_POOL_EXECUTOR)和一个Handler(InternalHandler),其中SerialExecutor线程池用于对任务排队,THREAD_POOL_EXECUTOR用于真正的执行任务,InternalHandler的作用是将执行环境切换到主线程中,而AsyncTask类中的InternalHandler变量是一个静态类型的变量,这也就决定了AsyncTask类必须在主线程中加载。
  • 在调用AsyncTask的executor方法开始执行异步任务时,会首先调用onPreExecute方法通知外界任务已经开始,接着使用线程池执行前面FutureTask任务。
  • 前面所说的这个FutureTask任务是在AsyncTask初始化时被封装好的,在该任务中调用了doInBackground方法用于异步执行我们添加的耗时任务,doInBackground方法执行完毕会通过InternalHandler将返回结果发送到onPostExecute中,该方法是运行在主线程中。

 

  • 《Android开发艺术探索》

源码地址:本系列文章所对应的全部源码已同步至github,感兴趣的同学可以下载查看,结合代码看文章会更好。源码传送门

本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8515304.html

原文地址:https://www.cnblogs.com/moriah/p/8531218.html

时间: 2024-10-29 19:10:23

Android查缺补漏(线程篇)-- AsyncTask的使用及原理详细分析的相关文章

Android查缺补漏(线程篇)-- IntentService的源码浅析

本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8975114.html 在Android中有两个比较容易弄混的概念,Service和Thread,我们都知道这两个东西都可以执行后台任务,但要注意的是Service是跑在主线程中的,如果不做特殊处理是会阻塞主线程的,而IntentService正好弥补了这一点,在<Android查缺补漏--Service和IntentService>这篇博文中已经简单介绍过了IntentSe

Android查缺补漏(View篇)--自定义 View 的基本流程

View是Android很重要的一部分,常用的View有Button.TextView.EditView.ListView.GridView.各种layout等等,开发者通过对这些View的各种组合以形成丰富多彩的交互界面,一个应用中界面交互的体验往往在应用的受欢迎程度上起了很关键得作用,所以开发者们大多会想方设法的做出一个更加精美的界面,例如:通过自定义View.深入学习View的原理以便更好的对其优化使其在操作起来更加流畅等等,也正因为如此,在面试中View也常常作为面试官重点考察的对象之一

Android查缺补漏(View篇)--事件分发机制源码分析

在上一篇博文中分析了事件分发的流程及规则,本篇会从源码的角度更进一步理解事件分发机制的原理,如果对事件分发规则还不太清楚的童鞋,建议先看一下上一篇博文 <Android查缺补漏(View篇)--事件分发机制> ,先来看一下本篇的分析思路,一会儿会按照事件传递的顺序,针对以下几点进行源码分析: Activity对点击事件的分发过程 PhoneWindow是如何处理点击事件的 顶级View对点击事件的分发过程 View对点击事件的处理过程 Activity对点击事件的分发过程 通过上一篇博文中我们

Android查缺补漏(View篇)--自定义View利器Canvas和Paint详解

上篇文章介绍了自定义View的创建流程,从宏观上给出了一个自定义View的创建步骤,本篇是上一篇文章的延续,介绍了自定义View中两个必不可少的工具Canvas和Paint,从细节上更进一步的讲解自定义View的详细绘制方法.如果把自定义View比作盖一座房子,那么上篇文章就相当于教会了我们怎么一步步的搭建房子的骨架,而本篇文章将要教会我们的是为房子的骨架添砖加瓦直至成型,甚至是怎么装修. Canvas 为了后文更为方便的讲解Canvas的常用方法的使用,我们先来做一些准备工作,创建一个自定义V

Android查缺补漏(View篇)--在 Activity 的 onCreate() 方法中为什么获取 View 的宽和高为0?

在 Activity 的 onCreate() 方法中为什么获取 View 的宽和高为0 ? @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my_view); myview = ViewUtils.find(this, R.id.myview); getViewSize("onCr

Android查缺补漏--Service和IntentService

Service的运行不依赖界面,即使程序被切换到后台,Service仍然能够保持正常运行.当某个应用程序进程被杀掉时,所有依赖于该进程的Service也会停止运行. Service 分为启动状态和绑定状态.当处于仅启动状态时,通过 stopService或 stopSelf 即可停止 Service.当处于绑定状态时需要通过 unBindService 和 stopService 结合使用才能完全停止 Service. 一.Service的生命周期(onCreate()-onStartComma

Android查缺补漏--ContentProvider的使用

ContentProvider (内容提供者)是一种共享型组件,可以为系统内应用于与应用之间提供访问接口. ContentProvide要想正常工作需要三个关键点: ContentProvider:对外提供数据的访问接口. Uri:ContentProvider的唯一标识,外界可根据其访问对应的ContentProvider. ContentResolver 比如,当应用A想把自己数据暴露出来让别的应用也可以操作的话,就可以在应用A内部创建一个ContentProvider实现相关方法并添加UR

Android查缺补漏(View篇)--自定义 View 中 wrap_content 无效的解决方案

自定义 View 中 wrap_content 无效的解决方案 做过自定义 View 的童鞋都会发现,直接继承 View 的自定义控件需要重写 onMeasure() 方法,并设置 wrap_content 时的自身大小,否在在布局文件中对自定义控件在设置大小时,wrap_content 将等同于 match_parent. 其实在 Android 中自带的控件中,也都对 onMeasure() 方法进行了重写,对于 wrap_content 等情况做了特殊处理,在 wrap_content 时

Android查缺补漏(View篇)--布局文件中的“@+id”和“@id”有什么区别?

Android布局文件中的"@+id"和"@id"有什么区别? +id表示为控件指定一个id(新增一个id),如: <cn.codingblock.view.customer_view.MyView android:id="@+id/myview" ... /> id表示引用一个现有的id,如: <cn.codingblock.view.customer_view.MyView android:id="@+id/myv