
Learn && Live
虚度年华浮萍于世,勤学善思至死不渝
Hey,欢迎阅读Connor学Android系列,这个系列记录了我的Android原理知识学习、复盘过程,欢迎各位大佬阅读斧正!原创不易,转载请注明出处:http://t.csdn.cn/BK6K4,话不多说我们马上开始!
在工作线程中更新UI(通过某些特定方法)
(1)使用 View 的 postInvalidate() 方法刷新页面
(2)使用 View 的 post() 或 postDelayed() 方法更新UI
(3)使用 Activity 的 runOnUIThread() 方法更新UI
TextView tv = (TextView) findViewById(R.id.hello_text);
// 1
tv.postInvalidate();
// 2
tv.post(new Runnable() {
@Override
public void run() {
tv.setText("Hi,Fresh By Post");
}
});
tv.postDelayed(new Runnable() {
@Override
public void run() {
tv.setText("Hi,Fresh By postDelayed :");
}
},1000);
// 3
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
tv.setText("OH,I am Fine!!!");
}
});
使用 Handler
(1)Handler是专门用来在线程之间传递消息的工具类,主要用于UI界面的更新、消息的传递与处理
(2)Handler发送消息的两种方法:
send方法:用于发送一个包含数据的Message对象,并在handleMessage(Message message)方法中处理
post系列的方法:用于发送一个Runnable对象,并在MessageQueue收到消息时执行
使用 AsyncTask
(1)AsyncTask是Android给我们提供的一种轻量级的异步任务类
(2)使用步骤:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H6U8AMF8-1662515145951)(F:\yhy925\dailylife\Work\2.Android\2.《Android进阶之光》\《Android进阶之光》知识点总结\3.AsncTask\1.方法.png)]
onPreExecute():在主线程执行。一般在任务执行前做准备工作,比如对 UI 做一些标记
doInBackground(Params… params):在线程池中执行。在 onPreExecute() 执行后执行,用于执行较为耗时的操作。在执行过程中可以调用 publishProgress(Progress… values) 来更新进度信息
onProgressUpdate(Process… values):在主线程中执行。当调用 publishProgress() 时,此方法会将进度更新到UI组件上
onPostExecute(Result result):在主线程中执行。当后台任务执行完成后,这个方法会被执行。doInBackground 方法得到的结果就是返回的 result 的值。此方法一般做任务执行后的收尾工作,比如更新 UI 和数据
public abstract class AsyncTask<Params, Progress, Result> { }
AsyncTask 是一个抽象的泛型类,它有三个泛型参数,如果不需要某个参数,可以将其设置为 void
(1)Params:参数类型
(2)Progress:后台任务执行进度的类型
(3)Result:返回结果的类型
private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
private static final int KEEP_ALIVE = 1;
……
private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);
(1)线程池使用的是 ThreadPoolExecutor ,核心线程数是5个,最大线程数是128,非核心线程空闲等待新任务的最长时间为1s
(2)采用的阻塞队列是 LinkedBlockingQueue,容量为10
(3)综合(1)(2),AsyncTask 最多同时容纳139个任务,超出后就会执行饱和策略,默认抛出 RejectedExecutionException
重要属性
(1)WorkerRunnable 实现了 Callable 接口,并实现了 call 方法,在 call 方法中调用了 doInBackground 方法来处理任务并得到结果,并最终调用 postResult 将结果投递出去
(2)FutureTask 是一个可管理的异步任务,实现了 Runnable 和 Future 接口,可以包装 Runnable 和 Callable,并提供给 Executor 执行,也可以调用线程直接执行(FutureTask.run())
(3)在构造函数中,将 WorkerRunnable 作为参数传给了 FutureTask
执行过程
(1)调用 AsyncTask 的 execute() 方法
(2)execute() 方法内会做下面三件事
(3)这个 exec 是一个 SerialExecutor,完成对 FutureTask 列表进行串行执行,它的 execute() 方法内会完成下面几件事
串行任务处理
SerialExecutor 实际上是一个 ThreadPoolExecutor,只不过对其做了处理,只能完成对 FutureTask 的串行处理,那是如何实现的呢?
(1)首先回到 exec 的 execute() 方法中,其中不仅维护了一个任务队列,还有一个指向队首的 FutureTask 的 Runnable 引用 mActive
(2)当处理队列中的第一个任务或 FutureTask 的 run() 方法执行完毕时,会调用synchronized修饰的 scheduleNext() 方法
(3)scheduleNext() 方法中会取出队首元素并赋值给 mActive,并由 ThreadPoolExecutor 调用 execute() 方法执行任务并返回结果
并行任务处理
那么有没有可能借助 AsyncTask 实现对任务的并行处理吗,答案是肯定的
Android 3.0及以上版本将 SerialExecutor 作为默认的线程,并没有完全删除原有的 ThreadPoolExecutor,因此可以通过如下代码实现
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "");
也可以通过该方法传入其他类型的线程池,甚至是自定义的线程池
// 其他类型
task.executeOnExecutor(Executors.newCachedThreadPool(), "");
// 自定义类型
Execuror exec = new ThreadPoolExecutor(0, Integer.MAX_VALUE,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
task.executeOnExecutor(exec, "");
onProgressUpdate
综合上面的叙述并没有发现这个方法的调用和执行过程,那么它是在什么情况下被调用的呢?
(1)首先明确可以在重写的 doInBackground() 方法中调用 publishProgress() 方法
(2)这个方法内部与 postResult() 方法类似,创建一个标志为 MESSAGE_POST_PROGRESS 的 Message 并通过 InternalHandler 发送
(3)InternalHandler 中接收到标志为 MESSAGE_POST_PROGRESS 的 Message 后就会调用 AsyncTask 的 onProgressUpdate() 方法
生命周期问题与内存泄露
AsyncTask会一直执行,直到doInBackground()方法执行完毕。如果AsyncTask被声明为Activity的非静态内部类,那么AsyncTask会持有对Activity的引用,如果在销毁activity的时候没有取消正在运行的AsyncTask,这会导致Activity没法被回收,从而导致内存泄露
结果丢失
屏幕旋转或Activity在后台被系统杀掉等情况会导致Activity的重新创建,之前运行的AsyncTask会持有一个之前Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将不再生效
处理不当容易导致任务阻塞
所以如果一个AsyncTask的doInBackGround方法中存在着一个无限循环没有正确处理,导致这个AsyncTask的doInBackGround方法一直运行,那么这会导致同一个进程中其他的AsyncTask的任务无法执行