##先大概认识下Android.os.AsyncTask类: android的类AsyncTask对线程间通信进行了包装,提供了简易的编程方式来使后台线程和UI线程进行通信:后台线程执行异步任务,并把操做结果通知UI线程。html
public abstract class AsyncTask<Params, Progress, Result> { ... }
doInBackground方法和onPostExecute的参数必须对应,这两个参数在AsyncTask声明的泛型参数列表中指定,第一个为doInBackground接受的参数,第二个为显示进度的参数,第第三个为doInBackground返回和onPostExecute传入的参数。android
public class MainActivity extends Activity { Button download; ProgressBar pb; TextView tv; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); pb = (ProgressBar) findViewById(R.id.pb); tv = (TextView) findViewById(R.id.tv); download = (Button) findViewById(R.id.download); download.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { DownloadTask dTask = new DownloadTask(); dTask.execute(1000); } }); } class DownloadTask extends AsyncTask<Integer, Integer, String> { // 后面尖括号内分别是参数(例子里是线程休息时间),进度(publishProgress用到),返回值 类型 @Override protected void onPreExecute() {//前期准备工做1.不能作耗时的任务2.本方法执行完后才能执行 doInBackground(Integer... params) tv.setText("开始执行任务"); } @Override protected String doInBackground(Integer... params) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } // 第二个执行方法,onPreExecute()执行完后执行 for (int i = 0; i <= 100; i++) { pb.setProgress(i);//能够在主线程或子线程里调用 ,子线程时内部使用了View的post方法, publishProgress(i); try { Thread.sleep(params[0]); } catch (InterruptedException e) { e.printStackTrace(); } } return "执行完毕"; } @Override protected void onProgressUpdate(Integer... progress) { // 这个函数在doInBackground调用publishProgress时触发,虽然调用时只有一个参数 // 可是这里取到的是一个数组,因此要用progesss[0]来取值 // 第n个参数就用progress[n]来取值 tv.setText(progress[0] + "%"); //super.onProgressUpdate(progress); } @Override protected void onPostExecute(String result) { // doInBackground返回时触发,换句话说,就是doInBackground执行完后触发 // 这里的result就是上面doInBackground执行后的返回值,因此这里是"执行完毕" setTitle(result); //super.onPostExecute(result); } } }
调用task.cancel(true);的方法在doInBackground()方法里判断任务是否取消,若是取消尽快结束后台方法。复写onCancelled(Result result)任务被取消时的方法。编程
@Override protected String doInBackground(Integer... params) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } // 第二个执行方法,onPreExecute()执行完后执行 String res = null; for (int i = 0; i <= 100; i++) { Log.d("jpc",i+" 是否取消了"+isCancelled()); if(isCancelled()){//添加是否取消的判断,尽快结束doInBackground()方法 res = "在"+i+"时取消了"; Log.d("jpc",i+" 取消了"); break; }else{ pb.setProgress(i);//能够在主线程或子线程里调用 ,子线程时内部使用了View的post方法, publishProgress(i); try { Thread.sleep(params[0]); } catch (InterruptedException e) { e.printStackTrace(); Log.d("jpc",i+" "+e); res = e.getMessage(); } res = "执行完毕"; } } return res; } @Override protected void onCancelled(String result) { Log.d("jpc"," onCancelled 取消了"); tv.setText(result +" onCancelled"); }
public static void execute(Runnable runnable) public final AsyncTask<Params, Progress, Result> execute(Params... params) public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params)数组
public static void execute(Runnable runnable):API 11 3.0之后提供的。利用AsyncTask里的串行线程池来执行任务,任务是依次执行,具体执行任务的线程来自线程池中。并发
private void executeTest1(){ for(int i = 0;i<200;i++){ final int index = i; Runnable runnable = new Runnable() { @Override public void run() { Log.d("jpc",index + " 开始执行 Thread ID = "+Thread.currentThread().getId()+ " Thread Name = "+Thread.currentThread().getName()); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } Log.d("jpc",index + " 结束执行 Thread ID = "+Thread.currentThread().getId()+ " Thread Name = "+Thread.currentThread().getName()); } }; AsyncTask.execute(runnable); } }
public final AsyncTask<Params, Progress, Result> execute(Params... params):利用串行的线程池依次执行任务,返回任务自己能够用来取消任务等操做。异步
**public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params)**API 11 3.0之后提供的。 这个接口容许开发者提供自定义的线程池来运行和调度Thread,若是你想让全部的任务都能并发同时运行,那就建立一个没有限制的线程池(Executors.newCachedThreadPool()),并提供给AsyncTask。这样这个AsyncTask实例就有了本身的线程池而没必要使用AsyncTask默认的(AsyncTask.THREAD_POOL_EXECUTOR ,核心线程数有限制超过等待,任务队列128有限制超过报错)。async
private void executeTest2(){ for(int i = 0;i<200;i++){ MyTask task = new MyTask(); task.execute(i); } } @SuppressLint("NewApi") private void executeTest3(){ for(int i = 0;i<200;i++){ MyTask task = new MyTask(); task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,i); } } @SuppressLint("NewApi") private void executeTest4(){ for(int i = 0;i<2000;i++){ MyTask task = new MyTask(); task.executeOnExecutor(Executors.newCachedThreadPool(),i); } } class MyTask extends AsyncTask<Integer, Void, String>{ @Override protected String doInBackground(Integer... params) { Log.d("jpc",params[0] + " 开始执行 Thread ID = "+Thread.currentThread().getId()+ " Thread Name = "+Thread.currentThread().getName()); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } Log.d("jpc",params[0] + " 结束执行 Thread ID = "+Thread.currentThread().getId()+ " Thread Name = "+Thread.currentThread().getName()); return params[0]+" 完成"; } }
有时候 AsyncTask.execute()的任务不必定立刻执行 AsyncTask主要有二个部分:一个是与主线各的交互,另外一个就是线程的管理调度。虽然可能多个AsyncTask的子类的实例,可是AsyncTask的内部Handler和ThreadPoolExecutor都是进程范围内共享的,其都是static的,也即属于类的,类的属性的做用范围是CLASSPATH,由于一个进程一个VM,因此是AsyncTask控制着进程范围内全部的子类实例。 与主线程交互 与主线程交互是经过Handler来进行的 线程任务的调度 内部会建立一个进程做用域的线程池来管理要运行的任务,也就就是说当你调用了AsyncTask#execute()后,AsyncTask会把任务交给线程池,由线程池来管理建立Thread和运行Therad。 因此全部的AsyncTask并不都会运行在单独的线程中,而是被SERIAL_EXECUTOR顺序的使用线程执行。由于应用中可能还有其余地方使用AsyncTask,因此某个AsyncTask也许会等待到其余任务都完成时才得以执行而不是调用executor()以后立刻执行。 那么解决方法其实很简单,要么直接使用Thread,要么建立一个单独的线程池(Executors.newCachedThreadPool())。或者最简单的解法就是使用executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR),这样起码不用等到前面的都结束了再执行。ide
生命周期 关于AsyncTask存在一个这样普遍的误解,不少人认为一个在Activity中的AsyncTask会随着Activity的销毁而销毁。而后事实并不是如此。AsyncTask会一直执行doInBackground()方法直到方法执行结束。一旦上述方法结束,会依据状况进行不一样的操做。函数
若是cancel(boolean)调用了,则执行onCancelled(Result)方法 若是cancel(boolean)没有调用,则执行onPostExecute(Result)方法 AsyncTask的cancel方法须要一个布尔值的参数,参数名为mayInterruptIfRunning,意思是若是正在执行是否能够打断, 若是这个值设置为true,表示这个任务能够被打断,不然,正在执行的程序会继续执行直到完成。若是在doInBackground()方法中有一个循环操做,咱们应该在循环中使用isCancelled()来判断,若是返回为true,咱们应该避免执行后续无用的循环操做。 总之,咱们使用AsyncTask须要确保AsyncTask正确地取消。post
很差好工做的cancel() 有时候起做用。 若是你调用了AsyncTask的cancel(false),doInBackground()仍然会执行到方法结束,只是不会去调用 onPostExecute()方法。可是实际上这是让应用程序执行了没有意义的操做。那么是否是咱们调用cancel(true)前面的问题就能解决呢?并不是如此。若是mayInterruptIfRunning设置为true,会使任务尽早结束,可是若是的doInBackground()有不可打断的方法会失效,好比这个BitmapFactory.decodeStream() IO操做。可是你能够提早关闭IO流并捕获这样操做抛出的异常。可是这样会使得cancel()方法没有任何意义。
内存泄露 还有一种常见的状况就是,在Activity中使用非静态匿名内部AsyncTask类,因为Java内部类的特色,AsyncTask内部类会持有外部类的隐式引用。因为AsyncTask的生命周期可能比Activity的长,当Activity进行销毁AsyncTask还在执行时,因为AsyncTask持有Activity的引用,致使Activity对象没法回收,进而产生内存泄露。
结果丢失 另外一个问题就是在屏幕旋转等形成Activity从新建立时AsyncTask数据丢失的问题。当Activity销毁并创新建立后,还在运行的 AsyncTask会持有一个Activity的非法引用即以前的Activity实例。致使onPostExecute()没有任何做用。
Android实战技巧:深刻解析AsyncTask [The Hidden Pitfalls of AsyncTask] (http://blog.danlew.net/2014/06/21/the-hidden-pitfalls-of-asynctask/) [Android中糟糕的AsyncTask] (http://www.open-open.com/lib/view/open1417955629527.html)