Android中的多线程

一、概述

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 future = executor.submit(new Callable() {

@Override

public String call() throws Exception {

//执行任务的代码

return "result";

}

});

```

其中,Callable的call()方法可以返回一个结果,并且在任务执行完成后可以通过Future.get()方法获取。

3. 关闭线程池

在应用程序退出之前,需要关闭线程池,释放资源。关闭线程池有两种方式:shutdown()和shutdownNow()。

- shutdown():调用该方法后,线程池不再接受新的任务提交,但会等待任务队列中的任务执行完成后再关闭线程池。

```java

executor.shutdown();

```

- shutdownNow():调用该方法后,线程池会尝试停止所有正在执行的任务,并返回那些未执行的任务。

```java

List runnables = executor.shutdownNow();

```

三、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/

点赞(76) 打赏

评论列表 共有 1 条评论

错恋* 8月前 回复TA

作为摄影师,最难为的是你不得不拍片。

立即
投稿
发表
评论
返回
顶部