小知识 安卓线程和ui

1. 定时更新ui

通常需要一些类似定时更新ui的代码,如动画控制。

1.1多线程定时更改ui

具体就是新启动(不让ui线程sleep而卡住)一个线程去计时,之后定时来通知ui修改。

1.1.1新启动线程定时执行任务

  • Timer + TimerTask
  • 新启动线程:run方法中:while(true) + Thread.Sleep/SystemClock.Sleep

  本质上都是一个新线程在背后计时。由于使用一个新的非ui线程执行计时,需要在时间到达后去通知ui修改。出于性能考虑,安卓的ui控件不是线程安全的,然后谷歌设计只让ui线程(主线程)能够直接修改ui控件,其它非ui线程不能来达到ui的线程安全。

1.1.2非ui线程更新ui控件的方式

  • runOnUiThread
  • Handler
  • View.postDelay

  runOnUiThread从名字上可以看出就是专门供其它线程更改ui使用的。而handler用于不同线程之间的消息传递,可以让线程T1在希望的时刻去通知T2执行某些特定操作。这当然也完全能满足[非ui线程定时通知ui线程更改ui控件状态] 的目的。

1.2 Handler定时更新ui

  如果只是为了完成“定时执行”,那么不开启一个新线程,使用handler.sendEmptyMessageDelayed(1,2000)也可以。

  在开始定时任务执行的地方调用:

handler.sendEmptyMessage();

  主线程中的handler重写handleMessage:

final int UPDATE_ANIM = 1001;

boolean isAnimFinish;

Handler handler = new Handler(){

@Override

public void handleMessage(Message msg) {

switch (msg.what) {

case UPDATE_ANIM:

if(!isAnimFinish){

//更新ui的代码,代码中根据情况改变isAnimFinish标志。

handler.sendEmptyMessageDelayed(UPDATE_ANIM, 2000);

}

break;

}

}

};

  可见,开启新的线程一般是执行一些非ui但耗时的操作,比如网络获取新闻数据。而定时任务这样的事情Handler也可以搞定。

2.Handler的跨线程通信

2.1原理描述

  为了让其它线程发消息通知当前线程执行一些任务,当前线程线程可以这样做:

  • 当前线程提供一个唯一的MessageQueue,用来接收其它线程丢进来的Message。MessageQueue使用先进先出的时间顺序维护所有消息。
  • 当前线程提供一个唯一的Looper来管理它的MessageQueue,主要就是不断的(loop)从中取走Message,然后发送给把此Message丢进队列的Handler对象去处理。
  • 当前线程可以创建一或多个Handler对象。假设handler_1按需求重写其public void handleMessage(Message msg)方法。当Looper从MessageQueue中取得一个调用handler_1的sendMessage方法发送的Message后,就调用handler_1的handleMessage来处理此Message。

  LooperMessageQueue都是线程唯一的,当然没有多个的必要——除了增加麻烦。

  • 其它线程可以根据需要封装一个Message对象,调用handler_1的sendMessage, 这样handler_1把Message发送到自己线程所对应的MessageQueue中,很快此Message被所在线程的Looper监测到,取走,发送给handler_1去处理。

  通过以上Looper、MessageQueue、Handler的合作,每一个线程都通过Handler来让其它线程根据需要通知自己执行一些操作。

  Handler可以实现不同线程之间的通信,默认主线程已经提供好了Looper和MessageQueue,所以按需要自己写个handler对象,就可以在新开启的其它线程中使用handler来让主线程执行操作,常见的就是更新ui控件。

  Handler在哪个线程中创建,就和哪个线程的Looper、MessageQueue对应起来。

2.2 让自己的线程开始接收消息

  其它线程默认Looper和MessageQueue是没有准备好的,可以在run方法里通过以下几步配置好:

  • 调用Looper.prepare()方法,这会建立Looper实例和对应的MessageQueue。
  • 设计好自己的Handler对象,主要是处理消息,之后供外界用它来想MessageQueue发送消息。
  • 最好调用Looper.loop()方法开启Looper对消息队列的监测。表示可以让其它线程来发送通知了。

2.3 Toast.show的调用

  本质上对ui控件的修改,最终都是ui线程执行的。比如我们的线程里需要设置某个TextView的Text属性,那么只能是使用ui线程的handler去发送消息给ui线程去执行。或者使用runOnUiThread这样的简便方法。

  一个特殊的例子就是Toast.show,我们可以在自己线程的handler的handleMessage方法中去调用。但也仅限handleMessage中,Toast.show需要当前线程有Looper和Handler,它最终也是辗转到ui线程中执行了。

3.多线程更新ListView

  另一个常见“跨线程改变ui”的例子就是网络数据加载,比如加载新闻列表到ListView,启动新的线程是为了避免主线程阻塞而卡ui。

  相比启动一个线程去达到计时器的目的,使用非ui线程去执行耗时操作等就划算得多了。一般的套路是:

  • 界面上需要新的数据时,启动一个线程去从网络或本地获取一批数据,通常是分页获得一个合理的数据集合。界面上显示进度条,并且使得一部分界面不可交互。
  • 获取数据完毕后,调用adapter的notifyDataSetChanged(),它是一个ui操作,需要使用“非ui线程执行ui操作”的技巧去完成。

   ListAdapter的要点就是:复用屏幕不可见的View对象,并且使用ViewHolder来避免findViewById的开销。

4.AsyncTask

  没什么可说的,非常典型的开启线程完成耗时任务,之后更新Ui,几乎大多数场景都可以用它来快速实现功能。

  大致就是:

  • onPreExecute中执行ui操作,显示进度条。
  • doInBackground中执行耗时任务,调用publishProgress来更新进度。
  • onPostExecute中使用结果数据,dismiss掉进度条。

  应该在ui线程中创建AsyncTask的实例,并调用其execute方法。

时间: 2024-11-03 21:50:34

小知识 安卓线程和ui的相关文章

UI设计师不可不知的安卓屏幕知识-安卓100分享

http://www.android100.org/html/201505/24/149342.html UI设计师不可不知的安卓屏幕知识-安卓100分享 不少设计师和工程师都被安卓设备纷繁的屏幕搞得晕头转向,我既做UI设计,也做一部分安卓界面布局,刚好对这块内容比较熟悉,也曾在公司内部做过相关的讲座,在此,我将此部分知识重新梳理出来分享给大家!... 分享到:QQ空间微博 为了方便网友浏览,本站具有屏幕自适应功能,在手机等设备上任然具有最优的浏览体验,横竖屏无缝切换. 公告:欢迎来到安卓100

UI 控件小知识

>在storyboard 中添加控件 UIimageview 中 是不能拖进任何控件,但是手动代码可以 >在BUtton 中 添加图片: 如果不想改变图片的拉伸,就在image中添加,如果在backbround 中添加,图片会随着按钮的frame被拉伸:填充小图片用image,大图片 用background: >若果需要为 TextField 添加图片,需要在BorderStyle中 选中 没有形状的: >在tableview.backgroundColor 和tableView.

安卓 异步线程更新Ui

异步跟新UI: 1.handler+Thread(runnable):如果handler和Thread都写在了一个Java文件中,就不说了,如果runnable定义在了一个单独的类文件中,可以通过在构造方法里接收handler参数,然后执行完耗时操作后,通过handler发送消息来通知主UI线程更新UI 2.接口回调,定义一个接口,然后在主UI执行耗时操作的时候,借助匿名内部类,在这里写异步线程返回来的数据处理操作,异步线程接收一个匿名的内部类实例,然后在执行完耗时操作后回调接口的方法,可以把耗

面试过程中,你知道这些小知识,将事半功倍

在平时我们面试的过程总总会遇到一些面试官问一些平时我们不怎么注意的问题,当问出来的时候,面试者通常都是一脸懵逼,这和我想象中的不一样阿,怎么不按照套路出牌,当然一些小知识更能体现出你的细心和好学,以下分析20个面试中的小知识,共勉~.·整理的这份PDF有从基础到进阶.含有BATJ.字节跳动面试专题,算法专题,高端技术专题,混合开发专题,java面试专题,Android,Java小知识,到性能优化.线程.View.OpenCV.NDK等应有尽有.还有辅之相关的视频+学习笔记 (更多完整项目下载.未

.NET设计篇08-线程统一取消模型和跨线程访问UI

知识需要不断积累.总结和沉淀,思考和写作是成长的催化剂,输出倒逼输入 内容目录 一.线程统一取消模型1.取消令牌2.可以中断的线程1.设计一个中断函数2.创建CancellationTokenSource对象3.启动线程4.取消线程执行二.跨线程访问UI基本方法1.Control.Invoke和BeginInvoke2.桌面退出3.编写线程安全的控件三.BackgroundWorker组件1.干活的代码2.启动任务3.结果取回4.取消任务5.进度报告四.等等 一.线程统一取消模型 线程取消在多线

.NET设计篇08-线程取消模型和跨线程访问UI

知识需要不断积累.总结和沉淀,思考和写作是成长的催化剂,输出倒逼输入 内容目录 一.线程统一取消模型1.取消令牌2.可以中断的线程1.设计一个中断函数2.创建CancellationTokenSource对象3.启动线程4.取消线程执行二.跨线程访问UI基本方法1.Control.Invoke和BeginInvoke2.桌面退出3.编写线程安全的控件三.BackgroundWorker组件1.干活的代码2.启动任务3.结果取回4.取消任务5.进度报告四.等等 一.线程统一取消模型 线程取消在多线

Android 48个小知识

1.判断sd卡是否存在 boolean sdCardExist = Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED); 2.TextView部分文字设置颜色 TextView tv = new TextView(this); //添加css样式 tv.setText(Html.fromHtml("<font color="#ff0000">红色<

安卓线程相关 HandlerThread Handler Thread Looper Message Runnable

本文由PurpleSword(jzj1993)原创,转载请注明 原文网址 http://blog.csdn.net/jzj1993 安卓主线程(UI线程)是线程不安全的:对UI控件的操作都应在主线程中完成:UI线程不应执行耗时操作,以免程序不响应(即ANR异常) 实现新线程的常用方法(注意要调用start方法启动新线程而不是run方法): 一.定义类,实现Runnable接口 class MyRunnable implements Runnable { /** * 实现接口的run方法 */ @

iOS子线程操作UI问题检查

iOS开发中,因为大部分函数都不是线程安全的,所以UI子线程中操作UI是非常危险的事,但是有时候因为开发者经验不足,不知道子线程中不能UI,或者知道但是写代码的时候没注意,或者不知道那些函数操作UI了(比如UITableView的reload函数),造成这个问题时常发生,防不胜防,而且iOS不像安卓,一旦子线程中操作UI就直接崩溃,iOS中操作UI只是有可能崩,导致问题经常不好重现,而且经常奔溃堆栈是乱的,找不到出错的地方在哪儿,十分头疼. 本人写了一个简单的线程检查ui操作的库,当子线程操作u