位置: 编程技术 - 正文

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(表格布局)

  • 以前年度多缴纳的企业所得税退还
  • 外经证错了已经交了税怎么办
  • 住宿费电子发票样式
  • 经营利润和营业利润的区别
  • 计税金额是含税还是不含税
  • 贷款已支付属于什么会计科目
  • 油卡充值属于什么行业
  • 销售房地产要交培训费是传销行为吗
  • 企业账面库存过大应怎样处理好
  • 代付租金委托书怎么写
  • 完成产值怎么算
  • 出口退免税的基本政策包括
  • 王者荣耀电脑版怎么键盘操作
  • php邮箱发送
  • 网速变慢了
  • 固定资产残料收入的账务处理
  • 房产契税如何计算2021年
  • PHP:pg_get_pid()的用法_PostgreSQL函数
  • PHP函数func_num_args用法实例分析
  • 销售已使用固定资产收入与主营收入合计超过120万元
  • threejs loader
  • yolov5 教程
  • php运用的技术php开发有哪些实用的技术
  • phpcrawl
  • 税控盘干嘛用
  • 已确认的发票如何入账
  • 企业所得税申报表A类
  • 固定资产备案有什么用
  • 员工预支款计入什么科目
  • vue笔记大全
  • 租赁业务成本
  • 给股东分配股利
  • wordpress提示插件
  • okhttp3源码分析
  • dedecms5.7
  • 公司广告费用咨询费都应当作为管理费用对还是错
  • 递延所得税怎么计算
  • 福利用品可以抵增值税吗
  • 管理费用增加是因为什么
  • 增值是什么意思解释
  • 企业资产总额包括应收账款吗
  • 小公司没有财务软件怎么手工记账
  • 固定资产的更新改造支出计入什么科目
  • 纸质汇票什么时候能到账
  • 技术服务收入包括哪些
  • 只有进项要交税吗
  • 企业增值税额
  • 加班餐费报销计入什么费用
  • 管理不善造成的存货盘亏损失计入什么科目
  • 申报高新技术企业专利有什么要求
  • 天猫佣金是啥
  • 出租办公楼收入属于收入吗
  • 摊余成本通俗
  • 检查mysql是否正常
  • 透明数据网
  • centos6.1安装
  • mysql视图语句
  • mysql主从复制原理详解
  • mysql更新表中的数据
  • macbook和windows
  • windows u盘制作
  • wav文件属于什么文件
  • xp桌面底部任务在右边
  • linux acl设置
  • linux root用户登陆
  • linux ftp搭建教程
  • linux 使用
  • js unload
  • 批处理执行bat文件
  • python如何用
  • PreferenceActivity、PreferenceFragment使用
  • javascript如何学
  • 屏幕模式自适应模式
  • javascript编程语言
  • jquery判断数据类型
  • android获取手机的基本信息
  • 企业招用退役士兵
  • 江苏省发展改革委
  • 税务文书保存期限分几类
  • 政府发放奖金给企业怎么入账
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

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

    友情链接: 武汉网站建设