赞
踩
Android为了线程安全,并不允许我们在UI线程外操作UI;很多时候我们做界面刷新都需要通过Handler来通知UI组件更新!除了用Handler完成界面更新外,还可以使用runOnUiThread()来更新,甚至更高级的事务总线。
当我们的子线程想修改Activity中的UI组件时,我们可以新建一个Handler对象,通过这个对象向主线程发送信息;而我们发送的信息会先到主线程的MessageQueue进行等待,由Looper按先入先出顺序取出,再根据message对象的what属性分发给对应的Handler进行处理。
Handler运行在主线程中(UI线程中), 它与子线程可以通过Message对象来传递数据, 这个时候,Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传弟)Message对象,(里面包含数据) , 把这些消息放入主线程队列中,配合主线程进行更新UI。
- UI线程:就是我们的主线程,系统在创建UI线程的时候会初始化一个Looper对象,同时也会创建一个与其关联的MessageQueue;
- Handler:作用就是发送与处理信息,如果希望Handler正常工作,在当前线程中要有一个Looper对象
- Message:Handler接收与处理的消息对象
- MessageQueue:消息队列,先进先出管理Message,在初始化Looper对象时会创建一个与之关联的MessageQueue;
- Looper:每个线程只能够有一个Looper,管理MessageQueue,不断地从中取出Message分发给对应的Handler处理!
Handler在子线程中:
如果是Handler写在了子线程中的话,我们就需要自己创建一个Looper对象了!创建的流程如下:
1 )直接调用Looper.prepare()方法即可为当前线程创建Looper对象,而它的构造器会创建配套的MessageQueue;
2 )创建Handler对象,重写handleMessage( )方法就可以处理来自于其他线程的信息了! 3 )调用Looper.loop()方法启动Looper
- new Thread(new Runnable() {
- @Override
- public void run() {
- /*
- * handler使用步骤
- *gei threadLocal设置了一个looper对象
- * 在looper的构造方法中,创建了一个messageQueue对象
- * */
- Looper.prepare();
-
- /*在构造方法中获取looper和looper中的messageQueue
- *
- * */
- Handler handler=new Handler(){
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
-
- }
- };
-
- /*奖message发送到messagequeue中,在messageQueue里面,所有的message都是时间为顺序从小到大排列
- *
- * */
- handler.sendEmptyMessage(0);
- /*
- *顺序取出messageQueue中的message
- *并且执行message。target。dispatchMessage();其中的message。target就是发送这个消息的handler
- * 每一条消息都有一定的执行时间,handler会判断时间有没有到,如果没到时间会等待,
- * */
- Looper.loop();
- }
- }).start();
----------handler的使用------
通过Message与Handler进行通信的步骤是:
1. 重写Handler的handleMessage方法,根据Message的what值进行不同的处理操作
2. 创建Message对象
虽然Message的构造函数式public的,我们还可以通过Message.obtain()或Handler.obtainMessage()来获得一个Message对象(Handler.obtainMessage()内部其实调用了Message.obtain())。
3. 设置Message的what值
Message.what是我们自定义的一个Message的识别码,以便于在Handler的handleMessage方法中根据what识别出不同的Message,以便我们做出不同的处理操作。
4. 设置Message的所携带的数据,简单数据可以通过两个int类型的field arg1和arg2来赋值,并可以在handleMessage中读取。
5. 如果Message需要携带复杂的数据,那么可以设置Message的obj字段,obj是Object类型,可以赋予任意类型的数据。或者可以通过调用Message的setData方法赋值Bundle类型的数据,可以通过getData方法获取该Bundle数据。
6. 我们通过Handler.sendMessage(Message)方法将Message传入Handler中让其在handleMessage中对其进行处理。
需要说明的是,如果在handleMessage中 不需要判断Message类型,那么就无须设置Message的what值;而且让Message携带数据也不是必须的,只有在需要的时候才需要让其携带数据;如果确实需要让Message携带数据,应该尽量使用arg1或arg2或两者,能用arg1和arg2解决的话就不要用obj,因为用arg1和arg2更高效。
- Handler handler = new Handler()
- {
- public void handleMessage(android.os.Message msg) {
- switch (msg.what){
- case 1:
- String str= (String) msg.obj;
- reponsedattx.setText(str);
- break;
-
-
- }
- };
- };
//get同步请求---http://ddb.cn/api/VlianbaoCash/deposit public void gettongbuDatasync(){ new Thread(new Runnable() { @Override public void run() { OkHttpClient client = new OkHttpClient();//创建OkHttpClient对象 Request request = new Request.Builder() .url(String.valueOf(test.getText()))//请求接口。如果需要传参拼接到接口后面。 .build();//创建Request 对象 Response response=null; try { response = client.newCall(request).execute();//得到Response 对象 Log.e("kwwl","get同步res=="+response.body().string()); String resstr=response.body().string(); Message msg=new Message(); //虽然Message的构造函数式public的,我们也可以通过以下两种方式通过循环对象获取Message //msg = Message.obtain(uiHandler); //msg = uiHandler.obtainMessage(); //what是我们自定义的一个Message的识别码,以便于在Handler的handleMessage方法中根据what识别 //出不同的Message,以便我们做出不同的处理操作 msg.what = 1; //我们可以通过arg1和arg2给Message传入简单的数据 msg.arg2 = 321; msg.obj="jjjj"; //我们也可以通过给obj赋值Object类型传递向Message传入任意数据 //msg.obj = null; //我们还可以通过setData方法和getData方法向Message中写入和读取Bundle类型的数据 //msg.setData(null); //Bundle data = msg.getData(); //将该Message发送给对应的Handler***** handler.sendMessage(msg); } catch (IOException e) { e.printStackTrace(); } } }).start(); }
-------回到主线程更新UI的四种方法,参考:https://blog.csdn.net/mislaydu/article/details/51776247
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。