我是靠谱客的博主 笨笨泥猴桃,这篇文章主要介绍多线程(四)、Android多线程使用及AsyncTask源码分析,现在分享给大家,希望可以做个参考。

本篇是多线程系列的第四篇,如果对前三篇感兴趣的也可以去看看。

多线程(一)、基础概念及notify()和wait()的使用

多线程(二)、内置锁 synchronized

多线程(三)、线程池 ThreadPoolExecutor 知识点总结

除了前面的线程池的使用外,在Android中,我们除了通过Thread创建线程外,还可以通过 AsyncTaskIntentServiceHandleThread 来创建,线程池前面一篇已经详细介绍了,下面对其他几个方法简单的介绍。

1.1、HandleThread

1.1.1、源码
复制代码
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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
public class HandlerThread extends Thread { int mPriority; int mTid = -1; Looper mLooper; public HandlerThread(String name) { super(name); mPriority = Process.THREAD_PRIORITY_DEFAULT; } public HandlerThread(String name, int priority) { super(name); mPriority = priority; } protected void onLooperPrepared() { } @Override public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; } public Looper getLooper() { if (!isAlive()) { return null; } synchronized (this) { while (isAlive() && mLooper == null) { try { wait(); } catch (InterruptedException e) { } } } return mLooper; } public boolean quit() { Looper looper = getLooper(); if (looper != null) { looper.quit(); return true; } return false; } public boolean quitSafely() { Looper looper = getLooper(); if (looper != null) { looper.quitSafely(); return true; } return false; } public int getThreadId() { return mTid; } }

可以看到 HandlerThread 继承的是 Thread ,其在内部自己实现了 Looper,可以单独发送和接收消息,可以实现ui线程到子线程通信和子线程到子线程的通信。

1.1.2、使用

1、创建HandlerThread 并启动

复制代码
1
2
3
4
5
// 创建 HandlerThread 实例对象,参数为自定义线程名字,作为标记 handlerThread = new HandlerThread("HandlerThreadTest"); // 启动 HandlerThread handlerThread.start();

2、创建工作线程,并复写 handleMessage 方法

复制代码
1
2
3
4
5
6
7
8
9
10
11
// 创建工作线程,复写 handleMessage 方法 workHandler = new Handler(handlerThread.getLooper()) { @Override public void handleMessage(@NonNull Message msg) { super.handleMessage(msg); boolean isMain = Looper.myLooper() == Looper.getMainLooper(); System.out.println("收到消息:what=" + msg.what + ",message=" + (String) msg.obj); System.out.println("IsMainThread=" + isMain + ",currentThread:" + Thread.currentThread()); } };

3、发送消息 (这里模拟在子线程中发送消息)

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
new Thread(new Runnable() { @Override public void run() { // 使用工作线程向工作线程发送数据。 Message msg = Message.obtain(); msg.what = 1; msg.obj = "测试数据"; workHandler.sendMessage(msg); boolean isMain = Looper.myLooper() == Looper.getMainLooper(); System.out.println("IsMainThread=" + isMain + ",currentThread:" + Thread.currentThread()); } }).start();

4、释放

复制代码
1
2
3
// 释放 mHandlerThread.quitSafely();

运行结果:

可以看到上面的示例实现了在两个子线程之间数据传送。

如果我们将发送消息放在ui线程,即实现了ui线程到子线程的数据通信。

1.2、IntentService

1.2.1、源码

同样的,intentService源码也不多,这里直接贴出来。

复制代码
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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
public abstract class IntentService extends Service { private volatile Looper mServiceLooper; private volatile ServiceHandler mServiceHandler; private String mName; private boolean mRedelivery; private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { onHandleIntent((Intent)msg.obj); stopSelf(msg.arg1); } } public IntentService(String name) { super(); mName = name; } public void setIntentRedelivery(boolean enabled) { mRedelivery = enabled; } @Override public void onCreate() { // TODO: It would be nice to have an option to hold a partial wakelock // during processing, and to have a static startService(Context, Intent) // method that would launch the service & hand off a wakelock. super.onCreate(); HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); thread.start(); mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); } @Override public void onStart(Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); } @Override public int onStartCommand(Intent intent, int flags, int startId) { onStart(intent, startId); return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY; } @Override public void onDestroy() { mServiceLooper.quit(); } @Override public IBinder onBind(Intent intent) { return null; } @WorkerThread protected abstract void onHandleIntent(Intent intent); }

通过源码,可以看到 IntentService 是一个抽象类,还有一个抽象方法 onHandleIntent,继承至 Service

1.2.2、使用

新建一个MyIntentService继承至 IntentService

复制代码
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
public class MyIntentService extends IntentService { private static final String TAG = "MyIntentService"; public MyIntentService() { super("IntentService"); } @Override public void onCreate() { super.onCreate(); Log.i(TAG, "onCreate: "); } @Override public int onStartCommand(@Nullable Intent intent, int flags, int startId) { Log.i(TAG, "onStartCommand: "); return super.onStartCommand(intent, flags, startId); } @Override protected void onHandleIntent(@Nullable Intent intent) { boolean isMainThread = Looper.getMainLooper() == Looper.myLooper(); Log.i(TAG, "onHandleIntent: isMainThread=" + isMainThread); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } Log.i(TAG, "onHandleIntent: 任务结束"); } @Override public void onDestroy() { super.onDestroy(); Log.i(TAG, "onDestroy"); } }

2、跟Service一样,需要在 AndroidManifest.xml 中进行注册

复制代码
1
2
<service android:name=".MyIntentService">

3、启动服务

复制代码
1
2
startService(new Intent(this, MyIntentService.class));

运行结果:

可以看到在MyIntentServiceonHandleIntent 默认给我们开启了一个子线程来执行耗时操作,且当任务执行结束后自动停止服务,和Service的区别是 使用Service 可以同时执行多个请求,而使用IntentService 只能同时执行一个请求。

1.3、AsyncTask

AsyncTask 也是我们在Android中使用较为频繁的异步通信方法,我们可以通过 AsyncTask轻松的实现子线程到ui线程的通信,保证了线程安全,减少了我们通过 Thread + Handler 这种复杂的组合方法来实现,而且AsyncTask实现原理也是通过线程池,所以也具有上面线程池的好处。

1.3.1、使用
复制代码
1
2
3
4
public abstract class AsyncTask<Params, Progress, Result>{ // ...... }

首先可以看到 AsyncTask是一个抽象类,所以,我们在使用的时候需要创建自己的类来实现它,还要实现里面唯一的一个抽象方法。

复制代码
1
2
protected abstract Result doInBackground(Params... params);

可以看到抽象方法有三个泛型参数,分别是.

Params : 开始异步任务执行时传入的参数类型,与 doInBackground()参数和执行时调用 excute() 参数类型一致。

Progress : 异步任务执行过程中,返回下载进度值的类型,与 onProgressUpdate() 参数类型一致。

Result : 异步任务执行完成后,返回的结果类型,与doInBackground()的返回值类型还有 onPostExecute() 参数类型一致

使用 AsyncTask 时,除了必须实现的抽象方法外,一般还有几个方法比较重要,可以根据我们的需求进行重写

  • onPreExecute:主线程,执行线程任务前自动调用,通过在这个方法里面进行相应的初始化操作。
  • doInBackground:子线程,必须实现的抽象方法,方法里面为工作线程,可以进行耗时操作。
  • onProgressUpdate:主线程,任务执行时候,获取进度,通过在 doInBackground 方法中调用 publishProgress 来触发
  • onPostExecute :主线程,当任务执行结束后自动调用,可进行UI更新。

简单示例:

复制代码
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
48
// 新建 MyAsyncTask 实现 抽象类 AsyncTask // Params:Integer // Progress:String // Result:Double public class MyAsyncTask extends android.os.AsyncTask<Integer, String, Double> { @Override protected void onPreExecute() { super.onPreExecute(); System.out.println(TAG + "--onPreExecute"); } // 这里的参数类型为我们自己设置的Params 参数类型 @Override protected Double doInBackground(Integer... integers) { // 模拟耗时操作 try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(TAG + "--doInBackground length=" + integers.length); for (Integer i : integers) { System.out.println(TAG + "--doInBackground data=" + i); // 在 doInBackground 调用 publishProgress 触发 onProgressUpdate publishProgress(i + "—更新后的值"); } // 这里模拟返回结果,参数类型为我们设置的 Double return 2.2; } // 这里的参数类型为我们自己设置的String类型 (Progress) @Override protected void onProgressUpdate(String... values) { super.onProgressUpdate(values); for (String data : values) { System.out.println(TAG + "--onProgressUpdate date=" + data); } } // 任务执行结束后自动触发,参数类型为我们自己设置的Result 参数类型 @Override protected void onPostExecute(Double aDouble) { super.onPostExecute(aDouble); System.out.println(TAG + "--onPostExecute aDouble=" + aDouble); } }

调用 MyAsyncTask :

通过 execute 方法调用,需要在主线程里面执行,传入参数需要和 doInBackground 参数一致,及 Params 设置的类型。

只能调用一次,如果调用两次 execute 方法,会抛异常

Caused by: java.lang.IllegalStateException: Cannot execute task: the task is already running.

复制代码
1
2
3
MyAsyncTask myAsyncTask = new MyAsyncTask(); myAsyncTask.execute(100,101,102);

结果:

1.3.2、源码分析

我们深入 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
48
49
public AsyncTask(@Nullable Looper callbackLooper) { mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper() ? getMainHandler() : new Handler(callbackLooper); // 通过Callable创建一个任务 mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); Result result = null; try { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); // 从 doInBackground 中获取 result = doInBackground(mParams); Binder.flushPendingCommands(); } catch (Throwable tr) { mCancelled.set(true); throw tr; } finally { // 任务执行结束,将结果 发送到 postResult(result); } // 返回结果 return result; } }; // 将任务传给 FutureTask ,复写其 done 方法 mFuture = new FutureTask<Result>(mWorker) { @Override protected void done() { try { postResultIfNotInvoked(get()); } catch (InterruptedException e) { android.util.Log.w(LOG_TAG, e); } catch (ExecutionException e) { throw new RuntimeException("An error occurred while executing doInBackground()", e.getCause()); } catch (CancellationException e) { postResultIfNotInvoked(null); } } }; } // WorkerRunnable private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> { Params[] mParams; }

我们看到构造方法中,先创建了一个Callable的任务,在 多线程(一)、基础概念及notify()和wait()的使用 我们介绍了通过 Callable 来创建线程,可以在线程结束后获取结果,我们也看到在 任务里面通过 result = doInBackground(mParams) 获取到结果。任务创建后,将其放入到 FutureTask 中,这是 Callable 线程创建的标准用法。

看完构造方法,我们再来看调用 execute 方法执行的时候,它又做了啥。

复制代码
1
2
3
4
5
@MainThread public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }

这里没啥信息,直接调用了executeOnExecutor 方法,传入了 sDefaultExecutor 和我们设置的参数,再看 executeOnExecutor 方法:

复制代码
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 final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,Params... params) { if (mStatus != Status.PENDING) { switch (mStatus) { case RUNNING: throw new IllegalStateException("Cannot execute task:" + " the task is already running."); case FINISHED: throw new IllegalStateException("Cannot execute task:" + " the task has already been executed " + "(a task can be executed only once)"); } } mStatus = Status.RUNNING; // 调用了 onPreExecute 方法 onPreExecute(); mWorker.mParams = params; // 执行了我们在构造方法里面创建的mFuture exec.execute(mFuture); return this; }

这里面我们还是看到很有用的信息,首先调用了 onPreExecute 方法,这也是我们在执行 AsyncTask 方法的时候,调用的第一个方法,用来进行一些初始化操作,我们的任务通过 exec.execute(mFuture) 进行执行,看看我们传入的 sDefaultExecutor 是个啥。

最终创建了 SerialExecutor

复制代码
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
private static class SerialExecutor implements Executor { final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); Runnable mActive; public synchronized void execute(final Runnable r) { mTasks.offer(new Runnable() { public void run() { try { r.run(); } finally { scheduleNext(); } } }); if (mActive == null) { scheduleNext(); } } protected synchronized void scheduleNext() { if ((mActive = mTasks.poll()) != null) { THREAD_POOL_EXECUTOR.execute(mActive); } } }

内部声明了一个双端队列ArrayDeque类型的mTasks(双端队列中offer方法表示从队列尾插入,poll()表示从队列头获取元素)。

这里通过 mTasks.offer 将我们的任务不断的放入阻塞队列中,再通过 mTasks.poll() 拿出任务,最终通过 THREAD_POOL_EXECUTOR 来执行。

再看 THREAD_POOL_EXECUTOR 又是啥?

复制代码
1
2
3
4
5
6
7
8
static { ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), sThreadFactory); threadPoolExecutor.setRejectedExecutionHandler(sRunOnSerialPolicy); THREAD_POOL_EXECUTOR = threadPoolExecutor; }

我们前面说了,AsyncTask 内部是通过线程池来执行的,看这里应该就清楚了,任务的执行,实质是通过创建的 threadPoolExecutor线程池,来执行任务。按照前面的老规矩,看看具体参数。

参数说明:

复制代码
1
2
3
4
private static final int CORE_POOL_SIZE = 1; private static final int MAXIMUM_POOL_SIZE = 20; private static final int KEEP_ALIVE_SECONDS = 3;

int corePoolSize: 1

int maximumPoolSize: 20

long keepAliveTime:3

TimeUnit unit:TimeUnit.SECONDS

BlockingQueue workQueue:new SynchronousQueue()

1个核心线程,非核心线程数目为20,使用 SynchronousQueue 阻塞队列。

这里源码是查看的API 29 ,不同的版本有区别。

看到了任务的执行,那么AsyncTask是怎么实现子线程到主线程的数据通信的呢?

postResult:

复制代码
1
2
3
4
5
6
7
8
private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result; }

前面构造中,我们看到通过 doInBackground 返回的结果,通过 postResult 方法传递出去了,而在 postResult 里面就是通过Handler,来将数据从子线程传到了主线程。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private static class InternalHandler extends Handler { public InternalHandler(Looper looper) { super(looper); } @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"}) @Override public void handleMessage(Message msg) { AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj; switch (msg.what) { case MESSAGE_POST_RESULT: // There is only one result result.mTask.finish(result.mData[0]); break; case MESSAGE_POST_PROGRESS: result.mTask.onProgressUpdate(result.mData); break; } } }

我们再看看publishProgress

复制代码
1
2
3
4
5
6
7
protected final void publishProgress(Progress... values) { if (!isCancelled()) { getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult<Progress>(this, values)).sendToTarget(); } }

其本质,也是通过 Handler 来实现子线程到主线程的数据通信。

总结:所以,AsyncTask 本质是通过线程池来执行任务,并且封装了 Handler 来实现子线程到ui线程的数据传输。

优点:AsyncTask 是一个轻量级的异步任务处理类,轻量级体现在,使用方便、代码简洁上,而且整个异步任务的过程可以通过cancel()进行控制。

缺点:不适用于处理长时间的异步任务,一般这个异步任务的过程最好控制在几秒以内,如果是长时间的异步任务就需要考虑多线程的控制问题;当处理多个异步任务时,UI更新变得困难。

二、总结

多线程部分一共四篇,这篇收了个尾,后面也会继续对Android其他知识点进行总结,Android进阶系列也会一直写下去,如果文中有错误的地方,欢迎大佬们批评指点。

最后

以上就是笨笨泥猴桃最近收集整理的关于多线程(四)、Android多线程使用及AsyncTask源码分析的全部内容,更多相关多线程(四)、Android多线程使用及AsyncTask源码分析内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(377)

评论列表共有 0 条评论

立即
投稿
返回
顶部