详解Android的Handler机制原理
以下是Android Handler机制的主要组成部分和工作原理:
1.Message(消息):Message是一个包含要传递的数据和指令的对象。它可以携带整数、字符串、Bundle等不同类型的数据。当需要在不同线程之间传递数据或执行任务时,通常会创建一个Message并将其发送给Handler。
2.Handler(处理程序):Handler是用于处理Message的对象。它通常与一个特定的线程(通常是主线程)关联。通过Handler,您可以将Message发送到与其关联的线程的消息队列中,以便在那个线程中执行处理。
3.Looper(消息循环器):Looper是一个用于管理线程的消息队列的对象。每个线程都可以有一个Looper,它会在线程上创建一个消息队列,允许该线程接收并处理Message。主线程通常已经具有一个默认的Looper,而后台线程需要显式创建一个Looper。
4.MessageQueue(消息队列):MessageQueue是一个FIFO(先进先出)队列,用于存储待处理的Message。每个Looper都有一个关联的MessageQueue,Handler将Message发送到这个队列中,然后由Looper依次处理队列中的Message。
Handler机制的工作流程:
1.在主线程(或其他线程)上创建一个Handler对象,这个Handler会关联到当前线程的Looper。
2.在后台线程中,创建一个Message对象,可以将一些数据和处理指令放入这个Message。
3.使用Handler的sendMessage方法将Message发送到与Handler关联的Looper的MessageQueue中。
4.Looper在后台线程中不断轮询MessageQueue,当有新的Message到达时,将Message取出并交给Handler处理。
5.Handler收到Message后,可以根据Message中的指令执行相应的操作,通常是在主线程中更新UI。
6.如果需要定时任务或循环执行,可以使用Handler的postDelayed方法。
Handler 的三种使用方法,分别是:
Handler.sendMessage(Message)
Handler.post(Runnable)
Handler.obtainMessage(what).sendToTarget();
1. Handler.sendMessage()方法
Handler.sendMessage(Msg) 方法是最为常见的一种方法。
1.1 使用步骤说明
其使用步骤分四步,如下所示:
1、步骤一:新建 Handler 对象,覆写 handleMessage(Message) 方法。
2、步骤二:新建 Message 对象,设置其携带的数据。
3、步骤三:在子线程中通过 Handler.sendMessage(Message) 方法发送信息。
4、步骤四:在 Handler 的 handleMessage(Message msg) 方法中处理消息,通知主线程作出相对应的 UI 工作。
步骤一:新建 Handler 对象,覆写 handleMessage(Message) 方法
//创建 Handler对象,并关联主线程消息队列 mHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { super.handleMessage(msg); ···略··· } } };
步骤二:新建 Message 对象,设置其携带的数据
Bundle bundle = new Bundle(); bundle.putInt(CURRENT_PROCESS_KEY, i); Message msg = new Message(); msg.setData(bundle); msg.what = 2;
步骤三:在子线程中通过 Handler.sendMessage(Message) 方法发送信息
mHandler.sendMessage(msg)
步骤四:在 Handler 的 handleMessage(Message msg) 方法中处理消息,通知主线程作出相对应的 UI 工作
mHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { super.handleMessage(msg); //根据信息编码及数据做出相对应的处理 switch (msg.what) { case 1: //更新 TextView UI mDisplayTv.setText("CustomChildThread starting!"); break; case 2: //获取 ProgressBar 的进度,然后显示进度值 Bundle bundle = msg.getData(); int process = bundle.getInt(CURRENT_PROCESS_KEY); mProgressBar.setProgress(process); break; default: break; } } };
1.2.1Java版本的具体代码如下所示:
public class HandlerAddThreadActivity extends AppCompatActivity { public static final String CURRENT_PROCESS_KEY = "CURRENT_PROCESS"; private TextView mDisplayTv; private Handler mHandler; private ProgressBar mProgressBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_handler_add_thread); TextView titleTv = findViewById(R.id.title_tv); titleTv.setText("Handler + Thread"); mDisplayTv = findViewById(R.id.display_tv); mProgressBar = findViewById(R.id.test_handler_progress_bar); //mHandler用于处理主线程消息队列中的子线程消息 mHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case 1: //更新 TextView UI mDisplayTv.setText("CustomChildThread starting!"); break; case 2: //获取 ProgressBar 的进度,然后显示进度值 Bundle bundle = msg.getData(); int process = bundle.getInt(CURRENT_PROCESS_KEY); mProgressBar.setProgress(process); break; default: break; } } }; Button mClickBtn = findViewById(R.id.click_btn); mClickBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //开启子线程,子线程处理UI工作 CustomChildThread customThread = new CustomChildThread(); customThread.start(); } }); } /** * 子线程,用于处理耗时工作 */ public class CustomChildThread extends Thread { @Override public void run() { //在子线程中创建一个消息对象 Message childThreadMessage = new Message(); childThreadMessage.what = 1; //将该消息放入主线程的消息队列中 mHandler.sendMessage(childThreadMessage); //模拟耗时进度,将进度值传给主线程用于更新 ProgressBar 进度。 for (int i = 1; i <= 5; i++) { try { //让当前执行的线程(即 CustomChildThread)睡眠 1s Thread.sleep(1000); //Message 传递参数 Bundle bundle = new Bundle(); bundle.putInt(CURRENT_PROCESS_KEY, i); Message progressBarProcessMsg = new Message(); progressBarProcessMsg.setData(bundle); progressBarProcessMsg.what = 2; mHandler.sendMessage(progressBarProcessMsg); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
1.2.2Kotlin版本的代码如下所示:
class TestThreadAddHandlerActivity : AppCompatActivity() { companion object { const val PROGRESS_VALUE_KEY = "PROGRESS_VALUE" } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_thread_add_handler) handlerAddThreadStartBtn.setOnClickListener(View.OnClickListener { //工作线程开始模拟下载任务 val workThread: WorkThread = WorkThread(this) workThread.start() }) } class WorkThread(activity: TestThreadAddHandlerActivity) : Thread() { private var handler: MyHandler = MyHandler(activity) override fun run() { super.run() for (i in 0..6) { sleep(1000) //通过 Handler 将进度参数传递给 主线程,让其更新 progressBar 进度 val message = Message() message.what = 1 val bundle = Bundle() bundle.putInt(PROGRESS_VALUE_KEY, i) message.data = bundle handler.sendMessage(message) } } } /** * 静态内部类,防止内存泄漏 */ class MyHandler(activity: TestThreadAddHandlerActivity) : Handler() { private var weakReference = WeakReference(activity) override fun handleMessage(msg: Message) { super.handleMessage(msg) //处理消息 when (msg.what) { 1 -> { val activity = weakReference.get() if (activity != null && !activity.isFinishing) { //获取消息中携带的任务处理进度参数,然后设置成 ProgressBar 的进度。 val progressValue: Int = msg.data.get(PROGRESS_VALUE_KEY) as Int activity.handlerAddThreadProgressBar.progress = progressValue } } } } } }
2. Handler.post()方法
除了使用 Handler.sendMessage(Message) 来发送信息,Handler 还支持 post(Runnable) 方法来传递消息,通知主线程做出相对应的 UI 工作。使用方法如下:
/** * 将可运行的 Runnable 添加到消息队列。Runnable 将在该 Handler 相关的线程上运行处理。 * The runnable will be run on the thread to which this handler is attached. */ new Handler().post(new Runnable() { @Override public void run() { //更新处理 UI 工作 } });
2.1 Java版本的具体代码如下
public class HandlerPostFunctionActivity extends AppCompatActivity { private Handler mMainHandler; private ProgressBar mProgressBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_handler_add_thread); TextView titleTv = findViewById(R.id.title_tv); titleTv.setText("Handler post() function"); mProgressBar = findViewById(R.id.test_handler_progress_bar); //新建静态内部类 Handler 对象 mMainHandler = new Handler(getMainLooper()); Button mClickBtn = findViewById(R.id.click_btn); mClickBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //开启子线程,子线程处理UI工作 CustomChildThread customThread = new CustomChildThread(); customThread.start(); } }); } /** * 子线程,用于处理耗时工作 */ public class CustomChildThread extends Thread { @Override public void run() { //模拟耗时进度,将进度值传给主线程用于更新 ProgressBar 进度。 for (int i = 1; i <= 5; i++) { try { //让当前执行的线程(即 CustomChildThread)睡眠 1s Thread.sleep(1000); //新创建一个 Runnable 用户处理 UI 工作 MyRunnable runnable = new MyRunnable(HandlerPostFunctionActivity.this, i); //调用Handler post 方法。 mMainHandler.post(runnable); } catch (InterruptedException e) { e.printStackTrace(); } } } } /** * 将 Runnable 写成静态内部类,防止内存泄露 */ public static class MyRunnable implements Runnable { private int progressBarValue; private WeakReference<HandlerPostFunctionActivity> weakReference; MyRunnable(HandlerPostFunctionActivity activity, int value) { this.weakReference = new WeakReference<>(activity); this.progressBarValue = value; } @Override public void run() { HandlerPostFunctionActivity activity = weakReference.get(); if (activity != null && !activity.isFinishing()) { activity.mProgressBar.setProgress(progressBarValue); } } } }
2.2 Kotlin版本的具体代码如下:
class TestHandlerPostRunnableActivity : AppCompatActivity() { private var mMainHandler: Handler? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_thread_add_handler) handlerAddThreadStartBtn.setOnClickListener(View.OnClickListener { //工作线程开始模拟下载任务 val workThread: WorkThread = WorkThread(this) workThread.start() }) //创建 Handler,关联App的 主Looper 对象 mMainHandler = Handler(Looper.getMainLooper()) } class WorkThread(private var activity: TestHandlerPostRunnableActivity) : Thread() { private var handler: Handler? = activity.mMainHandler override fun run() { super.run() for (i in 0..6) { sleep(1000) //新建 Runnable 设置进度参数传,然后通过 post(Runnable) 方法,让其更新 progressBar 进度 val runnable: MyRunnable = MyRunnable(activity, i) handler?.post(runnable) } } } /** * 处理 UI 工作。 * 静态内部类,防止内存泄露 */ class MyRunnable(activity: TestHandlerPostRunnableActivity, value: Int) : Runnable { private var weakReference = WeakReference(activity) private var progressValue = value override fun run() { val activity = weakReference.get() if (activity != null && !activity.isFinishing) { //获取任务执行进度参数,更新 progressBar 进度 activity.handlerAddThreadProgressBar.progress = progressValue } } } }
3. obtainMessage()方法
obtainMessage() 方法与 sendMessage() 方法很相似,通过 mHandler.obtainMessage().sendToTarget() 发送信息。该方法与 sendMessage() 的区别就是你不用额外去创建一个 Message 对象。
obtainMessage() 方法有三种,分别是:
//指定 what 用于区分,通过 Message.what 获得 public final Message obtainMessage(int what); //传递obj参数,通过 Message.obj 获得 public final Message obtainMessage(int what, @Nullable Object obj) //传递arg1 arg2参数,通过 Message.arg1 Message.arg2 获得 public final Message obtainMessage(int what, int arg1, int arg2)
3.1 Java版本的具体代码如下:
public class HandlerObtainMessageActivity extends AppCompatActivity { private TextView mDisplayTv; private Handler mHandler; private ProgressBar mProgressBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_handler_add_thread); TextView titleTv = findViewById(R.id.title_tv); titleTv.setText("Handler + Thread"); mDisplayTv = findViewById(R.id.display_tv); mProgressBar = findViewById(R.id.test_handler_progress_bar); //mHandler用于处理主线程消息队列中的子线程消息 mHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case 1: //更新 TextView UI mDisplayTv.setText("Handler obtainMessage() Test!!"); break; case 2: //通过 msg.obj 获取 ProgressBar 的进度,然后显示进度值 int process = (int) msg.obj; mProgressBar.setProgress(process); break; default: break; } } }; Button mClickBtn = findViewById(R.id.click_btn); mClickBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //开启子线程,子线程处理UI工作 CustomChildThread customThread = new CustomChildThread(); customThread.start(); } }); } /** * 子线程,用于处理耗时工作 */ public class CustomChildThread extends Thread { @Override public void run() { //发送第一条消息,代表开始执行异步任务 mHandler.obtainMessage(1).sendToTarget(); //模拟耗时进度,将进度值传给主线程用于更新 ProgressBar 进度。 for (int i = 1; i <= 5; i++) { try { //让当前执行的线程(即 CustomChildThread)睡眠 1s Thread.sleep(1000); //将执行进度参数 i 传递给主线程 progressBar mHandler.obtainMessage(2, i).sendToTarget(); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
3.2 Kotlin版本的具体代码如下:
class TestHandlerObtainMessageActivity : AppCompatActivity() { companion object { const val PROGRESS_VALUE_KEY = "PROGRESS_VALUE" } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_thread_add_handler) handlerAddThreadStartBtn.setOnClickListener(View.OnClickListener { //工作线程开始模拟下载任务 val workThread: WorkThread = WorkThread(this) workThread.start() }) } class WorkThread(activity: TestHandlerObtainMessageActivity) : Thread() { private var handler: MyHandler = MyHandler(activity) override fun run() { super.run() for (i in 0..6) { sleep(1000) //通过 Handler 将进度参数传递给 主线程,让其更新 progressBar 进度 val bundle = Bundle() bundle.putInt(PROGRESS_VALUE_KEY, i) handler.obtainMessage(1, bundle).sendToTarget() } } } /** * 静态内部类,防止内存泄漏 */ class MyHandler(activity: TestHandlerObtainMessageActivity) : Handler() { private var weakReference = WeakReference(activity) override fun handleMessage(msg: Message) { super.handleMessage(msg) when (msg.what) { 1 -> { val activity = weakReference.get() if (activity != null && !activity.isFinishing) { //获取任务执行进度参数,然后通过 ProgressBar 显示出来 val bundle: Bundle = msg.obj as Bundle val progressValue: Int = bundle.get(PROGRESS_VALUE_KEY) as Int activity.handlerAddThreadProgressBar.progress = progressValue } } } } } }
4. 总结:
在实际开发中,三种方法的使用都可行,具体用哪种方法,需结合你的实际情况及个人喜好。另外,在实际使用中往往将 Handler 写成静态内部类,这时需要注意防止内存泄露!(The handler class should be static or leaks might occur),具体代码见上方!
4.1 在子线程中创建Handler
思考: 在上面代码中, 我们都是在主线程中创建了 Handler 对象,那如果在子线程中创建一个 Handler 对象呢?会发生什么呢?
如下所示:我们在 CustomChildThread 线程中,新建一个 Handler 对象。
public class CustomChildThread extends Thread { @Override public void run() { Handler handler = new Handler(Activity.this); //会报错:java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() } }
结果: 抛出异常: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()。
原因: 因为在创建 Handler对象时要关联所处线程的 Looper对象,而我们的子线程没有 Looper,所以会抛出上述异常。
解决方法: 通过调用,Looper.prepare() 方法为子线程创建一个 Looper 对象,并且调用 Looper.loop() 方法开始消息循环。如下所示:
class CustomChildThread extends Thread { @Override public void run() { //为当前线程创建一个 Looper 对象 Looper.prepare(); //在子线程中创建一个 Handler 对象 Handler handler = new Handler() { public void handleMessage(Message msg) { // 在这里处理传入的消息 } }; //开始消息循环 Looper.loop(); } }
以上就是详解Android的Handler机制原理的详细内容,更多关于Android Handler机制的资料请关注脚本之家其它相关文章!
相关文章
Android Studio开发中Gradle各种常见报错问题解决方案
这篇文章主要为大家介绍了Android Studio开发中Gradle各种常见报错问题解决方案,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪2023-12-12Android之解析JSON数据示例(android原生态,FastJson,Gson)
本篇文章主要介绍了Android之解析JSON数据示例,主要使用android原生态代码解析,FastJson,Gson三种方法,有兴趣的可以了解一下。2017-02-02解决Android MediaRecorder录制视频过短问题
本文主要介绍Android MediaRecorder,在使用MediaRecorder时经常会遇到视频录制太短问题,这里提供解决问题的实例代码以供大家参考2016-07-07
最新评论