一、概述
Android中的多线程是指在一个应用程序中同时运行多个独立的线程,每个线程各自独立执行,互不干扰。线程的创建和销毁都由应用程序控制,通过使用多线程技术可以提高应用程序的响应速度,增加用户体验。
Android中提供了多种多线程技术,其中最常用的是线程池和AsyncTask,本文将详细介绍这两种技术的使用方法和案例说明。
二、线程池
线程池是维护线程的一个池子,当需要执行任务时,从池子中申请一个线程来执行任务,任务执行完成后线程返回池子中。线程池可以控制线程的数量,同时减少了线程的创建和销毁的开销,提高了应用程序的性能。
1. 创建线程池
线程池可以通过ThreadPoolExecutor类来创建,需要传入以下几个参数:
- corePoolSize:线程池中核心线程的数量,当申请任务时,如果线程池中的线程数小于这个数量,就会新建一个线程来执行任务。当线程数大于或等于这个数量时,新来的任务会被加入到任务队列中排队等待执行。
- maximumPoolSize:线程池中最大线程的数量,当线程池中的线程数达到这个数量时,新来的任务会进入任务队列中排队等待执行。
- keepAliveTime:当线程池中的线程数大于corePoolSize时,如果这些线程都处于空闲状态(即没有任务可以执行),则这些线程会在keepAliveTime后自动销毁,直到线程池中的线程数等于corePoolSize。
- unit:keepAliveTime的时间单位。
- workQueue:任务队列,用来保存等待执行的任务。
- threadFactory:线程工厂,用来给线程起一个名字,方便调试。
- handler:当线程池达到最大线程数且任务队列已满时,用来处理无法执行的任务。
代码示例:
```java
private static final int CORE_POOL_SIZE = 5;//核心线程数
private static final int MAXIMUM_POOL_SIZE = 10;//最大线程数
private static final int KEEP_ALIVE_TIME = 3000;//线程空闲超时时间
private static final TimeUnit TIME_UNIT = TimeUnit.MILLISECONDS;//超时时间单位
private static final int QUEUE_CAPACITY = 10;//任务队列容量
ThreadPoolExecutor executor = new ThreadPoolExecutor(CORE_POOL_SIZE,
MAXIMUM_POOL_SIZE, KEEP_ALIVE_TIME, TIME_UNIT,
new ArrayBlockingQueue<>(QUEUE_CAPACITY), new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "ThreadPoolDemo");
}
}, new ThreadPoolExecutor.AbortPolicy());
```
2. 执行任务
线程池创建完成后,可以通过submit()方法提交任务给线程池来执行,这个方法有两种方式:可以提交Runnable类型的任务,也可以提交Callable类型的任务。
- Runnable类型的任务:
```java
executor.submit(new Runnable() {
@Override
public void run() {
//执行任务的代码
}
});
```
- Callable类型的任务:
```java
Future @Override public String call() throws Exception { //执行任务的代码 return "result"; } }); ``` 其中,Callable的call()方法可以返回一个结果,并且在任务执行完成后可以通过Future.get()方法获取。 3. 关闭线程池 在应用程序退出之前,需要关闭线程池,释放资源。关闭线程池有两种方式:shutdown()和shutdownNow()。 - shutdown():调用该方法后,线程池不再接受新的任务提交,但会等待任务队列中的任务执行完成后再关闭线程池。 ```java executor.shutdown(); ``` - shutdownNow():调用该方法后,线程池会尝试停止所有正在执行的任务,并返回那些未执行的任务。 ```java List ``` 三、AsyncTask AsyncTask是Android中的轻量级异步任务处理类,它提供了在后台线程中执行任务、在UI线程中更新UI的便捷机制,而不需要自己去创建和管理线程。AsyncTask在创建时必须指定三个泛型参数,分别是Params、Progress、Result,分别表示doInBackground()方法的参数类型、进度更新的类型、执行结果的类型。 1. AsyncTask的生命周期 - onPreExecute():在UI线程中执行,任务执行前调用,可以在这里做一些初始化操作。 - doInBackground(Params... params):在后台线程中执行,紧接着onPreExecute()方法的执行,用于执行耗时操作。 - onProgressUpdate(Progress... values):在UI线程中执行,当调用publishProgress()方法时,该方法被回调,用于更新UI界面上的进度条。 - onPostExecute(Result result):在UI线程中执行,当doInBackground()方法执行完成后,该方法被回调,用于更新任务执行结果。 2. AsyncTask的使用方法 继承AsyncTask,重写doInBackground()、onPostExecute()方法即可。 ```java private class MyTask extends AsyncTask @Override protected void onPreExecute() { super.onPreExecute(); //UI线程中执行,任务执行前调用,可以在这里做一些初始化操作 } @Override protected String doInBackground(Void... voids) { //在后台线程中执行,紧接着onPreExecute()方法的执行,用于执行耗时操作 return "result"; } @Override protected void onProgressUpdate(Void... values) { super.onProgressUpdate(values); //在UI线程中执行,当调用publishProgress()方法时,该方法被回调,用于更新UI界面上的进度条 } @Override protected void onPostExecute(String s) { super.onPostExecute(s); //在UI线程中执行,当doInBackground()方法执行完成后,该方法被回调,用于更新任务执行结果。 } } ``` 创建MyTask实例并执行任务: ```java MyTask task = new MyTask(); task.execute(); ``` 3. AsyncTask的注意事项 - AsyncTask只能被执行一次。如果想要再次执行任务,需要重新创建一个AsyncTask实例。 - 在UI线程中操作的代码可以放在onPreExecute()方法中,任务执行完成后更新UI界面的代码可以放在onPostExecute()方法中。 - doInBackground()方法不能操作UI界面。 四、案例示例 以下是一个示例,演示了使用线程池和AsyncTask来执行下载任务,并显示下载进度。 1. 使用线程池来下载图片 线程池执行下载任务,通过Handler更新UI进度。 ```java private ThreadPoolExecutor executor; private Handler handler; private void downloadImageWithThreadPool() { handler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (msg.what == 1) { progressBar.setProgress(msg.arg1); textView.setText(msg.arg1 + "%"); } else if (msg.what == 2) { imageView.setImageBitmap((Bitmap) msg.obj); } } }; executor = new ThreadPoolExecutor(5, 10, 3000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(10), new ThreadFactory() { @Override public Thread newThread(Runnable r) { return new Thread(r, "DownloadThread"); } }, new ThreadPoolExecutor.DiscardOldestPolicy()); executor.execute(new Runnable() { @Override public void run() { try { URL url = new URL("https://developer.android.com/images/brand/Android_Robot.png"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); conn.setReadTimeout(5000); if (conn.getResponseCode() == 200) { Bitmap bitmap = BitmapFactory.decodeStream(conn.getInputStream()); Message msg = handler.obtainMessage(); msg.what = 2; msg.obj = bitmap; handler.sendMessage(msg); } } catch (Exception e) { e.printStackTrace(); } finally { if (executor != null) { executor.shutdown(); } } } }); } ``` 2. 使用AsyncTask来下载图片 通过AsyncTask执行下载任务,并在onProgressUpdate()方法中更新UI进度。 ```java private DownloadTask task; private void downloadImageWithAsyncTask() { task = new DownloadTask(); task.execute(); } private class DownloadTask extends AsyncTask private int progress; @Override protected void onPreExecute() { super.onPreExecute(); progressBar.setProgress(0); textView.setText("0%"); } @Override protected Bitmap doInBackground(Void... voids) { try { URL url = new URL("https://developer.android.com/images/brand/Android_Robot.png"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); conn.setReadTimeout(5000); if (conn.getResponseCode() == 200) { int length = conn.getContentLength(); InputStream is = conn.getInputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len; while ((len = is.read(buffer)) != -1) { bos.write(buffer, 0, len); progress += len; publishProgress((int) ((progress / (float) length) * 100)); } byte[] data = bos.toByteArray(); return BitmapFactory.decodeByteArray(data, 0, data.length); } } catch (Exception e) { e.printStackTrace(); } return null; } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); progressBar.setProgress(values[0]); textView.setText(values[0] + "%"); } @Override protected void onPostExecute(Bitmap bitmap) { super.onPostExecute(bitmap); imageView.setImageBitmap(bitmap); } } ``` 注意,在AsyncTask中不能进行UI操作,需要通过onPreExecute()和onPostExecute()方法来操作。在doInBackground()方法中进行耗时操作,通过publishProgress()方法来更新进度。 五、小结 本文介绍了Android中的多线程技术,分别是线程池和AsyncTask。线程池适合执行多个独立的任务,可以控制线程的数量和各种参数,通过submit()方法提交任务执行。AsyncTask适合执行一个耗时操作并更新UI界面的任务,只需继承AsyncTask并重写相关方法即可。在使用时需要注意线程安全问题。 如果你喜欢我们三七知识分享网站的文章,
欢迎您分享或收藏知识分享网站文章
欢迎您到我们的网站逛逛喔!https://www.37seo.cn/
作为摄影师,最难为的是你不得不拍片。