位置: 编程技术 - 正文

android中Handler学习心得(安卓handler使用)

编辑:rootadmin

推荐整理分享android中Handler学习心得(安卓handler使用),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:android handler用法,android handle原理,android handle原理,安卓中handler作用,android中handler机制,android中handler机制,android handler用法,android handler用法,内容如对您有帮助,希望把文章链接给更多的朋友!

在android开发中,Handler消息发送和处理几乎无处不在。稍微复杂一点的Activity,需要运行时更新UI一般都会使用Handler,特别是在非UI线程中更新UI必须使用Handler(除了极个别View可以在线程中更新)发送消息,然后在Handler.handleMessage()中接收到,处理消息更新UI。Activity.runOnUiThread()也是可以更新UI,其实也是间接使用了handler的。

如果一不小心,在非UI线程中直接更新UI会抛出异常,程序直接关闭,错误消息如下:

- ::.: E/AndroidRuntime(): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

一般在Activity中申明一个handler对象,然后在异步处理的地方使用该handler.sendMessage()一个消息,然后在handler的handleMessage方法里进行判断处理。

Handler里有很多发送消息的方法,可以实现各种需求:

sendMessage(Message msg)

sendEmptyMessage(int what)

sendEmptyMessageDelayed(int what, long delayMillis)

sendEmptyMessageAtTime(int what, long uptimeMillis)

sendMessageDelayed(Message msg, long delayMillis)

sendMessageAtFrontOfQueue(Message msg)

sendMessageAtTime(Message msg, long uptimeMillis)

通过以上的方法发送的消息,可以在msg.callback方法中更新UI,或 handleMessage(Message)中接收到,然后可以更新UI。

post(Runnable r)

postAtTime(Runnable r, long uptimeMillis)

postAtTime(Runnable r, Object token, long uptimeMillis)

postDelayed(Runnable r, long delayMillis)

postAtFrontOfQueue(Runnable r)

通过以上方法可以传递一个实现了Runnable接口的对象,在该对象的run()方法里可以更新UI。

通过关联的源代码,可以发现,Handler有构造方法如下:

public Handler(Looper looper, Callback callback, boolean async) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; }

若传入了looper对象,会调用该构造方法。

可以看出Handler收发消息需要借助这两个对象:Looper,MessageQueue;asynchronous是否是异步接收消息,该方法的注释可以大致知道,使用默认的Looper来handleMessage将不会是异步的,所以是false,Callback接口里面只有一个方法,其实就是handleMessage()处理消息的回调函数,为null时,直接使用Handler自身的handleMessage()方法。

当在申明handler的时候根本没有传入Looper?

在另外的一个构造方法中源码如下:

mLooper = Looper.myLooper(); if (mLooper == null) {

throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async;

若没有传looper,直接使用Looper.myLooper()获取,即返回的是Looper中sThreadLocal变量中的looper;在Activity启动时,默认会创建一个looper,在ActivityThread类里面有申明的 final Looper mLooper = Looper.myLooper(),在Activity.attach(....)方法中可以看到ActivityThread对象被传入。如果在UI线程中申明Handler,默认用到的就是这个mLooper。

先来看看消息是怎么发送的?大致理解:

通过handler的构造函数 知道了有个MessageQueue,字面意思知道里面放的全是Message了,看源码本来就是。mQueue就是在Looper里面维护,是在Looper的构造方法中new出来的,源码如下:

private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread();}

android中Handler学习心得(安卓handler使用)

该构造方法是私有构造,只有Looper自身才能调用,当外界调用prepare()方法时,间接的去new Looper(),并放入到sThreadLocal中:

public static void prepare() { prepare(true);}

private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed));}

new时需要传入一个boolean类型的参数quitAllowed,参数主要用于new MessageQueue(quitAllowed),字面意思是允许退出,默认传入的是true,当调用

public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } }

上面方法传入的是false。理解为当UI线程(mainThread)开启Looper时传入的是false,其他子线程传入的true。

上面那么多发送消息的方法,最后都会调用到sendMessageAtTime()方法,源码如下:

public boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this &#; " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, uptimeMillis);}

接着调用了enqueueMessage()方法,源码如下:

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis);}

可以看到msg.target=this,消息里还保存了Handler对象的引用。 通过MessageQueue.enqueueMessage()最终把要发送的消息放入队列中,等待发送。

接着看看消息是怎么接收的?

Looper是什么,MessageQueue又是什么?通过看源码可以大致理解:

Looper就是不断的到MessageQueue拿Message然后dispatchMessage到handleMessage();源码如下:

public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; // Make sure the identity of this thread is that of the local process, // and keep track of what that identity token actually is. Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } // This must be in a local variable, in case a UI event sets the logger Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " &#; msg.target &#; " " &#; msg.callback &#; ": " &#; msg.what); } msg.target.dispatchMessage(msg);

…………

…………

}

首先拿到当前线程的Looper对象me,然后拿到MessageQueue对象queue=me.mQueue,再然后就是for循环了,不断的拿Message msg = queue.next(); 然后就是msg.target.dispatchMessage(msg)分发消息,上面说了msg.target就是handler,又回到了handler对象中了; dispatchMessage(Message msg)方法源码如下:

public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }

优先使用msg.callback,其次是构造方法传过来mCallback,最后才使用自身的handleMessage。此时正在更新UI。

通过上面知道,若要在子线程中要申明一个handler对象,并要收发消息,有两种方式:第一种:在run()方法中,先要调用Looper.prepare()方法(间接的new Looper(),间接的new MessageQueue()),接着不停的sendMessage,最后必须调用Looper.loop(),才能把消息拿出并dispatchMessage。第二种:在申明handler的时候把UI线程中的Looper对象传入,不需重新创建新的Looper及MessageQueue对象,例如:Handler handler = new Handler(Looper.getMainLooper()){public void handleMessage(Message msg){//handle message}};或Handler handler = new Handler(Looper.getMainLooper(),new Handler.Callback() {@Overridepublic boolean handleMessage(Message msg) {//handle messagereturn false;}});

这种方式不需要再调用prepare和loop了,直接发消息就可以了。原因是:调用prepare就是用来new Looper()和new MessageQueue(),而现在已经传入了一个looper自然不需要再new了;调用loop主要用于开启消息循环不断到MessageQueue拿消息的,现在传入的是MainThread的mLooper,上面有说到在创建MainThread的looper时传入的boolean型变量是false即该looper对象中的mQueue不允许退出,猜测loop一直在执行中即使mQueue中没有消息也不会退出,当有消息发送过来时就拿出来并dispatchMessage。

MessageQueue 中的quit方法源码如下:

void quit(boolean safe) { if (!mQuitAllowed) { throw new IllegalStateException("Main thread not allowed to quit."); }

……

……

}

至于该方法在哪里调用还没弄明白,而且关于Handler还有很细节问题没搞清楚,有待提高。

Android UI之TableLayout(表格布局) 说明:表格布局采用常见的表格方式来表示布局,与上文中提到的android:weight属性显示出来的效果有些相似。而事实上,TableLayout的确是LinearLayout的子类

asm/semaphore.h: No such file or directory 当我进行内核hook的时候,包含的#includeasm/semaphore.h头文件,编译的时候系统提示找不到这个文件或者目录,然后去谷歌搜的,上面说这个头文件已经被

Android学习 - Android新的menu实现ActionMode Android的menu有多种实现方式,这里介绍一种新的menu实现方式:ActionMode。ActionMode是Android3.0以后出现的,我们可以使用AppCompat库使ActionMode兼容至Android2.1。

标签: 安卓handler使用

本文链接地址:https://www.jiuchutong.com/biancheng/378169.html 转载请保留说明!

上一篇:Android roboguice 开源框架使用

下一篇:Android UI之TableLayout(表格布局)

  • 无形资产多摊销了怎么办
  • 销售折扣怎么开
  • 对方公司注销用现金还货款怎么入帐?
  • 建筑清包工的账务处理
  • 结余资金财政收回如何做账
  • 认证过的进项税怎么记账
  • 一般纳税人进项税额转出会计分录
  • 促销服务费能抵增值税吗
  • 红字发票冲红步骤
  • 研发费用报表列报
  • 子公司评估增值 出售股权
  • 企业取得固定资产的方式有哪些
  • 会计成本核算的三种基本方法
  • 投资利税率计算器在线计算
  • 股份支付的会计处理?
  • 企业所得税法的主要内容
  • 暂估入库有时间限制吗
  • 收到场地租赁费入什么科目
  • 合并报表六大抵消分录通俗理解
  • 出口发票汇率按照报关单什么时间计算
  • win11如何设置定时关机
  • 公司购买空调计入什么费用
  • 关闭开机自动启动
  • 操作系统的文件系统管理主要负责
  • PHP:curl_getinfo()的用法_cURL函数
  • neoDVD.exe - neoDVD是什么进程 有什么用
  • 如何做世界上最小的遥控飞机
  • PHP:imagecreatefromgif()的用法_GD库图像处理函数
  • 穆尔官网
  • 如何快速搭建前端界面
  • 已提足折旧固定资产改建支出 所得税怎么计算
  • phpsubstr方法参数
  • 会计等式反映了六大会计要素的恒等关系
  • 前端项目实战教程
  • php密码加密技术phpass
  • php读取文件内容的方法和函数
  • 个税申报结果查询
  • 公允价值变动收益借方是增加还是减少
  • 农民工工资专用账户
  • 借贷公司借钱给别的公司需要开什么会
  • cookie 会话
  • mongodb主从同步速度
  • 保洁公司的税率是多少
  • 公司购买食品怎么入账
  • 异地预缴税款怎么做账
  • 购买花卉
  • 代收代缴的水电费怎么开票
  • 给客户的回扣怎么表达
  • 疫情期间公司购买物品
  • 印花税为什么不用计提
  • 复式记账法的特点不包括
  • 管理费怎么扣除
  • 会计的主要目标是提供什么和什么
  • mysql触发事件
  • sql实现选择操作
  • wind怎么申请
  • Windows Server 2008的节能降耗
  • win10周年更新版是什么意思
  • win7切换输入法的快捷键怎么设置
  • linux禁止root用户远程登录
  • gnu grub卸载
  • win8.1如何更新到win10
  • 铁嘴大师
  • 代码的历史
  • shell脚本命令行参数
  • Python连接access数据库
  • linux 加法命令
  • disk指令
  • dirsearch批量
  • jQuery实现checkbox列表的全选、反选功能
  • shell脚本进程号
  • shell监控http脚本
  • New AssetBundle build system in Unity 5.0
  • android布局背景颜色的代码
  • html5 jquery
  • 猫猫的娱乐
  • java教程 视
  • python网络爬虫总结
  • 车船税保险公司代收代缴后,单位还申报不?
  • 阁楼交取暖费吗合法吗
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设