欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android异步:Handler扩展

程序员文章站 2024-04-02 17:42:04
Android异步[2]:Handler扩展1.HandlerThread1.1 HandlerThread简介1.2 HandlerThread使用1.3 HandlerThread原理2.runOnUiThread2.1 runOnUiThread简介2.2 runOnUIThread使用2.3 runOnUIThread原理3.View#post()3.1 View#post()简介3.2 View#post()使用3.3 View#post()原理4.AsyncTask4.1 AysncTask简介...

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

相关标签: Android基础