Android(java)学习笔记202:Handler消息机制的原理和实现
2015-08-30 10:40
831 查看
联合学习 Android(java)学习笔记149:AsyncTask(异步任务)和Handler(消息机制)
1. 首先我们通过一个实例案例来引出一个异常:
(1)布局文件activity_main.xml:
(2)MainActivity.java:
(3)布署程序到模拟器上,出现如下效果,程序直接stop;并且直接报出异常错误:
报错:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
意思:从错误线程调用的异常。谁创建的view,谁才能修改编辑view,只有主线程才可以修改view(所有的View都是主线程创建的)。
总结:上面报这个CalledFromWrongThreadException错误,是因为只有主线程才能修改View更新UI,但是我们这里却自己新建一个线程new Thread()其中run()的内容涉及到更新UI,这是不允许的,所有才会出现这样的错误警告。
但是往往我们编写程序的时候设计多个线程需要控制UI显示,但是我们上面已经说过了UI更新只能交给主线程,为了解决这个矛盾,解放程序员,google开发出来消息机制,用来子线程和主线程通信,子线程要更新UI,就会发送消息数据给主线程,这样主线程就会更新相应的UI界面,从而解决这个矛盾。
2. 消息机制的原理和实现
消息机制实现逻辑图:
这里handler负责把外面的子线程的消息发到message queue消息队列之中,然后looper不停监听[b]message queue里面是不是有消息,如果有的话,looper就把消息发送到handler,交给handler的handlemessage根据信息,更新UI。[/b]
使用消息机制目的:
Android系统的主线程安全的系统,别的线程不可以修改ui线程的界面,如果子线程里面想要更新UI,就必须采用消息机制处理。
使用handler消息处理器编写代码步骤:
(1)在主线程里面声明消息处理器handler;
(2)子线程想要更新UI,利用消息机制
(3)系统内部有消息队列message queue和消息looper,轮询到消息,交给handler去处理:
(4)重写handler的方法处理消息:
接下来我们就修改上面的案例,就更好理解这个消息机制:
MainActivity.java:
acitivity_main.xml:
1. 首先我们通过一个实例案例来引出一个异常:
(1)布局文件activity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <TextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:text="@string/hello_world" /> </RelativeLayout>
(2)MainActivity.java:
package com.itheima.testthread; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.widget.EditText; import android.widget.TextView; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); System.out.println(Thread.currentThread().getName()); final TextView tv = (TextView) findViewById(R.id.tv); new Thread() { public void run() { for (int i = 0; i < 100; i++) { tv.setText("哈哈哈"+i); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } }; }.start(); } }
(3)布署程序到模拟器上,出现如下效果,程序直接stop;并且直接报出异常错误:
报错:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
意思:从错误线程调用的异常。谁创建的view,谁才能修改编辑view,只有主线程才可以修改view(所有的View都是主线程创建的)。
总结:上面报这个CalledFromWrongThreadException错误,是因为只有主线程才能修改View更新UI,但是我们这里却自己新建一个线程new Thread()其中run()的内容涉及到更新UI,这是不允许的,所有才会出现这样的错误警告。
但是往往我们编写程序的时候设计多个线程需要控制UI显示,但是我们上面已经说过了UI更新只能交给主线程,为了解决这个矛盾,解放程序员,google开发出来消息机制,用来子线程和主线程通信,子线程要更新UI,就会发送消息数据给主线程,这样主线程就会更新相应的UI界面,从而解决这个矛盾。
2. 消息机制的原理和实现
消息机制实现逻辑图:
这里handler负责把外面的子线程的消息发到message queue消息队列之中,然后looper不停监听[b]message queue里面是不是有消息,如果有的话,looper就把消息发送到handler,交给handler的handlemessage根据信息,更新UI。[/b]
使用消息机制目的:
Android系统的主线程安全的系统,别的线程不可以修改ui线程的界面,如果子线程里面想要更新UI,就必须采用消息机制处理。
使用handler消息处理器编写代码步骤:
(1)在主线程里面声明消息处理器handler;
private Handler handler = new Handler() { };
(2)子线程想要更新UI,利用消息机制
Message msg = new Message(); msg.what 消息类型 msg.obj 具体消息携带的数据 handler.sendMessage(msg);
(3)系统内部有消息队列message queue和消息looper,轮询到消息,交给handler去处理:
(4)重写handler的方法处理消息:
public void handleMessage (Message msg) { //运行在主线程,更新UI };
接下来我们就修改上面的案例,就更好理解这个消息机制:
MainActivity.java:
package com.itheima.testthread; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.widget.EditText; import android.widget.TextView; public class MainActivity extends Activity { private TextView tv; private Handler handler = new Handler() { public void handleMessage(Message msg) { // 运行在主线程,更新ui String str = (String) msg.obj; tv.setText(str); EditText et; }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); System.out.println(Thread.currentThread().getName()); tv = (TextView) findViewById(R.id.tv); new Thread() { public void run() { for (int i = 0; i < 100; i++) { // tv.setText("哈哈哈"+i); Message msg = new Message(); msg.obj = "哈哈哈" + i; handler.sendMessage(msg); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } }; }.start(); } }
acitivity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:text="@string/hello_world" /> </RelativeLayout>
相关文章推荐
- Android基础知识巩固:关于PendingIntent和广播
- android 应用自动更新
- Android中Unable to execute dex: Multiple dex files define Lcom/viewpagerindicator/CirclePageIndicat
- Android 开发 AutoCompleteTextView结合自定义的适配器,查询数据库
- Android 技巧
- 导入导出Android手机文件
- 学习笔记——Android创建应用程序和活动
- android自定义时间选择器
- Android资源管理框架(Asset Manager)简要介绍和学习计划
- Android中TimePickerDialog的使用
- 从零开始学Android之监听器实现监听动作的三种方式(匿名内部类,独立类,接口方式)
- android studio中配置opencv问题
- android 状态栏沉浸
- 获取资源ID失败--android使用友盟第三方登陆错误解决
- Android之——自定义下拉菜单的实现
- Android进阶之大话设计模式
- Android基础整理(一)
- Android中的DatePickerDiaolog的使用
- Android的JSON数据解析
- ubuntu14.10上编译Android5.0.2源码