android4.0之后,android不允许在UI线程(主线程)中运行其他耗时线程,如网络请求的线程,否则就会崩溃抛出NetWorkOnMainThreadException
而且将耗时线程放入主线程中执行,会大大影响客户体验,所以android为我们提供了其他的处理方法,其中一种常用的就是,异步任务AsyncTask;
AsyncTask的底层其实是对Thread、Handler、Message的封装,智能的应用了Handler(子线程将运行结果返回到handler队列中,主线程定时扫描该队列,取出要用的值);
我们一般可以新建一个类**Task继承于AsyncTask类,通过覆写其方法实现主线程和子线程的数据交互:
1,新建一个任务继承AsyncTask需要传入三个参数,即:<Params, Progress, Result>
2,启动异步方法:new **Task().excute(?);?处用来向**Task()方法传值,即上面的Params(一般用map<>,或String);注意:每new一个对象只能进行一次调用excute()操作
3,常用的覆写方法有:
onpreExcute():此方法在开启异步方法后,第一个执行,属于对主线程的操作;应用:比如让某个控件隐藏等操作放进这个方法里;
onInBackground():此方法执行后,异步方法会自动开启一个线程(为什么不说new一个线程,这涉及到其底层的工作原理,后面会有阐述),执行该方法内部的逻辑,这个方法属于子线程的操作,要跟其他方法有所区分;
此方法会接收第一个参数Params,进行处理,并返回第三个参数Result,并可以在过程中进行第二个参数progress的赋值,通过publishProgress()方法将数值传递给下一个方法onProgressUpdate();
onProgressUpdate();此方法通过setProgress()处理从上面方法接收过来的数据,对UI线程的进度条控件进行管理;
onPostEcute():此方法可以接受onInBackground返回的Result,并对UI线程的某个控件进行管理;
4,异步方法的工作原理:
在异步方法工作时,会用到三个概念:任务队列缓冲池、线程池、线程队列;
首先,当某个Task类继承了AysncTask并开启了excute()方法后,该任务就会进入任务队列缓冲池中进行排队,等待CPU的调度
其次,当该Task类的对象执行了onInBackgrond()方法后,系统会在线程池中找空闲线程,如果有,将给任务交给这个空闲线程处理,如果没有,会new一个线程来处理这个任务;
再次,接到任务的线程会进入到线程队列中进行排队,等待CPU的调用,和其他任务线程快速切换执行;
(扩展:为什么”其次“中会存在空闲线程?因为在系统的实际运行过程中,线程的开启和销毁会消耗大量的CPU资源,系统为了避免这种情况导 致的系统卡顿,会建一个线程池,用来维护线程的持续运转,即当一个线程结束时,不会让它销毁,而是让其空转,等待接收其他任务,直到线程池销毁,线程才会 销毁,这是android后台对线程的优化处理;另外,异步任务的线程池存放线程数量是有上限的(这也决定了异步任务只能处理稳定的,轻量级的多线程任 务),超过其线程数量,任务将不会得到执行)
=================================
android3.0之前,异步任务是并发执行的,即几个任务同时切换执行,3.0之后,异步任务改成了顺序执行,即任务队列中的任务要一个个执行 (并非按顺序),一个执行不完,不能执行另一个,即,顺序执行,他是默认的执行方式-execue()方法,其默认执行的方法是:executeOnExecutor(AsyncTask.SERIAL_EXECUTOR),如果要并发执行,需要执行AsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR),且 为了防止系统的任务繁重,只在线程池中维护了5个线程,也就是,每次最多跑5个任务(类似于迅雷下载)。如果需要并发更多的任务,需要自定义线程池了。所 以异步任务只适合处理一些轻量级的并随时修改UI的异步线程,如果遇到繁重的任务,最好自己新建一个Thread并用handler和looper机制处 理。