Android子线程更新UI主线程方法之Handler
- 格式:doc
- 大小:14.75 KB
- 文档页数:6
AndroidApp在线程中创建handler的⽅法讲解相关概念1.Handler:可以看做是⼀个⼯具类,⽤来向消息队列中插⼊消息的;2.Thread:所有与Handler相关的功能都是与Thread密不可分的,Handler会与创建时所在的线程绑定;3.Message:消息;4.MessageQueue:消息队列,对消息进⾏管理,实现了⼀个Message链表;5.Looper:消息循环,从MessageQueue中取出Message进⾏处理;6.HandlerThread:继承Thread,实例化时⾃动创建Looper对象,实现⼀个消息循环线程.在Android开发中经常会使⽤到线程,⼀想到线程,⼀般都会想到:new Thread(){...}.start();这样的⽅式。
这样如果在⼀个Activity中多次调⽤上⾯的代码,那么将创建多个匿名线程,如果这些线程的没有被销毁,那肯定会影响性能呢。
这个时候我么就想到了android提供的⼀个异步处理线程的类HandlerThread。
⼀般Handler的⽤法Handler handler = new Handler(){...};这样创建的handler是在主线程即UI线程下的Handler,即这个Handler是与UI线程下的默认Looper绑定的(当然也只有主线程才能这么⼲,⼦线程是⼲不了的,除⾮⾃⼰创建个looper)。
因此,有些时候会占⽤ui主线程,引起⼀些问题,所以我们就想到了重新创建个⼦线程,来处理handler。
使⽤HandlerThread解决问题HandlerThread实际上继承于Thread,只不过它⽐普通的Thread多了⼀个Looper。
我们可以使⽤下⾯的例⼦创建Handler HandlerThread thread = new HandlerThread("MyHandlerThread");thread.start();创建HandlerThread时要把它启动了,即调⽤start()⽅法。
android33 handle用法Android33是一款知名的移动操作系统,它提供了许多帮助开发者开发Android应用程序的工具和功能。
其中一个重要的工具就是handle(句柄),它在Android开发中扮演了重要的角色。
本文将介绍handle的用法,并详细解释如何在Android开发中使用handle来实现各种功能。
第一步,了解handle的概念和作用在Android中,handle是一个用于处理消息和事件的对象。
它可以将消息发送到一个特定的线程,以便在不同的线程之间进行通信和协作。
handle的主要作用是处理UI线程和后台线程之间的通信,以及进行定时任务的调度。
在Android 开发中,handle可以帮助开发者实现各种功能,如更新UI界面、处理网络请求、执行定时任务等。
第二步,创建handle对象并发送消息首先,我们需要创建一个handle对象,并将其绑定到一个特定的线程。
在Android中,我们通常会将handle绑定到UI线程,以便在后台线程中发送消息更新UI界面。
接下来,我们可以使用handle的sendMessage()方法来发送消息,并在handle的回调方法中处理这些消息。
第三步,更新UI界面在许多情况下,我们需要在后台线程中执行一些耗时的任务,并在任务完成后更新UI界面。
这时,handle就可以派上用场了。
我们可以在后台线程中执行任务,并使用handle的sendMessage()方法发送消息到UI线程,然后在handle的回调方法中更新UI界面。
这样就可以实现在后台线程中执行任务并更新UI界面的功能。
第四步,处理网络请求在Android开发中,我们经常需要执行网络请求并处理返回的数据。
在这种情况下,handle也可以帮助我们处理网络请求并更新UI界面。
我们可以在后台线程中执行网络请求,并使用handle的sendMessage()方法将数据发送到UI线程,然后在handle的回调方法中处理数据并更新UI界面。
深入解析Android中Handler消息机制Android提供了Handler 和Looper 来满足线程间的通信。
Handler先进先出原则。
Looper 类用来管理特定线程内对象之间的消息交换(MessageExchange)。
Handler消息机制可以说是Android系统中最重要部分之一,所以,本篇博客我们就来深入解析Android中Handler消息机制。
Handler的简单使用为什么系统不允许子线程更新UI因为的UI控件不是线程安全的。
如果在多线程中并发访问可能会导致UI控件处于不可预期的状态,那为什么不对UI控件的访问加上上锁机制呢?因为有这么两个缺点:1.上锁会让UI控件变得复杂和低效2.上锁后会阻塞某些进程的执行对于手机系统来说,这两个缺点是不可接受的,所以最简单高效的方法就是——采用单线程模型来处理UI操作。
对开发者而言也不是很麻烦,只是通过Handler切换一下访问的线程的就好。
Handler的简单使用既然子线程不能更改界面,那么我们现在就借助Handler让我们更改一下界面:主要步骤是这样子的:1.new出来一个Handler对象,复写handleMessage方法2.在需要执行更新UI的地方sendEmptyMessage 或者sendMessage3.在handleMessage里面的switch里面case不同的常量执行相关操作public class MainActivity extends ActionBarActivity {private TextView mTextView;private Handler mHandler;private static final int UI_UPDATE1 = 0;private static final int UI_UPDATE2 = 1;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(yout.activity_main);mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case UI_UPDA TE1:mTextView.setText("通过Handler方法1修改UI");break;case UI_UPDA TE2:mTextView.setText("通过Handler方法2修改UI");break;}}};mTextView = (TextView) findViewById(R.id.textview);mTextView.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Log.d("Test", "点击文字");updateUi();}});}protected void updateUi() {new Thread(new Runnable() {@Overridepublic void run() {// 方式一和方式二可以达到相同的效果,就是更改界面//方式一//mHandler.sendEmptyMessage(UI_UPDA TE1);//方式二Message msg = Message.obtain();msg.what = UI_UPDATE2;mHandler.sendMessage(msg);}}).start();}}<RelativeLayout xmlns:android="/apk/res/android"xmlns:tools="/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.example.handlerdemo3.MainActivity" ><TextViewandroid:id="@+id/textview"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/hello_world"android:layout_centerInParent="true"android:clickable="true" /></RelativeLayout>消息机制的分析理解安卓的异步消息处理机制就是handler机制。
什么是Handler?Handler主要用于异步消息的处理。
当有耗时操作时,因为UI线程不能进行耗时操作否则会产生ANR异常,因此把耗时操作要通过子线程来执行,而执行的结果如果需要更新到UI,这时子线程中又不能直接更新UI;所以Android提供了用Handler在子线程中向Looper发消息,把子线程执行结果封装到Message中,并发送到由Looper维护的属于这个子线程的消息队列,再由Looper轮询消息队列,按顺序取出Message,交由Handler并在主线程中使用(更新UI)。
特点:1.传递Message。
用于接受子线程发送的数据,并用此数据配合主线程更新UI。
2.传递Runnable对象。
用于通过Handler绑定的消息队列,安排不同操作的执行顺序。
Handler分发消息方法:post方法虽然发送的是一个实现了Runnable接口的类对象,但是它并非创建了一个新线程,而是执行了该对象中的run方法。
也就是说,整个run中的操作和主线程处于同一个线程。
post(Runnable)postAtTime(Runnable,long)postDelayed(Runnable,long)sendEmptyMessage(int)sendMessage(Message)sendMessageAtTime(Message,long)sendMessageDelayed(Message,long)Message的实例化:Message msg=new Message();Message msg=handler2.obtainMessage();msg.sendToTarget();//sendToTarget()可以替换下面的sendMessage//handler2.sendMessage(msg);Looper相关:Looper对象通过消息机制接受系统或者应用的其他线程提交的准备在UI线程上执行的代码。
handler的运行机制Handler的运行机制Handler是Android开发中非常重要的一个概念,它在Android 中起到了非常重要的作用,它可以帮助我们实现异步操作,以及主线程和子线程之间的通信。
Handler的运行机制分为三个部分:消息队列、消息处理器和消息。
我们来看看消息队列,消息队列是Handler的核心之一,它是用来保存消息的队列。
当我们向Handler发送消息时,它会将消息存放到队列中,然后由Handler按照一定的规则进行处理。
消息队列中的消息是按照优先级排序的,先进先出,后进后出。
接下来,我们来看看消息处理器,消息处理器是用来处理消息的。
当消息队列中有消息时,Handler会调用它的处理函数来处理消息。
消息处理器会根据消息的类型,执行相应的操作。
比如,当我们使用Handler.post()方法发送一个Runnable对象时,消息处理器会将它存储在消息队列中,并在处理时调用它的run()方法。
我们来看看消息,消息是Handler中的最小单位,它是用来传递信息的。
当我们向Handler发送消息时,我们需要创建一个Message对象,并将它传递给Handler。
Message对象中包含了消息的类型以及一些附加信息。
在Handler的处理函数中,我们可以根据消息的类型来执行相应的操作。
在整个Handler的运行过程中,主线程和子线程之间的通信是非常重要的。
当我们在子线程中执行一些操作时,如果需要更新UI,我们就需要使用Handler来实现。
在主线程中创建Handler对象,并将它传递给子线程,子线程就可以通过Handler来向主线程发送消息,从而更新UI。
总的来说,Handler的运行机制是非常复杂的,但是它的作用是非常重要的。
它可以帮助我们实现异步操作,以及主线程和子线程之间的通信。
在实际的开发中,我们需要熟练掌握Handler的使用,以便更好地开发出高质量的Android应用程序。
AndroidHandler消息机制原理解析前⾔做过 Android 开发的童鞋都知道,不能在⾮主线程修改 UI 控件,因为 Android 规定只能在主线程中访问 UI ,如果在⼦线程中访问 UI ,那么程序就会抛出异常android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy .并且,Android 也不建议在 UI 线程既主线程中做⼀些耗时操作,否则会导致程序 ANR 。
如果我们需要做⼀些耗时的操作并且操作结束后要修改 UI ,那么就需要⽤到 Android 提供的 Handler 切换到主线程来访问 UI 。
因此,系统之所以提供 Handler,主要原因就是为了解决在⼦线程中⽆法访问 UI 的问题。
概述要理解 Handler 消息机制原理还需要了解⼏个概念:1. UI 线程主线程 ActivityThread2. MessageHandler 发送和处理的消息,由 MessageQueue 管理。
3. MessageQueue消息队列,⽤来存放通过 Handler 发送的消息,按照先进先出执⾏,内部使⽤的是单链表的结构。
4. Handler负责发送消息和处理消息。
5. Looper负责消息循环,循环取出 MessageQueue ⾥⾯的 Message,并交给相应的 Handler 进⾏处理。
在应⽤启动时,会开启⼀个 UI 线程,并且启动消息循环,应⽤不停地从该消息列表中取出、处理消息达到程序运⾏的效果。
Looper 负责的就是创建⼀个 MessageQueue,然后进⼊⼀个⽆限循环体不断从该 MessageQueue 中读取消息,⽽消息的创建者就是⼀个或多个 Handler 。
流程图如下:下⾯结合源码来具体分析LooperLooper ⽐较重要的两个⽅法是 prepare( ) 和 loop( )先看下构造⽅法final MessageQueue mQueue;private Looper(boolean quitAllowed) {mQueue = new MessageQueue(quitAllowed);mThread = Thread.currentThread();}Looper 在创建时会新建⼀个 MessageQueue通过 prepare ⽅法可以为 Handler 创建⼀个 Lopper,源码如下:static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();private static Looper sMainLooper; // guarded by Looper.classpublic static void prepare() {prepare(true);}private static void prepare(boolean quitAllowed) {if (sThreadLocal.get() != null) {//⼀个线程只能有⼀个looperthrow new RuntimeException("Only one Looper may be created per thread");}sThreadLocal.set(new Looper(quitAllowed));}public static void prepareMainLooper() {prepare(false);synchronized (Looper.class) {if (sMainLooper != null) {throw new IllegalStateException("The main Looper has already been prepared.");}sMainLooper = myLooper();}}可以看到这⾥创建的 Looper 对象使⽤ ThreadLocal 保存,这⾥简单介绍下 ThreadLocal。
Android Handler 机制详解:在线程中新建Handler在android 中提供了一种异步回调机制Handler,使用它,我们可以在完成一个很长时间的任务后做出相应的通知handler 基本使用:在主线程中,使用handler 很简单,new 一个Handler 对象实现其handleMessage 方法,在handleMessage 中提供收到消息后相应的处理方法即可,这里不对handler 使用进行详细说明,在看本博文前,读者应该先掌握handler 的基本使用,我这里主要深入描述handler 的内部机制.现在我们首先就有一个问题,我们使用myThreadHandler.sendEmptyMessage(0);发送一个message 对象,那么Handler 是如何接收该message 对象并处理的呢?我先画一个数据结构图:从这个图中我们很清楚可以看到调用sendEmptyMessage 后,会把 Message 对象放入一个MessageQueue 队列,该队列属于某个Looper 对象,每个Looper 对象通过 ThreadLocal.set(new Looper())跟一个Thread 绑定了,Looper 对象所属的线程在Looper.Loop 方法中循环执行从MessageQueue 队列读取 Message 对象,并把Message 对象交由Handler 处理,调用Handler 的dispatchMessage 方法。
现在我们再来看一下使用Handler 的基本实现代码:12345678910// 主线程中新建一个handler normalHandler = new Handler () { public void handleMessage (android.os .Message msg ) { btnSendMsg2NormalHandler.setText ("normalHandler"); Log.d (Constant.TAG , MessageFormat .format ("Thread[{0}]--normalHandler handleMessage run...",Thread .currentThread () .getName ())); } };... //发送消息到hanlder1myThreadHandler.sendEmptyMessage (0);你现在已经很清楚了sendEmptyMessage到handleMessage的过程,途中经过Looper.MessageQueue队列,转由Looper所在的线程去处理了,这是一个异步的过程,当然Looper 所在的线程也可以是sendEmptyMessage所在的线程。
kotlin handler的用法Kotlin Handler 是一个用于处理线程间消息传递的工具类,在Android 开发中经常用于实现任务的延迟执行、定时执行以及在主线程更新 UI。
以下是 Kotlin Handler 的基本用法:1. 创建 Handler 对象:```kotlinval handler = Handler()```2. 在 Handler 中定义任务:```kotlinval runnable = Runnable {// 在这里执行需要在 Handler 中执行的任务}```3. 在指定的延迟时间后执行任务:```kotlinhandler.postDelayed(runnable, delayMillis)```其中,`delayMillis` 是延迟执行的时间,以毫秒为单位。
4. 在指定的时间间隔中循环执行任务:```kotlinhandler.postDelayed(object : Runnable {override fun run() {// 在这里执行需要循环执行的任务handler.postDelayed(this, delayMillis)}}, delayMillis)```通过在任务中再次调用 `postDelayed()` 方法来实现循环执行的效果。
5. 在主线程中执行任务:通常,需要在主线程中更新 UI,可以使用 Handler 将任务放到主线程队列中执行。
可以通过以下两种方式实现:- 在只包含一个任务的场景下,可以直接使用 `post()` 方法:```kotlinhandler.post {// 在这里执行需要在主线程中执行的任务}```- 在包含多个任务的场景下,可以使用 `post()` 方法或者`postAtFrontOfQueue()` 方法:```kotlinhandler.post(object : Runnable {override fun run() {// 在这里执行需要在主线程中执行的任务}})```6. 取消延迟执行的任务:如果在任务执行之前需要取消延迟执行的话,可以使用`removeCallbacks()` 方法:```kotlinhandler.removeCallbacks(runnable)```注意:在使用 Handler 的过程中,需要确保在 Activity 或Fragment 销毁之前取消所有未执行的任务,以避免内存泄漏等问题。
Android笔记(三⼗)Android中线程之间的通信(⼆)Handler消息传递机制什么是Handler之前说过了,Android不允许主线程(MainThread)外的线程(WorkerThread)去修改UI组件,但是⼜不能把所有的更新UI的操作都放在主线程中去(会造成ANR),那么只能单独启动⼀个⼦线程(WorkerThread)去处理,处理完成之后,将结果通知给UI主线程,⼦线程和主线程的通信就⽤到了Handler。
Handler、Looper和MessageQueue的基本原理先看⼀下他们的职责:Handler——处理者,负责发送以及处理Message。
MessageQueue——消息队列,⽤来存放Handler发送过来的消息,采⽤FIFO(first in first out)规则将Message以链表的⽅式串联起来的,等待Looper的抽取。
Looper——消息泵,不断的从消息队列中取出消息并回传给Handler1. Handler对象调⽤obtainMessage()⽅法获取Message对象2. 调⽤sendMessage(Message msg)⽅法将消息发送到消息队列(MessageQueue)中3. Looper循环这从消息队列中取出msg4. 调⽤Handler对象的handleMessage(Message msg)⽅法,将取出的msg传给HandlerHandler将消息传到队列,Looper从队列中拿到消息,然后⼜传给了Handler,这似乎是⼀个⽆⽤功,我们通过代码来看⼀下。
package cn.lixyz.handlertest;import android.app.Activity;import android.graphics.drawable.BitmapDrawable;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.util.Log;import android.view.View;import android.widget.Button;import android.widget.ImageView;/*** 实现点击按钮,开始播放幻灯⽚,每张幻灯⽚间隔2s。
Handler1、谈谈消息机制Handler作用?有哪些要素?流程是怎样的?参考回答:o负责跨线程通信,这是因为在主线程不能做耗时操作,而子线程不能更新UI,所以当子线程中进行耗时操作后需要更新UI时,通过Handler将有关UI的操作切换到主线程中执行。
o具体分为四大要素▪Message(消息):需要被传递的消息,消息分为硬件产生的消息(如按钮、触摸)和软件生成的消息。
▪MessageQueue(消息队列):负责消息的存储与管理,负责管理由Handler发送过来的Message。
读取会自动删除消息,单链表维护,插入和删除上有优势。
在其next()方法中会无限循环,不断判断是否有消息,有就返回这条消息并移除。
▪Handler(消息处理器):负责Message的发送及处理。
主要向消息池发送各种消息事件(Handler.sendMessage())和处理相应消息事件(Handler.handleMessage()),按照先进先出执行,内部使用的是单链表的结构。
▪Looper(消息池):负责关联线程以及消息的分发,在该线程下从MessageQueue获取Message,分发给Handler,Looper创建的时候会创建一个MessageQueue,调用loop()方法的时候消息循环开始,其中会不断调用messageQueue的next()方法,当有消息就处理,否则阻塞在messageQueue的next()方法中。
当Looper的quit()被调用的时候会调用messageQueue的quit(),此时next()会返回null,然后loop()方法也就跟着退出。
o具体流程如下在主线程创建的时候会创建一个Looper,同时也会在在Looper内部创建一个消息队列。
而在创键Handler的时候取出当前线程的Looper,并通过该Looper对象获得消息队列,然后Handler在子线程中通过MessageQueue.enqueueMessage在消息队列中添加一条Message。
Android子线程更新UI主线程方法之Handler
原文地址链接我们开发应用程序的时候,处于线程安全的原因子线程通常是不能直接更新主线程(UI线程)中的UI元素的,那么在Android开发中有几种方法解决这个问题,其中方法之一就是利用Handler处理的。
下面说下有关Handler相关的知识。
多线程一些基础知识回顾:在介绍Handler类相关知识之前,我们先看看在Java中是如何创建多线程的方法有两种:通过继承Thread类,重写Run方法来实现通过继承接口Runnable实现多线程具体两者的区别与实现,看看这篇文章中的介绍;接下来让我们看看Handler是什么?如何来用~~Handler是这么定义:主要接受子线程发送的数据, 并用此数据配合主线程更新UI. Handler 的主要作用:主要用于异步消息的处理Handler的运行过程:当(子线程)发出一个消息之后,首先进入一个(主线程的)消息队列,发送消息的函数即刻返回,而在主线程中的Handler逐个的在消息队列中将消息取出,然后对消息进行处理。
这样就实现了跨线程的UI更新(实际上还是在主线程中完成的)。
这种机制通常用来处理相对耗时比较长的操作,如访问网络比较耗时的操作,读取文大文件,比较耗时的操作处理等。
在大白话一点的介绍它的运行过程:启动应用时Android开启一个主线程(也就是UI线程) , 如果此
时需要一个耗时的操作,例如: 联网读取数据,或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,如果你放在主线程中的话,界面会出现假死现象(这也就是你在主线程中直接访问网络时会提示你异常的原因, 如下所述)。
这个时候我们需要把这些耗时的操作,放在一个子线
程中,因为子线程涉及到UI更新,Android主线程是线程不
安全的,更新UI只能在主线程中更新.。
这个时候,Handler 就出现了,来解决这个复杂的问题,由于Handler运行在主线
程中(UI线程中), 它与子线程可以通过Message对象来传递数据, 这个时候,Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传弟)Message对象,(里面包含
数据) , 把这些消息放入主线程队列中,配合主线程进行更新UI。
接下来我们看看关于HANDLER都有哪些方法(它都能干什么):其中Handler对象的一些主要方法,如下:
post(Runnable) postAtTime(Runnable,long)
postDelayed(Runnable long)
sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message,long) sendMessageDelayed(Message,long)正如方法名字中看到的,有两类方法:(1)在某个主线程中执行Runnable (2)在子线程中发送一个消息,在主线程中检测该消息处理线程间
传递Message对象的sendMessage方法和发送Runnable 多线程对象的post方法。
正对应着上面所说的两个特性1)、2)下面开发个Handler实例做说明:用post的方法执行一个Runnable对象,在该对象中随机产生一个10~100之间的随机数,赋值到UI主线程中的TextView中线程,执行5次,每次相隔5秒,拼接每次的数字,最后执行结果应该如: 10 22 33 44 61主要代码如下:int i = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(yout.activity_main);
handler.post(run);
} Handler handler = new Handler(){
@Override
public void handleMessage(Message msg){
String s = String.valueOf(msg.what);
TextView tv =
(TextView)findViewById(R.id.textView);
tv.setText(tv.getText() + ” ” + s);
}
}; Runnable run = new Runnable(){
public void run(){
Random r = new Random();
int rnum = r.nextInt((100 – 10) + 1) + 10;
handler.sendEmptyMessage(rnum);
handler.postDelayed(run, 5000);
i++;
if (i==5){
handler.removeCallbacks(run);
}
}
};
Android主线程不能访问网络异常解决办法: 从两个方面说下这个问题:1. 不让访问网络的原因2. 解决该问题的办法不让访问网络的原因:由于对于网络状况的不可预见性,很有可能在网络访问的时候造成阻塞,那么这样一来我们的主线程UI线程就会出现假死的现象,产生很不好的用户体验。
所以,默认的情况下如果直接在主线程中访问就报出了这个异常,名字是NetworkOnMainThreadException解决该问题的办法:1. 独立线程2. 异步线程AsyncTask 3. StrictMode修改默认的策略1) 独立线程的办法启动一个新线程的代码:new Thread(){
public void run() {
Dosomething();
handler.sendEmptyMessage(0);
}
}.start();
此处我们重写了线程类的run方法,执行Dosomething. 在里面还有个handler对象,这又涉及到了跨线程修改UI元素内容的问题。
在java中是不允许跨线程修改UI元素的,如我们在新启动的线程中想去修改UI主线程中TextView的文本时,会报错误的。
如果想做这样的操作,我们就得借助Handler这个类来实现。
关于这个handler类的用法,我们单独的再来写一篇博客进行介绍。
2) 异步调用的方法ASYNCTASK这里关于AsyncTask 介绍的文章不错,详细情况看作者的介绍吧:Click Here 接下来也将会有一篇博客专门介绍关于更新主线程UI线程的所有办法3) STRICTMODE修改默认的策略在我们的Activity类的onCreate方法中,设置如下规则:
StrictMode.ThreadPolicy policy = new
StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
这样也可以解决这个问题关于StrictMode的具体介绍,请看
这个博客介绍的非常详细:。