Android Asynctask与Handler的比较,优缺点区别,Asynctask源码

1  AsyncTask实现的原理,和适用的优缺点

AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程.

使用的优点:

l  简单,快捷

l  过程可控

使用的缺点:

l  在使用多个异步操作和并需要进行Ui变更时,就变得复杂起来.

2 Handler异步实现的原理和适用的优缺点

在Handler 异步实现时,涉及到 Handler, Looper, Message,Thread四个对象,实现异步的流程是主线程启动Thread(子线程)àthread(子线程)运行并生成Message- àLooper获取Message并传递给HandleràHandler逐个获取Looper中的Message,并进行UI变更。

使用的优点:

l  结构清晰,功能定义明确

l  对于多个后台任务时,简单,清晰

AsyncTask这个类感觉使用比较简单,就是实现其中几个方法,onPreExecute()方法是在任务刚开始运行时执行的一些初始化操作,比如初 始化一个进度条等等,然后就执行doInBackground()方法这里面主要放业务操作,比如查询数据库等,在这个方法执行的时候会调用 onProgressUpdate(),可以在这个方法中更新UI界面,最后是调用onPostExecute()方法,当得到业务结果后就可以在这个方
法中返回给UI线程,也可以关闭一些执行这个业务时开的一些资源。大家可以看得出AsyncTask这个类是一个泛型类,这个类的三个参数以此对应 doInBackground(String... params),onProgressUpdate(String... values),onPostExecute(String result)的参数,很形象的···如果不需要传参和返回值,可以用Void代替。而doInBackground(String... params)方法的返回值也就是onPostExecute(String
result)方法的参数值,因为doInBackground方法执行后返回的值是在onPostExecute(String result)中处理的。

用handler方式处理需要知道与handler相关的几个组件,Looper和Queue,其实Looper的作用就是把handler发送的消息放 到Queue中,并把消息广播给所有与这个Queue相关的handler,而Queue一般是主线程开启的时候就给这个线程分配了一个,所以你要与UI 主线程通信必须用于这个Queue相关联的handler对象才行,一般handler对象在那个线程中创建的就与那个线程的queue关联,所以在UI
线程中创建的handler对象就与UI线程通讯,这样我们就可以在子线程中发送消息给主线程,实现更新UI的功能。那主线程又是怎么处理子线程发送的消 息的呢?其实在生成handler对象的时候我们就要实现handler对象的handleMessage()方法这个方法就是主线程接受并处理子线程发 送过来的消息的方法,从而实现 更新UI线程的功能。

很多网友可能发现Android平台很多应用使用的都是AsyncTask,而并非Thread和Handler去更新UI,这里给大家说下他们到底有什 么区别,我们平时应该使用哪种解决方案。从Android 1.5开始系统将AsyncTask引入到android.os包中,过去在很早1.1和1.0 SDK时其实官方将其命名为UserTask,其内部是JDK 1.5开始新增的concurrent库,做过J2EE的网友可能明白并发库效率和强大性,比Java原始的Thread更灵活和强大,但对于轻量级的使
用更为占用系统资源。Thread是Java早期为实现多线程而设计的,比较简单不支持concurrent中很多特性在同步和线程池类中需要自己去实现 很多的东西,对于分布式应用来说更需要自己写调度代码,而为了Android UI的刷新Google引入了Handler和Looper机制,它们均基于消息实现,有时可能消息队列阻塞或其他原因无法准确的使用。

推荐大家使用AsyncTask代替Thread+Handler的方式,不仅调用上更为简单,经过实测更可靠一些,Google在Browser中大量 使用了异步任务作为处理耗时的I/O操作,比如下载文件、读写数据库等等,它们在本质上都离不开消息,但是AsyncTask相比Thread加 Handler更为可靠,更易于维护,但AsyncTask缺点也是有的比如一旦线程开启即dobackground方法执行后无法给线程发送消息,仅能
通过预先设置好的标记来控制逻辑,当然可以通过线程的挂起等待标志位的改变来通讯,对于某些应用Thread和Handler以及Looper可能更灵 活。

本文主要讲解下AsyncTask的使用以及Handler的应用

首先,我们得明确下一个概念,什么是UI线程。顾名思义,ui线程就是管理着用户界面的那个线程!

android的ui线程操作并不是安全的,并且和用户直接进行界面交互的操作都必须在ui线程中进行才可以。这种模式叫做单线程模式。

我们在单线程模式下编程一定要注意:不要阻塞ui线程、确保只在ui线程中访问ui组件

当我们要执行一个复杂耗时的算法并且最终要将计算结果反映到ui上时,我们会发现,我们根本没办法同时保证上面的两点要求;我们肯定会想到开启一个新的线程,让这个复杂耗时的任务到后台去执行,但是执行完毕了呢?我们发现,我们无法再与ui进行交互了。

为了解决这种情况,android为我们提供了很多办法。

1)、handler和message机制:通过显示的抛出、捕获消息与ui进行交互;

2)、Activity.runOnUiThread(Runnable):如果当前线程为ui线程,则立即执行;否则,将参数中的线程操作放入到ui线程的事件队列中,等待执行。

3)、View.post(Runnable):将操作放入到message队列中,如果放入成功,该操作将会在ui线程中执行,并返回true,否则返回false

4)、View.postDelayed(Runnable, long)跟第三条基本一样,只不过添加了一个延迟时间。

5)、android1.5以后为我们提供了一个工具类来搞定这个问题AsyncTask.

AsyncTask是抽象类,定义了三种泛型类型 Params,Progress,Result。

Params 启动任务执行的输入参数,比如HTTP请求的URL

Progress 后台任务执行的百分比。

Result 后台执行任务最终返回的结果,比如String

用程序调用,开发者需要做的就是实现这些方法。

1) 子类化AsyncTask

2) 实现AsyncTask中定义的下面一个或几个方法

onPreExecute(),该方法将在执行实际的后台操作前被UI thread调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条。

doInBackground(Params…),将在onPreExecute 方法执行后马上执行,该方法运行在后台线程中。这里将主要负责执行那些很耗时的后台计算工作。可以调用 publishProgress方法来更新实时的任务进度。该方法是抽象方法,子类必须实现。

onProgressUpdate(Progress…),在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。

onPostExecute(Result),在doInBackground 执行完成后,onPostExecute 方法将被UI thread调用,后台的计算结果将通过该方法传递到UI thread.

为了正确的使用AsyncTask类,以下是几条必须遵守的准则:

1) Task的实例必须在UI thread中创建

2) execute方法必须在UI thread中调用

3) 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params…), onProgressUpdate(Progress…)这几个方法

4) 该task只能被执行一次,否则多次调用时将会出现异常

下面介绍最本质的多线程:hanlder和message机制:

为何需要多线程:

在日常应用中,我们通常需要处理一些“后台,用户不可见”的操作,例如说,我们需要下载一个音乐,要是你的应用必须等用户下载完成之后才可以进行别的操 作,那肯定让用户非常的不爽。这时候,我们通常的做法是,让这些操作去后台执行,然后等后台执行完毕之后,再给用户弹出相应的提示信息。这时候,我们就需 要使用多线程机制,然后通过创建一个新的线程来执行这些操作。

明白了,实现需求,我们就准备着手实现了。但是,经过进一步的了解,我们悲剧的发现,android中的线程机制是,只能在UI线程中和用户进行交互。当 我们创建了一个新线程,执行了一些后台操作,执行完成之后,我们想要给用户弹出对话框以确认,但是却悲剧的发现,我们根本无法返回UI主线程了。

(说明:何为UI线程:UI线程就是你当前看到的这些交互界面所属的线程)。

这时候,我们如果想要实现这些功能,我们就需要一个android为我们提供的handler和message机制。

先讲解下编程机制:

我们通常在UI线程中创建一个handler,handler相当于一个处理器,它主要负责处理和绑定到该handler的线程中的message。每一 个handler都必须关联一个looper,并且两者是一一对应的,注意,这点很重要哦!此外,looper负责从其内部的messageQueue中 拿出一个个的message给handler进行处理。因为我们这里handler是在UI线程中实现的,所以经过这么一个handler、
message机制,我们就可以回到UI线程中了。

何为handler:处理后台进程返回数据的工作人员。

何为message:后台进程返回的数据,里面可以存储bundle等数据格式

何为messageQueue:是线程对应looper的一部分,负责存储从后台进程中抛回的和当前handler绑定的message,是一个队列。

何为looper:looper相当于一个messageQueue的管理人员,它会不停的循环的遍历队列,然后将符合条件的message一个个的拿出来交给handler进行处理。

注意,handler是在UI线程中声明的,如果我们直接用类似代码执行一个线程的话,实际上并没有创建一个新的线程,因为handler已经跟默认的UI线程中的looper绑定了。

如果有兴趣的话,可以去看下Handler的默认空构造函数便知道原因了,里面直接绑定了当前UI线程的looper。

下面给出一个比较简单,并且实用的实例。

这2种方式都可以实现,但是他们的区别在哪里?优缺点各是什么?

(1)、AsyncTask是封装好的线程池,比起Thread+Handler的方式,AsyncTask在操作UI线程上更方便,因为onPreExecute()、onPostExecute()及更新UI方法onProgressUpdate()均运行在主线程中,这样就不用Handler发消息处理了;

(2)、我不太同意封装好就会影响性能的说法,在我实际的运用中,真正的缺点来自于AsyncTask的全局线程池只有5个工作线程,也就是说,一个APP如果运用AsyncTask技术来执行线程,那么同一时间最多只能有5个线程同时运行,其他线程将被阻塞(注:不运用AsyncTask执行的线程,也就是自己new出来的线程不受此限制),所以AsyncTask不要用于多线程取网络数据,因为很可能这样会产生阻塞,从而降低效率。

三. 能否同时并发100+asynctask呢?

AsyncTask用的是线程池机制,容量是128,最多同时运行5个core线程,剩下的排队。

2、AsyncTask是否异步

public class MainService extends Service{

	private static Task task;//当前执行任务
	private static Map<String, Activity> allActivitys = new HashMap<String, Activity>();//缓存activity集合
	private static ExecutorService exec = Executors.newSingleThreadExecutor();

	@Override
	public void onStart(Intent intent, int startId) {
		super.onStart(intent, startId);
		MainAsyncTask asyncTask = new MainAsyncTask();
		//asyncTask.execute(task);
		//asyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, task);
		//asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, task);
		//asyncTask.executeOnExecutor(Executors.newFixedThreadPool(2), task);
		asyncTask.executeOnExecutor(exec, task);
	}

	private final class MainAsyncTask extends AsyncTask<Object, Integer, Object>{
		private Task task;
		@Override
		protected Object doInBackground(Object... params) {
			Object result = null;
			task = (Task)params[0];
			switch (task.getTaskID()) {
			case Task.TASK_USER_LOGIN:
				try {
					Thread.sleep(3000);
					System.out.println("任务"+task.getTaskID()+" Thread id: "+Thread.currentThread().getId());
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				break;
			case 2:
				System.out.println("任务"+task.getTaskID()+" Thread id: "+Thread.currentThread().getId());
				break;
			}
			return result;
		}

		@Override
		protected void onPostExecute(Object result) {
			super.onPostExecute(result);
			ActivityInterFace aif;
			switch (task.getTaskID()) {
			case Task.TASK_USER_LOGIN:
				aif = (ActivityInterFace)allActivitys.get("LoginActivity");
				aif.refresh(1, result);
				break;
			case 2:
				aif = (ActivityInterFace)allActivitys.get("LoginActivity");
				aif.refresh(2, result);
				break;
			default:
				break;
			}
		}

	}

	/**
	 * 添加新任务
	 * @param task
	 */
	public static void addTask(Context context, Task task) {
		MainService.task = task;
		context.startService(new Intent("mainService"));
	}

	/**
	 * 缓存activity
	 * @param activity
	 */
	public static void addActivity(Activity activity) {
		String path = activity.getClass().getName();
		String name = path.substring(path.lastIndexOf(".")+1);
		allActivitys.put(name, activity);
	}

	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}

}

当我执行两次调用asyncTask.execute(task);时发现只有当第一次的任务完成后才执行下一下任务!!怎么回事?

AyncTask不是号称异步线程池吗?既然是线程池那么多任务执行时应该可以并发执行啊,至少两个任务可以并发执

行,以前看过一个视频,人家的就可以啊!纠结了一下午,通过查阅资料和自己的动手实验终于把问题搞明白了。

原来在SDK3.0以前的版本执行asyncTask.execute(task);时的确是多线程并发执行的,线程池大小为5,最大可大

128个,google在3.0以后的版本中做了修改,将asyncTask.execute(task);修改为了顺序执行,即只有当一个的实例

的任务完成后在执行下一个实例的任务。

那么怎么才能并发执行呢,很简单,3.0后新增了一个方法executeOnExecutor(Executor

exec, Object...
params),

该方法接受2个参数,第一个是Executor,第二个是任务参数。第一个是线程池实例,google为我们预定义了两种:

第一种是AsyncTask.SERIAL_EXECUTOR,第二种是AsyncTask.THREAD_POOL_EXECUTOR,顾名思义,第一

种其实就像3.0以后的execute方法,是顺序执行的。第二种就是3.0以前的execute方法,是可以并发执行的。我们直

接用asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, task);就可以多任务并发执行了。

既然executeOnExecutor第一个参数是Executor,那么我们可以自定义Executor吗?当然可以,Executor主要由四

种类型newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor

(具体使用解析可以看我上一篇文章点击打开链接),可是当我这样使用

asyncTask.executeOnExecutor(Executors.newFixedThreadPool(1), task);或者

asyncTask.executeOnExecutor(Executors.newSingleThreadExecutor, task);并没有像我想象的与

asyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, task);那样是单线程顺序执行,而是像

asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, task);是多线程并发执行的,我不是

已经规定newFixedThreadPool的线程池数量是1或者是newSingleThreadExecutor单线程了么!怎么回事呢?原来程

序在每次调用asyncTask.executeOnExecutor(Executors.newFixedThreadPool(2), task)时会获取一个新的Executor对

象,这个对象内的线程只执行对应的task,所以无论哪种情况每个task都有一个新的线程来执行,即并发执行。

知道原因就好办了,我们定义个一全局静态变量

private static ExecutorService exec = Executors.newSingleThreadExecutor();程序在每次调用

asyncTask.executeOnExecutor(exec, task);时是使用的同一个Executor,执行效果如下:

当Executor类型为:private static ExecutorService exec = Executors.newFixedThreadPool(2);只有两个线程在执行

任务

当Executor类型为:private static ExecutorService exec = Executors.newSingleThreadExecutor();只有一个线程在执行任务

3、AsyncTask源码分析

public abstract class AsyncTask {
    private static final String LOG_TAG = AsyncTask;

	//获取当前的cpu核心数
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
	//线程池核心容量
    private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
	//线程池最大容量
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
	//过剩的空闲线程的存活时间
    private static final int KEEP_ALIVE = 1;
	//ThreadFactory 线程工厂,通过工厂方法newThread来获取新线程
    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
		//原子整数,可以在超高并发下正常工作
        private final AtomicInteger mCount = new AtomicInteger(1);

        public Thread newThread(Runnable r) {
            return new Thread(r, AsyncTask # + mCount.getAndIncrement());
        }
    };
	//静态阻塞式队列,用来存放待执行的任务,初始容量:128个
    private static final BlockingQueue sPoolWorkQueue =
            new LinkedBlockingQueue(128);

    /**
     * 静态并发线程池,可以用来并行执行任务,尽管从3.0开始,AsyncTask默认是串行执行任务
	 * 但是我们仍然能构造出并行的AsyncTask
     */
    public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

    /**
     * 静态串行任务执行器,其内部实现了串行控制,
	 * 循环的取出一个个任务交给上述的并发线程池去执行
     */
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
	//消息类型:发送结果
    private static final int MESSAGE_POST_RESULT = 0x1;
	//消息类型:更新进度
    private static final int MESSAGE_POST_PROGRESS = 0x2;
	/**静态Handler,用来发送上述两种通知,采用UI线程的Looper来处理消息
	 * 这就是为什么AsyncTask必须在UI线程调用,因为子线程
	 * 默认没有Looper无法创建下面的Handler,程序会直接Crash
	 */
    private static final InternalHandler sHandler = new InternalHandler();
	//默认任务执行器,被赋值为串行任务执行器,就是它,AsyncTask变成串行的了
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
	//如下两个变量我们先不要深究,不影响我们对整体逻辑的理解
    private final WorkerRunnable mWorker;
    private final FutureTask mFuture;
	//任务的状态 默认为挂起,即等待执行,其类型标识为易变的(volatile)
    private volatile Status mStatus = Status.PENDING;
    //原子布尔型,支持高并发访问,标识任务是否被取消
    private final AtomicBoolean mCancelled = new AtomicBoolean();
	//原子布尔型,支持高并发访问,标识任务是否被执行过
    private final AtomicBoolean mTaskInvoked = new AtomicBoolean();

	/*串行执行器的实现,我们要好好看看,它是怎么把并行转为串行的
	 *目前我们需要知道,asyncTask.execute(Params ...)实际上会调用
	 *SerialExecutor的execute方法,这一点后面再说明。也就是说:当你的asyncTask执行的时候,
	 *首先你的task会被加入到任务队列,然后排队,一个个执行
	 */
    private static class SerialExecutor implements Executor {
		//线性双向队列,用来存储所有的AsyncTask任务
        final ArrayDeque mTasks = new ArrayDeque();
		//当前正在执行的AsyncTask任务
        Runnable mActive;

        public synchronized void execute(final Runnable r) {
			//将新的AsyncTask任务加入到双向队列中
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
						//执行AsyncTask任务
                        r.run();
                    } finally {
						//当前AsyncTask任务执行完毕后,进行下一轮执行,如果还有未执行任务的话
						//这一点很明显体现了AsyncTask是串行执行任务的,总是一个任务执行完毕才会执行下一个任务
                        scheduleNext();
                    }
                }
            });
			//如果当前没有任务在执行,直接进入执行逻辑
            if (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
			//从任务队列中取出队列头部的任务,如果有就交给并发线程池去执行
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

    /**
     * 任务的三种状态
     */
    public enum Status {
        /**
         * 任务等待执行
         */
        PENDING,
        /**
         * 任务正在执行
         */
        RUNNING,
        /**
         * 任务已经执行结束
         */
        FINISHED,
    }

    /** 隐藏API:在UI线程中调用,用来初始化Handler */
    public static void init() {
        sHandler.getLooper();
    }

    /** 隐藏API:为AsyncTask设置默认执行器 */
    public static void setDefaultExecutor(Executor exec) {
        sDefaultExecutor = exec;
    }

    /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     */
    public AsyncTask() {
        mWorker = new WorkerRunnable() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                return postResult(doInBackground(mParams));
            }
        };

        mFuture = new FutureTask(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 occured while executing doInBackground(),
                            e.getCause());
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                }
            }
        };
    }

    private void postResultIfNotInvoked(Result result) {
        final boolean wasTaskInvoked = mTaskInvoked.get();
        if (!wasTaskInvoked) {
            postResult(result);
        }
    }
	//doInBackground执行完毕,发送消息
    private Result postResult(Result result) {
        @SuppressWarnings(unchecked)
        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult(this, result));
        message.sendToTarget();
        return result;
    }

    /**
     * 返回任务的状态
     */
    public final Status getStatus() {
        return mStatus;
    }

    /**
	 * 这个方法是我们必须要重写的,用来做后台计算
	 * 所在线程:后台线程
     */
    protected abstract Result doInBackground(Params... params);

    /**
	 * 在doInBackground之前调用,用来做初始化工作
	 * 所在线程:UI线程
     */
    protected void onPreExecute() {
    }

    /**
	 * 在doInBackground之后调用,用来接受后台计算结果更新UI
	 * 所在线程:UI线程
     */
    protected void onPostExecute(Result result) {
    }

    /**
     * Runs on the UI thread after {@link #publishProgress} is invoked.
     /**
	 * 在publishProgress之后调用,用来更新计算进度
	 * 所在线程:UI线程
     */
    protected void onProgressUpdate(Progress... values) {
    }

     /**
	 * cancel被调用并且doInBackground执行结束,会调用onCancelled,表示任务被取消
	 * 这个时候onPostExecute不会再被调用,二者是互斥的,分别表示任务取消和任务执行完成
	 * 所在线程:UI线程
     */
    @SuppressWarnings({UnusedParameters})
    protected void onCancelled(Result result) {
        onCancelled();
    }    

    protected void onCancelled() {
    }

    public final boolean isCancelled() {
        return mCancelled.get();
    }

    public final boolean cancel(boolean mayInterruptIfRunning) {
        mCancelled.set(true);
        return mFuture.cancel(mayInterruptIfRunning);
    }

    public final Result get() throws InterruptedException, ExecutionException {
        return mFuture.get();
    }

    public final Result get(long timeout, TimeUnit unit) throws InterruptedException,
            ExecutionException, TimeoutException {
        return mFuture.get(timeout, unit);
    }

    /**
     * 这个方法如何执行和系统版本有关,在AsyncTask的使用规则里已经说明,如果你真的想使用并行AsyncTask,
	 * 也是可以的,只要稍作修改
	 * 必须在UI线程调用此方法
     */
    public final AsyncTask execute(Params... params) {
		//串行执行
        return executeOnExecutor(sDefaultExecutor, params);
		//如果我们想并行执行,这样改就行了,当然这个方法我们没法改
		//return executeOnExecutor(THREAD_POOL_EXECUTOR, params);
    }

    /**
     * 通过这个方法我们可以自定义AsyncTask的执行方式,串行or并行,甚至可以采用自己的Executor
	 * 为了实现并行,我们可以在外部这么用AsyncTask:
	 * asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Params... params);
	 * 必须在UI线程调用此方法
     */
    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会最先执行
        onPreExecute();

        mWorker.mParams = params;
		//然后后台计算#doInBackground才真正开始
        exec.execute(mFuture);
		//接着会有#onProgressUpdate被调用,最后是#onPostExecute

        return this;
    }

    /**
     * 这是AsyncTask提供的一个静态方法,方便我们直接执行一个runnable
     */
    public static void execute(Runnable runnable) {
        sDefaultExecutor.execute(runnable);
    }

    /**
	 * 打印后台计算进度,onProgressUpdate会被调用
     */
    protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult(this, values)).sendToTarget();
        }
    }

	//任务结束的时候会进行判断,如果任务没有被取消,则onPostExecute会被调用
    private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }

	//AsyncTask内部Handler,用来发送后台计算进度更新消息和计算完成消息
    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 static abstract class WorkerRunnable implements Callable {
        Params[] mParams;
    }

    @SuppressWarnings({RawUseOfParameterizedType})
    private static class AsyncTaskResult {
        final AsyncTask mTask;
        final Data[] mData;

        AsyncTaskResult(AsyncTask task, Data... data) {
            mTask = task;
            mData = data;
        }
    }
}
时间: 2024-10-21 20:54:00

Android Asynctask与Handler的比较,优缺点区别,Asynctask源码的相关文章

Android ViewGroup触摸屏事件派发机制详解与源码分析

PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN.因为CSDN也支持MarkDown语法了,牛逼啊! [工匠若水 http://blog.csdn.net/yanbober] 该篇承接上一篇<Android View触摸屏事件派发机制详解与源码分析>,阅读本篇之前建议先阅读. 1 背景 还记得前一篇<Android View触摸屏事件派发机制详解与源码分析>中关于透过源码继续进阶实例验证模块中存在的点击Button却触发了LinearLayout的事

Android开发之自己定义TabHost文字及背景(源码分享)

使用TabHost 能够在一个屏幕间进行不同版面的切换,而系统自带的tabhost界面较为朴素,我们应该怎样进行自己定义改动优化呢 MainActivity的源码 package com.dream.ledong; import android.app.TabActivity; import android.content.Intent; import android.graphics.Color; import android.os.Bundle; import android.view.Gr

Android App 启动时显示正在加载图片(源码)

微信.QQ.天天动听等程序,在打开时显示了一张图片,然后跳转到相关界面.本文实现这个功能,其实很简单.... 新建两个Activity,LoadingActivity,MainActivity,将LoadingActivity设置为android.intent.action.MAIN.使用TimerTesk,或者Thread将LoadingActivity显示几秒后跳转到MainActivity界面. LoadingActivity: new Timer().schedule(new Timer

Android多线程研究(1)——线程基础及源码剖析

从今天起我们来看一下Android中的多线程的知识,Android入门容易,但是要完成一个完善的产品却不容易,让我们从线程开始一步步深入Android内部. 一.线程基础回顾 package com.maso.test; public class TraditionalThread { public static void main(String[] args) { /* * 线程的第一种创建方式 */ Thread thread1 = new Thread(){ @Override publi

Android Volley完全解析(四),带你从源码的角度理解Volley

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/17656437 经过前三篇文章的学习,Volley的用法我们已经掌握的差不多了,但是对于Volley的工作原理,恐怕有很多朋友还不是很清楚.因此,本篇文章中我们就来一起阅读一下Volley的源码,将它的工作流程整体地梳理一遍.同时,这也是Volley系列的最后一篇文章了. 其实,Volley的官方文档中本身就附有了一张Volley的工作流程图,如下图所示. 多数朋友突然看到一张这样

Android布局文件的加载过程分析:Activity.setContentView()源码分析

大家都知道在Activity的onCreate()中调用Activity.setContent()方法可以加载布局文件以设置该Activity的显示界面.本文将从setContentView()的源码谈起,分析布局文件加载所涉及到的调用链.本文所用的源码为android-19. Step 1  .Activity.setContentView(intresId) public void setContentView(int layoutResID) { getWindow().setConten

[Android] 异步消息处理机制(Handler 、 Looper 、MessageQueue)源码解析

1.Handler的由来 当程序第一次启动的时候,Android会同时启动一条主线程( Main Thread)来负责处理与UI相关的事件,我们叫做UI线程. Android的UI操作并不是线程安全的(出于性能优化考虑),意味着如果多个线程并发操作UI线程,可能导致线程安全问题. 为了解决Android应用多线程问题-Android平台只允许UI线程修改Activity里的UI组建,就会导致新启动的线程无法改变界面组建的属性值. 简单的说:当主线程队列处理一个消息超过5秒,android 就会抛

Android仿UC浏览器左右上下滚动功能(附源码)

本文要解决在侧滑菜单右边加个文本框,并能实现文本的上下滑动和菜单的左右滚动.这里推荐可以好好看看android的触摸事件的分发机制,这里我就不详细讲了,我只讲讲这个应用.要实现的功能就像UC浏览器(或其它手机浏览器)的左右滚动,切换网页,上下滚动,拖动内容. 目录:一.功能要求与实现       二.布局与代码       三.原理与说明 本文的效果:(源码下载) 一.功能要求与实现 1.功能要求: (1)手指一开始按着屏幕左右移动时,只能左右滚动菜单,如果这时手指一直按着,而且上下移动了,那么

Android中Loader及LoaderManager的使用(附源码下载)

managedQuery方法的缺陷 Loader是用来更好地加载数据的,在我们谈论Loader之前,我们先研究一下Activity的managedQuery方法,该方法也是用于在Activity中加载数据的.在Android 3.0之前的版本中,我们如果想在Activity中通过ContentResolver对ContentProvider进行查询,我们可以方便的调用Activity的managedQuery方法,该方法的源码如下: @Deprecated public final Cursor

Android中图片加载框架Glide解析2----从源码的角度理解Glide的执行流程

转载地址:http://blog.csdn.net/guolin_blog/article/details/53939176 在本系列的上一篇文章中,我们学习了Glide的基本用法,体验了这个图片加载框架的强大功能,以及它非常简便的API.还没有看过上一篇文章的朋友,建议先去阅读 Android图片加载框架最全解析(一),Glide的基本用法 . 在多数情况下,我们想要在界面上加载并展示一张图片只需要一行代码就能实现,如下所示: Glide.with(this).load(url).into(i