Android_Handler
来源:互联网 发布:南航网络教学平台 编辑:程序博客网 时间:2024/06/06 04:28
Android_Handler
今天无意间翻出来从前有关Handler的笔记,突然感觉到有点懵逼,不过现在明白了,还是记录下来,防止以后再次遇见这种情况,同时跟大家分享一下,如果有什么错误的,请各位大神指正。以下的都是本人的理解,希望指正。谢谢。
我想在开始今天的学习之前先跟大家讲一下有关线程的知识。
线程
线程有主次之分,每个正在执行的程序都存在主线程,可能存在若干个分支线程(子线程)
当正在执行的程序存在多个线程时,表现为多个线程同时工作
当正在执行的程序存在多个线程时,这些线程会交替运行,交替的间隔时间和每次每个线程的执行时间都是不可以确定的
创建线程的方法:
1) 自定义类继承java.lang.Thread类,并重写public void run()方法,当需要启动线程时,初始化该线程类的对象,并调用start()方法开启线程
2) 自定义类实现java.lang.Runnable接口,并重写抽象的public void run()方法,当需要启动线程时,初始化Thread类的对象,并在创建对象时使用自定义的Runnable实现类对象作为其构造方法的参数,最后,调用Thread类对象的start()方法开启线程
线程控制
Thread.sleep()方法可以让线程休眠,即多少毫秒之内不会工作
ANDROID的UI线程模型
UI:User Interface,即:(软件与)用户(的)接口
在ANDROID系统中,主线程也叫作UI线程
所有的显示控件的初始化都是在主线程中运行的,ANDROID系统约定:只有创建控件的线程(主线程)才可以控制这些控件!即:子线程不允许控制各个控件
我们在编写Android应用程序的时候,有的Activity中不仅仅只有一个主线程在执行操作,像一些网路请求这种耗时操作,我们应该交给子线程去执行,如果不交给子线程去执行那么你就会遇见 ANR错误。
ANR错误
ANR(Application Not Respoding)表示“应用程序没有响应”,出现该错误的原因在于执行时间过长,例如Activity的执行时间超过5s,或者广播接收者的执行时间超过10s
以上错误的出现原因针对主线程,子线程的执行时间不受限制
既然我们已经知道了在Android中需要用到子线程去执行一些耗时操作,那么问题来了,子线程只能去执行操作,但是不能更改UI,那么主线程和子线程是如何通信的呢?这就需要我们学习今天的知识 Handler机制。我们在学习Handler机制之前需要有以下知识做铺垫。
1、Message
Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据。通常我们会使用到的几个属性:message.what->用于标识是哪一个线程发送出来的message。what属性的值应该使用静态常量表示。message.arg1和arg2->用于携带 int值,message.obj携带的是一个Object对象。
2、Handler
Handler主要是用于发送和处理消息的。发送消息一般是使用Handler的sendMessage()方法,而发出的消息经过一系列的辗转处理后,追中会传到Handler的handlerMessage()方法中。
3、MessageQueue
MessageQueue是消息队列的意思,它主要用于存放所有通过Handler发动的消息。这部分消息会一直存在于消息队列中,等待被处理。每个线程中只会有一个MessageQueue对象。
4、Looper
Loop是每个线程中的MessageQueue的管家,调用Looper的loop()方法后,就会进入到一个无限循环当中,饭后每当发现MessageQueue中存在一条消息,就会将它取出来,并传递到Handler的handlerMessage()方法中。每个线程中也只会有一个Looper对象。
为了让大家能够更好的理解Handler消息机制的工作原理,请看下图:
通过以上的知识了解,相信大家对Handler消息机制大概有了一定的了解,那么我们就来实践一下吧。以下的例子我是使用了一个Clock例子,该例子就是启动程序,主界面上实时显示当前的时间。
1、我的MainActivity所对应的activity_main.xml布局文件很简单就只有一个TextView控件,代码如下:
<?xml version="1.0" encoding="utf-8"?><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="com.example.clockthreadtest.MainActivity"> <TextView android:id="@+id/tv_Clock" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:text="Hello World!" android:textSize="32sp" /></RelativeLayout>
2、我在MainActivity中使用了大家平时都使用的Handler机制来发送消息和处理消息,代码很基础,我就不解释了。
public class MainActivity extends Activity { private TextView tvClock; private Handler handler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); tvClock = (TextView) findViewById(R.id.tv_Clock); handler =new InnerHandler(); new InnerThread().start(); } class InnerHandler extends Handler { @Override public void handleMessage(Message msg) { String data= (String) msg.obj; tvClock.setText(data); } } class InnerThread extends Thread { @Override public void run() { for (int i = 0; i < 1200; i++) { Message message =new Message(); message.obj =new Date().toString(); handler.sendMessage(message); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }}
其实对于Handler机制,要是按照上面的写法完全没有什么错误,但是Handler其实还有其他的写法,就让我们来了解一下,开阔一下视野吧。
使用Message.obtain创建message
我新建了一个Activity名叫ClockActivityTest,它的布局文件的代码和activity_main代码相同,让我们来看一下ClockActivityTest的代码吧:
对了,要记着在AndroidManifest.xml文件中将ClockActivityTest设置为启动界面。
public class ClockActivity extends Activity { private TextView tvClock; private static final int UPDATA_MESSAGE_TIME = 1000; private Handler handler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_clock); tvClock = (TextView) findViewById(R.id.ClockActivity_tv_clock); handler = new Handler(); new InnerThread().start(); } //自定义类继承Runnable,这个类的主要做用是处理消息,下面的 //Message.obtion(handler,Runnable)中的Runnable就是该InnerRunner public class InnerRunner implements Runnable { @Override public void run() { tvClock.setText(new Date().toString()); } } public class InnerThread extends Thread { @Override public void run() { while (true) { //Message类有公有的无参数的构造方法,开发者可以随 意创建Message对象,但是, // Message对象大多是被处理后就没有存在的意义了,所以反复创建Message对象会无谓的消耗内存 //推荐使用Message.obtain() 方法获取消息的对象,Message类自身使用了“Message池”对消息对象进行管理, //从而可以控制产生的Message对象的数量.如果使用的Message.obtain() 方法中, // 使用到了Handler做为参数,则需要使用Message对象的sendToTarget() 发送消息, //而不再使用Handler的sendMessage() 系列方法 //Message的what属性用于标识消息的类型(因为子线程可能向主线程发送若干种不同的消息), // 不应该用于封装有具体数值含义的数据,通常,what属性的值应该使用静态常量表示, // 例如msg.what = MESSAGE_UPDATE_CLOCK; //通过Handler对象的obtainMessage() 系列方法也可以获取Message对象, // 其实现效果与Message类的obtain() 方法是等效的 Message message = Message.obtain(handler, new InnerRunner()); message.what = UPDATA_MESSAGE_TIME; message.sendToTarget(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }}
使用CallBack处理消息
我自己又新建了一个Activity名叫ClockActivityTestTwo,它的布局文件的代码和activity_main代码相同,让我们来看一下ClockActivityTestTwo的代码吧:
对了,要记着在AndroidManifest.xml文件中将ClockActivityTestTwo设置为启动界面。
public class ClockActivityTwo extends AppCompatActivity { private TextView tvClock; private Handler handler; private String dataString; private Date date =new Date(); private SimpleDateFormat sdf =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_clock_activity_two); tvClock = (TextView) findViewById(R.id.ClockActivityTwo_tv_clock); //使用Handler.Callback接口的实现类对象,做为Handler构造方法的参数, // 也可以实现对消息的处理【推荐】 handler =new InnerHandler( new InnerCallBack()); new InnerThread().start(); } //Handler.Callback定义了public boolean handleMessage(Message msg)方法, // 其中,返回值(boolean类型)表示“是否已经完全处理了消息”, // 当返回值为false时,如果存在其它的消息处理方法,则对应的代码也会被执行, // 当返回值为true时,表示“已经完全处理了消息”,则其它的处理消息的代码不会运行 class InnerCallBack implements Handler.Callback { @Override public boolean handleMessage(Message msg) { tvClock.setText(dataString); Log.i("ClockActivityTwo", "HandlerCallBack"); return true; } } class InnerHandler extends Handler { public InnerHandler(Callback callback) { super(callback); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); tvClock.setText(dataString); Log.i("ClockActivityTwo", "HandlerMessage"); } } class InnerThread extends Thread { @Override public void run() { for (int i = 0; i < 1200; i++) { Message message =Message.obtain(); date.setTime(System.currentTimeMillis()); dataString =sdf.format(date); handler.sendMessage(message); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }}
这里我分别使用了callBack和handlerMessage()方法处理消息,当我在public boolean handleMessage(Message msg) 这是返回值为true时,那么handlerMessage就不会处理该消息了。可以看一下log日志:
06-05 23:19:04.489 24761-24761/com.example.clockthreadtest I/ClockActivityTwo: HandlerCallBack06-05 23:19:05.489 24761-24761/com.example.clockthreadtest I/ClockActivityTwo: HandlerCallBack06-05 23:19:06.489 24761-24761/com.example.clockthreadtest I/ClockActivityTwo: HandlerCallBack
当我将callBack中的public boolean handleMessage(Message msg) 这是返回值为false时,handlerMessage也会执行。让我们来看一下log日志:
06-05 23:19:55.489 25109-25109/com.example.clockthreadtest I/ClockActivityTwo: HandlerCallBack06-05 23:19:55.489 25109-25109/com.example.clockthreadtest I/ClockActivityTwo: HandlerMessage06-05 23:19:56.489 25109-25109/com.example.clockthreadtest I/ClockActivityTwo: HandlerCallBack06-05 23:19:56.489 25109-25109/com.example.clockthreadtest I/ClockActivityTwo: HandlerMessage
本篇博客我给大家列举了三种不同的Handler的处理方法,至于你要使用哪一种方式,那就要看你自己的习惯了。下面我来总结一下这三种方式:
关于处理消息的方式
1) 使用Message.obtain(Handler h, Runnable callback)中的Runnable对象处理消息
2) 使用Handler.Callback处理消息
3) 重写Handler类的handleMessage()处理消息
以上3种方式可以并存,优先级为1 -> 2 -> 3
当存在第1种方式时,消息将直接被处理,并且不会向后传递
当第2种方式存在时,其public boolean handleMessage(Message msg)方法的返回值决定消息是否向后传递
- Android_Handler
- android_Handler
- Android_Handler
- Android_Handler
- Android_Handler
- Android_Handler
- android_handler(一)
- android_handler(二)
- android_handler(三)
- Android_Handler用法
- Android_Handler机制
- android_Handler详解
- android_handler(一)
- android_handler(二)
- Android_Handler机制
- Android_Handler详解(一)
- Android_Handler源码分析
- Android_Handler中的HandlerMessage方法
- Android MVP 架构模式详解
- EventBus3.0使用初体验
- sudo apt-get update时遇到以下问题
- C++第七次作业
- 《Vim Pratical》学习笔记
- Android_Handler
- python的get方式提交请求
- 控件和布局的XML 属性:step one
- localStorage也可以限时保存登录信息
- c++作业7
- fsck exited with status code 4
- C++实验7-最大公约和和最小公倍数
- Spark定制班第18课:Spark Streaming中空RDD处理及流处理程序优雅的停止
- pdf转doc工具横向评测: