Java Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
Android进阶——Handler的应用之解决Only the original thread that created a view hierarchy can touch its views
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 为什么会有这种异常产生呢? 当每个应用程序apk第一次启动时,Android会同时启动一个对应的主线程(Main Thread), 主线程负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件, 并把相关的事件分发到对应的组件进行处理,所以主线程通常又被叫做UI线程。 但是在开发Android应用时必须遵守单线程模型的原则: Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行,如果在非UI线程中直接操作UI线程, 会抛出android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views, 这与普通的java程序不同。 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 由于UI线程负责事件的监听和绘图,因此,必须保证UI线程能够随时响应用户的需求, UI线程里的操作应该向中断事件那样短小,费时的操作(如网络连接)需要另开线程, 否则,如果UI线程超过5s没有响应用户请求,会弹出对话框提醒用户终止应用程序(ANP)。 如果在新开的线程中需要对UI进行设定,就可能违反单线程模型, 因此android采用一种的Message Queue机制保证线程间通信。 Message Queue是一个消息队列,用来存放通过Handler发送的消息。 Android在第一启动程序时会默认会为UI thread创建一个关联的消息队列, 可以通过Looper.myQueue()得到当前线程的消息队列,用来管理程序的一些上层组件, activities,broadcast receivers 等,你可以在自己的子线程中创建Handler与UI thread通讯。 Handler会向message queue通过两种方法发送消息:send或post。 这两种消息都会插在message queue队尾并按先进先出执行, 但通过这两种方法发送的消息执行的方式略有不同: 1)通过send发送的是一个message对象, 会被handler的 handleMessage()函数处理; 2)而通过post方法发送的是一个runnable对象,则会自己执行。 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Android系统中的视图组件并不是线程安全的,如果要更新视图,必须在主线程中更新,不可以在子线程中执行更新的操作。 既然这样,我们就在子线程中通知主线程,让主线程做更新操作吧。那么,我们如何通知主线程呢?
我们需要使用到Handler对象。 代码如下:
Java Code
|