Android异步:Handler扩展
Android异步[2]:Handler扩展
1.HandlerThread
1.1 HandlerThread简介
在前面使用Handler时,基本的方式是创建Thread执行耗时操作,并通过Handler传递结果、更新UI。HandlerThread是Android提供的一个类,可以看做Handler+Thread实现的简化版。
HandlerThread特点
- (1)使用相对简单,不用自己做创建线程、创建Looper等操作
- (2)HandlerThread会将到来的任务依次处理(只开了一个子线程),对排队任务比较友好;但不支持多个任务并发
- (3)可以通过延时发送消息的方式决定多个任务的执行顺序
1.2 HandlerThread使用
1.HandlerThread使用步骤
- (1)创建一个HandlerThread实例对象,并调用start()方法启动HandlerThread
- (2)使用HandlerThread的getLooper()获取内部Looper,用它创建工作线程的Handler
- (3)使用工作线程的Handler,发送消息处理异步任务
- (4)任务执行完后要手动将HandlerThread退出,防止线程一直存活
2.HandlerThread使用实例
private void demo(){
// 1.创建一个HandlerThread实例,参数为线程名
HandlerThread handlerThread = new HandlerThread("HandlerDemoThread");
// 2.调用start()方法启动HandlerThread
handlerThread.start();
// 3.创建工作线程Handler
Handler workerHandler = new Handler(handlerThread.getLooper()){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//这里是子线程,在此处进行耗时操作
//还可以在这里使用主线程的Handler更新UI
}
};
//4.发送消息,让线程工作
workerHandler.sendEmptyMessage(1);
//5.执行完成后退出
handlerThread.quitSafely();
}
1.3 HandlerThread原理
HandlerThread源码如下,通过源码可以看到:
- (1)HandlerThread是Thread的实现类,因此可以调用start()方法进入就绪状态,等待CPU调度
- (2)当HandlerThread获得CPU时间片后,执行run()方法,会先创建当前线程Looper,然后开启循环
- (3)在外部,可以通过HandlerThread对象的getLooper()获取Looper,并用它来创建Handler,这个Handler是子线程的
- (4)调用quit()后HandlerThread退出循环,run()方法就结束了,因此一个HandlerThread一旦退出无法恢复
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
private @Nullable Handler mHandler;
// 设置线程名称
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
// 设置线程名称和优先级
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
// Looper准备完成后的回调
protected void onLooperPrepared() {}
@Override
public void run() {
mTid = Process.myTid();
// 初始化当前线程的Looper
Looper.prepare();
synchronized (this) {
// 给外部变量mLooper赋值,让其他线程可以获取此线程的Looper
mLooper = Looper.myLooper();
// 创建完成后通知其他等待的线程
notifyAll();
}
Process.setThreadPriority(mPriority);
// 回调一下此方法,可以在这里进行一些操作
onLooperPrepared();
// Looper开始循环
Looper.loop();
mTid = -1;
}
public Looper getLooper() {
// 如果当前线程已经挂了,直接返回null
if (!isAlive()) return null;
// 如果先调用了这个方法,但线程的run()还没有跑,就阻塞,等待线程跑完
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {}
}
}
// 返回当前线程的Looper
return mLooper;
}
// 获取一个当前Looper相关的Handler,不过这个hide了,实际上拿到也没什么用,因为收到事件后的逻辑要自己写
@NonNull
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}
// 退出循环
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;
}
// 获得线程Id
public int getThreadId() {
return mTid;
}
}
2.runOnUiThread
2.1 runOnUiThread简介
runOnUIThread是Activity的方法,可以在子线程中调用,将消息发送到主线程,执行一些更新UI操作
runOnUIThread特点
- runOnUIThread是Activity的方法,只能在Activity中调用
- 接收的Runnable的run方法中是主线程,可以更新UI,不能进行耗时操作
- 它是通过Hander+Thread实现的,是一种便捷更新UI的方式
2.2 runOnUIThread使用
在Activity中可以直接调用此方法,传入一个Runnable对象,在Runnable的run方法中进行更新UI操作
private void loadData(){
new Thread(){
@Override
public void run() {
// 这里停10s中,模拟耗时操作
try{
TimeUnit.SECOND.sleep(10);
}catch(InterruptException e){
e.printStack();
}
runOnUiThread(new Runnable() {
@Override
public void run() {
// 这里是主线程,可以更新UI
}
});
}
}.start();
}
2.3 runOnUIThread原理
RunOnUIThread是通过Hander+Thread实现的,方法逻辑如下:
public final void runOnUiThread(Runnable action) {
// 如果当前线程不是主线程,则通过Handler发送Runnable执行,如果是主线程,直接调用run()方法执行
if (Thread.currentThread() != mUiThread) {
// Activity中的这个Handler是主线程的Handler
mHandler.post(action);
} else {
action.run();
}
}
3.View#post()
3.1 View#post()简介
Android中View提供了post()和postDelay()方法,让传入的Runnable在主线程中执行。与runOnUiThread类似,可以更新UI。
View#post()特点
- (1)post(Runnable action)可以将Runnable发送到主线程中执行,方便的更新UI
- (2)postDelayed(Runnable action, long delayMillis)可以延时发送Runnable去执行
- (3)这两个方法只有在View执行了attachToWindow()后才会生效,new View()去执行这两个方法是无效的。
3.2 View#post()使用
- (1)直接通过View的post()或postDelay()方法发送消息,更新UI
- (2)Runnable在主线程中执行,可以更新UI,但不能执行耗时操作
- (3)View只有在被加载到Window上之后,post才会执行;刚new出来的与Activity无关的View,post()无效
// 有效的方式
public class MainActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = findViewById(R.id.myBtn);
button.post(()->{
//这里是主线程,可以更新UI
Log.i("MyTest","当前线程:"+Thread.currentThread().getName());
});
}
}
// 无效的方式,因为此时ImageView是new出来的,和Activity的Window没有关系
public class MainActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView myView = new ImageView(this);
myView.post(()->{
//这里是主线程,可以更新UI
Log.i("MyTest","当前线程:"+Thread.currentThread().getName());
});
// 如果要生效,需要下面的代码,将View添加到Activity上
// LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(300,100);
// addContentView(myView,params);
}
}
3.3 View#post()原理
View#post()总体执行原理如下
- (1)检查View关联的AttachInfo是否为空,如果为空,就保存在View内部的HandlerActionQueue中
- (2)如果不为空,就调用mAttachInfo的Handler,发送Runnable到主线程中
- (3)mAttachInfo在ViewRootImpl的performTraversals中执行,会递归的将mAttachInfo发送到ViewGroup中的View中
- (4)post()的具体Runnable的执行时间会在测量、布局、绘制流程之后,此时View绘制流程完成,因此一定可以获取宽高
- (5)刚new出来的View和ViewGroup无关,因此不会执行绘制流程,post()自然无效
1.View#post()和postDelay()
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
// 如果AttachInfo不为空,直接调用AttachInfo的Handler的post()发送消息
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
// 否则将Runnable存到一个HandlerActionQueue中
getRunQueue().post(action);
return true;
}
public boolean postDelayed(Runnable action, long delayMillis) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.postDelayed(action, delayMillis);
}
getRunQueue().postDelayed(action, delayMillis);
return true;
}
2.AttachInfo不为空时
- (1)通过AttachInfo的mHandler发送消息去处理,mHandler是在构造时传入的
- (2)AttachInfo的构造时机在View的dispatchAttachedToWindow()中
- (3)dispatchAttachedToWindow()在ViewRootImpl的performTraversals()中调用,然后执行测量、布局、绘制流程
- (4)上述方法会递归的遍历ViewGroup中的所有View,然后执行它们的dispatchAttachedToWindow()
// (1)AttachInfo是View的静态内部类,它的Handler赋值时机如下
final static class AttachInfo {
final Handler mHandler;
AttachInfo(IWindowSession session, IWindow window, Display display,
ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer,Context context) {
// 其他赋值操作略,这里mHandler是外接传入的handler
// 因此外接传入的Handler是哪个线程,这里就把Runnable发给哪个线程
mHandler = handler;
}
}
// (2)AttachInfo的赋值过程,在View的dispatchAttachedToWindow()中
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
mAttachInfo = info;
// 其他略
// 这里会把RunQueue中刚才发过来的Runnable取出来执行
if (mRunQueue != null) {
mRunQueue.executeActions(info.mHandler);
mRunQueue = null;
}
// 回调AttachToWindow()方法
onAttachedToWindow();
}
// (3)执行RunQueue#executeActions()方法,取出每个Runnable并交给Handler执行
public void executeActions(Handler handler) {
synchronized (this) {
final HandlerAction[] actions = mActions;
for (int i = 0, count = mCount; i < count; i++) {
final HandlerAction handlerAction = actions[i];
handler.postDelayed(handlerAction.action, handlerAction.delay);
}
mActions = null;
mCount = 0;
}
}
// (4)dispatchAttachedToWindow()在ViewRootImpl的performTraversals()中执行
private void performTraversals(){
final View host = mView; // 这个View就是DecorView,它是一个FrameLayout
if(mFirst){
...
// 执行DecorView的dispatchAttachedToWindow(),实际就是执行FrameLayout的对应方法
host.dispatchAttachedToWindow(mAttachInfo,0);
...
}
mFirst=false;
// 从队列中取出所有消息,派发给Handler执行
getRunQueue().executeActions(mAttachInfo.mHandler);
// 测量
performMeasure();
// 布局
performLayout();
// 绘制
performDraw();
}
// (5)ViewGroup的dispatchAttachedToWindow()
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
mGroupFlags |= FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
super.dispatchAttachedToWindow(info, visibility);
mGroupFlags &= ~FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
final int count = mChildrenCount;
final View[] children = mChildren;
for (int i = 0; i < count; i++) {
final View child = children[i];
child.dispatchAttachedToWindow(info,combineVisibility(visibility, child.getVisibility()));
}
final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
for (int i = 0; i < transientCount; ++i) {
View view = mTransientViews.get(i);
// 这里就是递归的执行此布局下所有View和ViewGroup的dispatchAttachedToWindow(),也即(2)位置
view.dispatchAttachedToWindow(info,combineVisibility(visibility, view.getVisibility()));
}
}
3.AttachInfo为空时
- 通过getRunQueue()方法获取HandlerActionQueue实例,并将Runnable封装成HandlerAction存到Queue中
- 在View被加载到窗体后,从HandlerActionQueue中取出所有Runnable并调用handler执行
// 获取HandlerActionQueue实例
private HandlerActionQueue getRunQueue() {
if (mRunQueue == null) {
mRunQueue = new HandlerActionQueue();
}
return mRunQueue;
}
// HandlerActionQueue,每个View有一个,存储多个HandlerAction
public class HandlerActionQueue {
private HandlerAction[] mActions; // 用数组存放
private int mCount;
public void post(Runnable action) {
postDelayed(action, 0);
}
public void postDelayed(Runnable action, long delayMillis) {
// 将Runnable和执行时间封装成一个HandlerAction,存起来
final HandlerAction handlerAction = new HandlerAction(action, delayMillis);
synchronized (this) {
if (mActions == null) {
mActions = new HandlerAction[4];
}
mActions = GrowingArrayUtils.append(mActions, mCount, handlerAction);
mCount++;
}
}
// HandlerAction就是一个存了Runnable和执行时间的POJO
private static class HandlerAction {
final Runnable action;
final long delay;
//...
}
}
4.AsyncTask
4.1 AysncTask简介
AsyncTask是Android提供的一个表示异步任务的类,可以执行耗时操作并更新UI。
1.AsyncTask特点
- 可以用来执行文件下载、文件读写、等耗时操作;在任务执行中可以更新进度,并在任务结束后回到主线程
- 相较于Handler+Thread的方式更加简单,且类的整体性更好
- 一个AsyncTask对象只能执行一次,在执行过程中可以随时取消
2.AsyncTask泛型参数
参数名 | 参数含义 | 常见参数类型 | 使用者 |
---|---|---|---|
Params | 输入参数 | String | doInBackground(Params …p) |
Progress | 进度参数 | Integer、Long | onProgressUpdate(Progress …p) |
Results | 输出参数 | Bitmap、File | onPostExecute(Results…r) |
3.AsyncTask回调方法
序号 | 方法名 | 方法作用 |
---|---|---|
1 | doInBackground(Params… p) | 抽象方法必须实现,执行耗时操作 |
2 | onPreExecute() | 执行前的准备操作,可用来初始化资源 |
3 | onPostExecute(Void aVoid) | 执行完成的提交操作,可以用来更新UI |
4 | onProgressUpdate(Progress… p) | 进度更新时回调,参数为当前进度 |
5 | onCancelled(Void aVoid) | 任务取消时回调 |
4.AsyncTask可执行方法
序号 | 方法名 | 方法作用 |
---|---|---|
1 | AsyncTask<Params, Progress, Result> execute(Params… params) | 执行任务 |
2 | AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,Params… params) | 在特定线程池执行任务 |
3 | boolean cancel(boolean mayInterruptIfRunning) | 取消任务(是否中断正在执行的任务) |
4 | boolean isCancelled() | 检查任务是否已取消 |
5 | void publishProgress(Progress… values) | 向onProgressUpdate()中传递任务执行进度 |
6 | void onProgressUpdate(Progress… values) | 当进度更新时回调,可以在这里实现进度条更新(UI操作) |
4.2 AsyncTask使用
1.AsyncTask使用步骤
- (1)创建AsyncTask实现类,规定泛型参数,按需实现抽象方法
- (2)在doInbackground()中执行耗时操作,使用publishProgress()发送进度;
- (3)在onProgressUpdate()中接收进度,此方法运行在主线程中,可以直接更新UI
- (4)在onPostExecute()中接收执行结果,此方法运行在主线程中,可以直接更新UI
- (5)在需要使用AsyncTask的地方,创建AsyncTask的实例,并通过execute()方法执行任务
- (6)执行过程中可以通过cancel()方法取消任务
2.AsyncTask注意事项
- execute()方法需要手动调用,输入参数Params就是在异步任务中定义的输入参数,必须在主线程中调用
- execute()后,回调方法执行顺序为execute->onPreExecute()->doInBackground()->onPostExecute()
3.AsyncTask使用实例
public class AsyncTaskDemo {
private List<FailedTaskListener> mListeners = new ArrayList<>();
private DownloadAsyncTask mTask;
public AsyncTaskDemo() {}
public void startTask(DownloadConfig[] configs) {
if (mTask != null) {
mTask.cancel(true);
mTask = null;
}
mTask = new DownloadAsyncTask(this);
mTask.execute(configs);
}
public void addFailedTaskListener(FailedTaskListener listener) {
mListeners.add(listener);
}
public void removeFailedTaskListener(FailedTaskListener listener) {
mListeners.remove(listener);
}
public void notifyFailedTask(List<DownloadConfig> failedConfigs) {
for (FailedTaskListener listener : mListeners) {
listener.onTaskHasFailed(failedConfigs);
}
}
public interface FailedTaskListener {
void onTaskHasFailed(List<DownloadConfig> failedConfigs);
}
static class DownloadConfig {
private int id;
private String url;
private String fileName;
// 构造器、getter、setter略
}
private static class DownloadAsyncTask extends AsyncTask<DownloadConfig, Integer, List<DownloadConfig>> {
private WeakReference<AsyncTaskDemo> mReferences;
DownloadAsyncTask(AsyncTaskDemo demo) {
this.mReferences = new WeakReference<>(demo);
}
@Override
protected List<DownloadConfig> doInBackground(DownloadConfig... downloadConfigs) {
List<DownloadConfig> failedConfigs = new ArrayList<>();
for (DownloadConfig config : downloadConfigs) {
if (!executeDownload(config)) {
failedConfigs.add(config);
}
}
return failedConfigs;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
Log.i("MyTest", "当前进度:" + values[0]);
}
@Override
protected void onPostExecute(List<DownloadConfig> failedConfigs) {
super.onPostExecute(failedConfigs);
mReferences.get().notifyFailedTask(failedConfigs);
}
private boolean executeDownload(DownloadConfig config) {
int count = 0;
while (count++ < 100) {
try {
// OkHttp模拟下载,此处略,用sleep模拟
TimeUnit.SECONDS.sleep(2);
publishProgress(count);
} catch (InterruptedException e) {
e.printStackTrace();
return false;
}
}
return true;
}
}
}
4.3 AsyncTask原理
AsyncTask是通过Handler+线程池实现的,线程池负责执行耗时操作,然后通过Handler切换线程。
1.创建任务
- (1)会绑定一个主线程的Handler
- (2)创建一个Callable对象mWorker,在call()中执行doInBackground()并在完成后postResult()发送结果
- (3)创建一个FutureTask对象mFuture,用于处理获取结果
public AsyncTask() {
this((Looper) null);
}
public AsyncTask(@Nullable Looper looper) {
mHandler = looper == null || looper == Looper.getMainLooper() ? getMainHandler(): new Handler(looper);
// 创建WorkerRunnable,这是一个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接收结果
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
// AtomicBoolean,设置取消状态
mCancelled.set(true);
throw tr;
} finally {
// 发送结果
postResult(result);
}
return result;
}
};
// 创建FutureTask,用来接收返回值
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);
}
}
};
}
2.执行任务
- (1)execute()会调用executeOnExecutor()在指定线程池上执行任务,如果没有则使用默认线程池
- (2)执行时先判断状态,处于执行中、已完成状态的任务不能被重复执行
- (3)回调onPreExecute()方法,通知调用者准备资源
- (4)将传入的参数传给WorkerRunnable
- (5)调用线程池的execute()方法执行FutureTask
- (6)此时会返回WorkerRunnable的call()内部,先执行doInBackground,并获取执行结果
- (7)在finally代码块中,使用Handler将获取的result发送出去,此时线程切换到主线程
- (8)在主线程中,根据执行结果决定回调onPostExecute()还是onCancelled(),至此任务结束
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,Params... params) {
// 首先判断一下状态,如果是RUNNING或FINISHED,抛出异常,说明一个异步任务只能执行一次
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)");
}
}
// 设置标志位为RUNNING
mStatus = Status.RUNNING;
// 回调onPreExecute()方法,此方法由使用者实现
onPreExecute();
// 设置WorkerRunnable的执行参数
mWorker.mParams = params;
// 调用线程池的execute()方法执行FutureTask
exec.execute(mFuture);
return this;
}
// postResult()
private Result postResult(Result result) {
// 这里会发送一个MESSAGE_POST_RESULT的消息,将结果通过Handler传过去
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
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:
// 接收到执行结果后,调用finish()方法处理
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
// 完成的方法
private void finish(Result result) {
// 如果取消,就回调取消;如果完成,就回调onPostExecute()
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
// 设置标志位,至此任务结束
mStatus = Status.FINISHED;
}
3.更新进度
- (1)publishProgress()会用Handler(默认主线程Handler)发送Message,传递进度
- (2)在接收到MESSAGE_POST_PROGRESS时回调onProgressUpdate(),默认在主线程中,用于更新进度
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
// 还是这段代码,这次看MESSAGE_POST_PROGRESS
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:
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
5.IntentService
5.1 IntentService简介
IntentService是一个抽象类,继承了四大组件中的服务Service,主要用于在Service中执行耗时操作。
IntentService的特点
- (1)适用于要执行耗时操作的场景,每次启动它相当于安排了一个任务
- (2)内部使用HandlerThread实现,多任务不能并发,只能排队执行
- (3)能且只能通过startService()方式启动
- (4)在执行完后会自动退出消息循环并关闭自身,不需要使用者回收
- (5)适用于Android7.0之前的场景;Android8.0及以上不适用IntentService(源码中类的注释可以看到)
5.2 IntentService使用
通常按如下步骤使用IntentService
- (1)写一个类,继承抽象类IntentService,实现它的有参构造器和onHandleIntent()方法
- (2)在onHandleIntent中,判断输入参数intent的类别(通常通过action),并根据不同类别的intent执行相应的耗时操作
- (3)IntentService是Service的子类,因此要在清单文件中注册
- (4)在需要启动时,通过startService()来启动IntentService
1.创建IntentService的实现类
public class MyIntentService extends IntentService {
public MyIntentService(String name) {
super(name);
}
@Override
protected void onHandleIntent(Intent intent) {
String action = intent.getAction();//根据action判断任务类型
if(action!=null){
switch (action){
case Request.REQUEST_1:
handleRequest1();
break;
case Request.REQUEST_2:
handleRequest2();
break;
}
}
}
private void handleRequest1() {//任务1,模拟耗时操作
try {
Thread.sleep(10*60);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void handleRequest2() {//任务2,模拟耗时操作
try {
Thread.sleep(20*60);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
2.通过不同的Intent启动IntentService
//通过startService(Intent intent)启动IntentService
private void handleAsyncTask(){
Intent intent1 = Request.getRequest1(this);
startService(intent1);
Intent intent2 = Request.getRequest2(this);
startService(intent2);
}
//请求1,表示第一类任务
public static Intent getRequest1(Context context){
Intent intent = new Intent(context,MyIntentService.class);
intent.setAction(REQUEST_1);
return intent;
}
//请求2,表示第二类任务
public static Intent getRequest2(Context context){
Intent intent = new Intent(context,MyIntentService.class);
intent.setAction(REQUEST_2);
return intent;
}
5.3 IntentService原理
IntentService的实现细节如下。
- (1)IntentService内部使用HandlerThread实现,通过HandlerThread的Looper创建Handler,并以Handler方式执行异步任务
- (2)IntentService在onCreate()方法中创建HandlerThread,并启动它的循环
- (3)在IntentService的onStart()时,会发送消息并最终执行onHandleIntent()方法,也即异步任务
- (4)在执行结束后,IntentService会自动关闭自己,并在onDestroy()中退出Looper的循环
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(),实现具体操作
onHandleIntent((Intent)msg.obj);
// 执行完后会结束自身
stopSelf(msg.arg1);
}
}
// 创建IntentService,传入的是Thread的名称
public IntentService(String name) {
super();
mName = name;
}
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public void onCreate() {
super.onCreate();
// 创建一个HandlerThread并启动循环
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
// 使用HandlerThread中的Looper创建Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
// 在调用onStart()时创建消息并通过Handler发送到MQ中,等待Looper取出执行
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
// 在服务销毁时退出Looper的循环
mServiceLooper.quit();
}
@Override
@Nullable
public IBinder onBind(Intent intent) {
return null;
}
// 具体执行逻辑的方法
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}
本文地址:https://blog.csdn.net/zhxaabbcc/article/details/110288813
上一篇: ajax请求后台接口数据与返回值处理js的实例讲解
下一篇: HTML5中你不知道的5个新功能
推荐阅读
-
Android异步:Handler扩展
-
Android AsyncTack 异步任务实例详解
-
学习Android Handler消息传递机制
-
详解Android的OkHttp包编写异步HTTP请求调用的方法
-
Android的HTTP扩展包OkHttp中的缓存功能使用方法解析
-
Android Handler消息派发机制源码分析
-
详解Android的OkHttp包编写异步HTTP请求调用的方法
-
Android中Handler引起的内存泄露问题解决办法
-
Android计时器的三种实现方式(Chronometer、Timer、handler)
-
Android使用缓存机制实现文件下载及异步请求图片加三级缓存