一、为什么要使用多线程?
默认情况下,当一个Android应用启动后,应用内部运行的线程只有一个,就是应用的UI线程,负责界面的展示以后用户和屏幕元素的互动。那么当我们需要进行网络下载、图片加载、复杂运算等比较耗时的操作时,如果也要主线程中进行,UI界面就没有足够的CPU时钟进行处理了,就会造成界面卡死的情况,这就是我们所说的ANR(Application Not Responding)。所以,为了防止出现这种情况,像这些耗时的操作我就需要开一个子线程去进行处理。
二、Runnable接口
我们在网上看线程的讲解的时候经常会看到Runnable这个接口的使用,其实Runnable只声明了一个接口函数,就是run()函数,它的作用就是给各种的线程类去继承并实现run方法。比如:FutureTask<V>、Thread、TimerTask等都实现了这个接口。我们只要记住它是一个只声明了run()函数的接口就好了。
三、使用Thread类实现多线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public void onButtonThreadClick(View v){ Thread thread = new Thread(){ private int runcount = 0; @Override public void run() { Random rnd = new Random(); while (true) { runcount += rnd.nextInt(10); System.out.println("Thread is running." + runcount); if(runcount >= 100000){ textView.post(new Runnable() { @Override public void run() { textView.setText("RunValue: "+ runcount); } }); break; } } } }; thread.start(); } |
上面是一个Thread线程的例子,在这里要注意:
- Thread启动的线程不能直接访问UI组件,要通过组件的.post方法访问,如上面的textView.post(new Runnable() {})
- 要使用start()方法启动线程,不可以使用run()方法
四、使用AsyncTask实现多线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
public void onBtnAsyncTaskClick(View v){ myTask = new MyTask(); myTask.execute("OK"); } public void onBtnCancelTaskClick(View v){ if(myTask != null){ myTask.cancel(true); } } public class MyTask extends AsyncTask<String, Integer, Long>{ int runcount = 0; String owner = ""; @Override protected Long doInBackground(String... params) { Random rnd = new Random(); while (true) { runcount += rnd.nextInt(10); System.out.println(this.owner + " is running." + runcount ); publishProgress(runcount); if (runcount >= 100000) { if (isCancelled()) break; break; } } return null; } @Override protected void onPostExecute(Long aLong) { textView.setText("RunValue: " + runcount); super.onPostExecute(aLong); } @Override protected void onPreExecute() { super.onPreExecute(); } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); textView.setText("Progress: " + values[0]); } } |
上面是一个AsyncTask的例子,
- onPreExecute:doInBackground运行之前的函数,可以操作UI的组件
- doInBackground: 耗时的操作(网络下载、图像处理等)放到这个函数里
- onPostExecute:doInBackground运行之后的函数,可以操作UI的组件
- onProgressUpdate:用于在UI显示运算进度,需要在doInBackground里调用publishProgress
AsyncTask的优点:
- 结构清晰,易于理解
- 可显示进度
- 可方便操作UI组件
AsyncTask的缺点:
- 不能多个实例同时运行,每次要创建一个新的实例,比如myTask.execute(“OK”);就会抛异常
五、HandlerThread
HandlerThread适用于在一个线程中执行多个实时性不高的操作.具体参考下面的链接
HandlerThread的多个任务只能串行执行,不能同时执行多个任务
六、ExectuorService线程池
七、IntentService
IntentService实际是继承自Service的一个类,用于方便在一个Service创建一个执行比较耗时的任务
IntentService里面只有一个工作线程,也只能同时执行一个任务
Service的系统权限比较高,不容易被系统杀死
八、FutureTask、TimerTask继承自Runnable接口,并不是实现多线程的类,只是实现多线程的辅助类,如new Thread(futureTask).start();这样的。他们与直接使用Runnable接口的差别如下:
- FutureTask可以取消,可以返回结果
- TimerTask可以定时执行