AsyncTask,IntentService工作原理分析&Android线程池
2016-05-09 09:13
609 查看
一,android中的主线程和子线程
android中的主线程可以认为是UI线程,在主线程不可以执行耗时的操作,否则就会给人一种卡顿的感觉。而主线程主要用于处理四大组件,以及处理它们和用户的交互。anroid的子线程的主要功能就是处理耗时操作。
要知道”在android3.0之后,要求网络访问必须在子线程执行,否则会抛出NetWorkOnMainThreadException异常。”
二,Android中的线程形态
Android中的线程状态,除了传统的Thread,还包含AsyncTask,HandlerThread,IntentService。
它们的底层其实都是Thread,它们的出现都是为了简化子线程更新UI的过程。
下面来逐一的介绍它们的使用和原理。
1,AsyncTask
在AsyncTask中,会在线程池中处理后台任务,并把处理的结果和处理的进度传递到主线程中去,方便更新UI。
使用它可以很方便的执行后台任务和更新UI。它实现的原理,是Handler和Thread,只是AsyncTask封装了它们。
AsyncTask是一个抽象类,并且它的子类需要传递泛型进来。
它的方法:
下面的AsyncTask被用来访问一张网络上的图片。图片的url是String,所以它的Params为String类型。所需要更新的进度类型为数字,为Integer类型。不需要处理后台任务的结果,所以Result为Void类型。
执行后台任务:
2,从源码上分析AsyncTask的工作原理
AsyncTask的execute方法:
3,IntentService
在IntentService的onCreate中:
例子:
4,android中的线程池
线程池出现的原因:
Android中的线程池来自于Java的Executor,它是一个接口,真正的实现是ThreadPoolExecutor类。
android中的几种线程池,底层都是由ThreadPoolExecutor来配置。
下面就来看看ThreadPoolExecutor。
Android中常见的线程池:
通过查看其构造方法,根据ThreadPoolExecutor的参数信息,就可以知道每个线程池的功能特性。
android中的主线程可以认为是UI线程,在主线程不可以执行耗时的操作,否则就会给人一种卡顿的感觉。而主线程主要用于处理四大组件,以及处理它们和用户的交互。anroid的子线程的主要功能就是处理耗时操作。
要知道”在android3.0之后,要求网络访问必须在子线程执行,否则会抛出NetWorkOnMainThreadException异常。”
二,Android中的线程形态
Android中的线程状态,除了传统的Thread,还包含AsyncTask,HandlerThread,IntentService。
它们的底层其实都是Thread,它们的出现都是为了简化子线程更新UI的过程。
下面来逐一的介绍它们的使用和原理。
1,AsyncTask
在AsyncTask中,会在线程池中处理后台任务,并把处理的结果和处理的进度传递到主线程中去,方便更新UI。
使用它可以很方便的执行后台任务和更新UI。它实现的原理,是Handler和Thread,只是AsyncTask封装了它们。
public abstract class AsyncTask<Params, Progress, Result>
AsyncTask是一个抽象类,并且它的子类需要传递泛型进来。
Params:表示参数类型 Progress:表示后台任务的进度类型 Result:表示后台任务的返回值类型
它的方法:
下面的AsyncTask被用来访问一张网络上的图片。图片的url是String,所以它的Params为String类型。所需要更新的进度类型为数字,为Integer类型。不需要处理后台任务的结果,所以Result为Void类型。
class AsuleAsyncTask extends AsyncTask<String,Integer,Void>{ //异步操作执行之前调用,在主线程运行 @Override protected void onPreExecute() { super.onPreExecute(); Log.i(Constants.LOG,"onPreExecute"); } //执行异步任务,在线程池中执行,params表示异步任务的输入参数 //在此方法中可以通过 publishProgress(进度值)来更新任务进度条,会去调用onProgressUpdate //后台任务的结果返回给onPostExecute @Override protected Void doInBackground(String... params) { Log.i(Constants.LOG, "doInBackground"); String url=params[0]; Log.i(Constants.LOG, "url" + url); //根据url去请求图片,执行异步任务 //........... return null; } //主线程运行,更新进度UI @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); } //异步操作执行之后调用,在主线程运行, //它的参数是doInBackground方法的返回值。处理后台任务的结果 @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); Log.i(Constants.LOG, "onPostExecute"); } }
执行后台任务:
new AsuleAsyncTask().execute("http://f10.topitme.com/o/201102/17/12979229866129.jpg");
2,从源码上分析AsyncTask的工作原理
AsyncTask的execute方法:
sDefaultExecutor实际上是一个串行的线程池。
AysncTask的onPreExecute方法会先执行,接下来线程池开始执行任务。 FutureTask交给SerialExecutor来执行。
线程池的执行过程: mFuture是FutureTask类型的变量。 如:private final FutureTask<Result> mFuture; 它在AstncTask的构造方法中初始化。 FutureTask实现了Runnable接口,可以当作是操作任务的类,我们都知道Runnable实现类可以理解为一个任务,线程负责执行Runnable任务。 而FutureTask不仅可以被线程当作一个任务来执行,而且它还可以调度任务。 比如FutureTask的cancel方法,可以中断执行任务的线程,记录任务结束状态。 相对于Runnable而言,FutureTask可以对任务进行管理。 mTasks是一个存储着Runnable的ArrayDeque,它表示着一个任务队列。 首先execute方法会把FutureTask对象插入到mTasks的任务队列中去。 如果没有正在活动的AsyncTask任务,就会调用scheduleNext方法。 而当一个任务执行完之后,AysncTask会继续执行其他任务,直到所有的任务都被执行完毕。 Async中有两个线程池,一个就是下面的SerialExecutor,还有就是THREAD_POOL_EXECUTOR线程池。 THREAD_POOL_EXECUTOR线程池: public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory); SerialExecutor用于任务的排列,而THREAD_POOL_EXECUTOR是真正的用于处理任务。(scheduleNext处理任务)
处理任务时,会去执行FutureTask的run方法。 AsyncTask的构造方法,对FutureTask进行了初始化,并且把WorkerRunnable实例作为FutureTask的构造参数。 在FutureTask的run中会call方法,这里callable代表的就是WorkerRunnable对象。 调用call方法,mTaskInvoked设为true,表示当前任务已经调用过了, 然后执行AsyncTask的doInBackground方法,将其返回值传递给postResult方法。 所以可以推断出doInBackground是运行在线程池中。
postResult会通过InternalHandler发送一个标记为MESSAGE_POST_RESULT的Message, InternalHandler在收到这个消息后,会调用AsyncTask的finish方法。 InternalHandler的作用是把执行环境切换到主线程,所以InternalHandler的创建必须要是在主线程中。 由于InternalHandler是静态的,AsyncTask类一加载就会进行初始化。 同样,AsyncTask的类也必须要在主线程加载。 而finish方法就很简单了,如果AsyncTask任务被取消了,就会调用onCancelled, 如果没有,代表后台任务已经执行完毕,就会把返回结果交由onPostExecute方法。 到这里,AsyncTask的整个工作过程就完毕了。
3,IntentService
IntentService继承自Service,并且它是抽象类,创建它的子类实现抽象方法才可以使用它。 IntentService负责执行后台的耗时的任务,也因为IntentService是服务的原因,这导致它的优先级比单纯的线程要高。 所以IntentService适用于执行高优先级的后台任务。
在IntentService的onCreate中:
@Override public void onCreate() { super.onCreate(); HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); thread.start(); mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); }
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); thread.start(); HandlerThread继承自Thread代表一个线程,start方法会去调用HandlerThread的run。 如下: public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; } Looper.prepare方法会创建消息队列MessageQueue和Looper对象。 Looper.loop();就开始在消息队列中轮询消息。 mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); 根据获取的Looper,构造一个Handler对象ServiceHandler。 要知道,prepare方法是由ActivityThread的main方法调用的, 也就是说应用一启动,MessageQueue和Looper对象实际上就已经被创建了。 这里又创建一次的原因,我自己是这样想的,ActivityThread的main创建的是代表着主线程的MessageQueue和Looper。 而我们这里是为一个子线程创建MessageQueue和Looper对象。 而MessageQueue和Looper对象是构建Handler的基础。 所以就认为ServiceHandler发送的消息和处理消息都是在HandlerThread这个线程中。
每次一启动IntentService,除了onCreate初始化之外, IntentService会在onStartCommand中处理后台任务的intent。 public int onStartCommand(Intent intent, int flags, int startId) { onStart(intent, startId); return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY; } public void onStart(Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); } private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { onHandleIntent((Intent)msg.obj); stopSelf(msg.arg1); } } onStartCommand方法中,mServiceHandler发送了一条消息, 这个消息会在ServiceHandler中去处理。怎么处理呢? msg.obj代表的是你开启IntentService的Intent对象, 这个时候可以从这个Intent对象中解析出外界所要传递的参数,通过这些参数就可以区分具体的后台任务。 onHandleIntent执行完毕后,stopSelf(taskId)会等待所有的消息执行完毕之后才终止服务。 判断所有消息执行完毕:最近启动服务的次数和startId是否相等,相等就认为所有消息都执行完毕,否则就不会终止服务。 执行顺序的问题: 执行一次后台任务开启一次IntentService,而内部是通过Handler发送消息来处理的, 而Looper轮询消息是有顺序的,所以当有多个后台任务时,会按照外界发起的顺序来执行。
例子:
class MyIntentService extends IntentService{ public MyIntentService(String name) { super(name); } @Override protected void onHandleIntent(Intent intent) { String name=intent.getStringExtra("football"); Log.i(Constants.LOG,name); } @Override public void onDestroy() { super.onDestroy(); Log.i(Constants.LOG, "onDestroy"); } } Intent service=new Intent(this,MyIntentService.class); service.putExtra("football","ronaldo"); startService(service); service.putExtra("football","messi"); startService(service);
4,android中的线程池
线程池出现的原因:
1,可以重用线程池中的线程,避免因为线程的开启和销毁带来的性能开销。 2,可以控制线程池的最大并发数,避免因为大量线程抢占系统资源而导致阻塞。 3,可以对线程进行管理,比如提供了定时执行和间隔循环执行的功能。
Android中的线程池来自于Java的Executor,它是一个接口,真正的实现是ThreadPoolExecutor类。
android中的几种线程池,底层都是由ThreadPoolExecutor来配置。
下面就来看看ThreadPoolExecutor。
ThreadPoolExecutor有很多的构造函数,通过指定这些参数来配置我们想要的线程池。 public ThreadPoolExecutor( int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue ThreadFactory threadFactory) corePoolSize:核心的线程池数量,默认情况下核心的线程池中的线程会一直存活,即使处于闲置状态 maximumPoolSize:线程池所能容纳的最大线程数量,活动的数量超过这个数值后,后续的新任务将会被阻塞 keepAliveTime:非核心线程的闲置的超时时长,超过这个时长,非核心线程会被回收 当ThreadPoolExecutor的allowCoreThreadTimeOut设定为true,同样也作用于核心线程 unit:用于指定keepAliveTime的时间单位,是个枚举 workQueue:线程池的任务队列,通过线程池的execute方法提交的Runnable对象会存储在这个参数中 threadFactory:线程工厂,为线程池提供创建新线程的功能,ThreadFactory是一个接口,只有一个方法:ThreadFactory.newThread
Android中常见的线程池:
通过查看其构造方法,根据ThreadPoolExecutor的参数信息,就可以知道每个线程池的功能特性。
创建FixedThreadPool Executors.newFixedThreadPool(nThreads); public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } 它是线程数量固定的线程池,并且线程都是核心线程。 由于都是核心线程,所有线程空闲的时候,也不会被回收。 当所有的线程都处于活动状态,没有闲置的线程时,如果有新任务过来,会处于等待状态。 只有核心线程,并且不回收,意味着FixedThreadPool可以更迅速的响应外界的请求。
创建CachedThreadPool Executors.newCachedThreadPool() public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); } 所有的线程都是非核心线程,并且非核心线程的数量没有上限。 当所有的线程都处于活动状态,如果有新任务过来,就会创建新的线程去执行新的任务。 TimeUnit为60秒,当空闲的线程超过60秒还是空闲,将会被回收。 由于会进行回收,所以几乎不怎么占用系统资源,适用于执行大量的耗时较少的任务。
创建ScheduledThreadPool Executors.newScheduledThreadPool() public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize){ return new ScheduledThreadPoolExecutor(corePoolSize); } public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS, new DelayedWorkQueue()); } DEFAULT_KEEPALIVE_MILLIS=10L 核心线程数量固定,非核心线程数量没有上限。并且非核心线程如果空闲会很快被回收。 适用于执行定时任务和具有固定周期的重复任务。
创建SingledThreadPool Executors.newSingleThreadExecutor() public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); } 核心线程有且只有一个,并且不会被回收。 它确保所有的任务都在同一个线程中按顺序执行。 它可以统一所有的外界任务在同一个线程中按顺序执行,使得这些线程之间不需要解决线程同步的问题。
相关文章推荐
- android中对图片进行切圆,画白边
- android studio 首字母提示 设置 大小写敏感
- Android中免Root实现Hook的Dexposed框架实现原理解析以及如何实现应用的热修复
- Android系列之广播
- geekband android #5 第十周分享(传感器)
- Android布局的各种对齐问题
- Android layout学习笔记
- Android开发中利用imeOptions属性将键盘回车键改成搜索等功能键【提高用户输入体验】
- Android Studio 2.1 稳定版开始支持 java8
- Android笔记之Content Provider(内容提供器)
- Android笔记之存储(SQLite数据库)
- Android笔记之数据存储(SharedPreferences)
- Android apk 反编译技术
- 作业——在线学习Android课程之第十周(传感器与LBS)
- Bitmap API
- Android 混淆Tips
- android tv关于第一次设置默认焦点失效的解决方案
- Android之ViewPager自动循环播放(轮播)效果实现(超简单)
- Android图片资源处理
- Adnroid多媒体---音视频