您的位置:首页 > 移动开发 > Android开发

Android--Handler

2016-06-02 20:42 459 查看
一:定义

主要接收子线程发送的数据, 并用此数据配合主线程更新UI,用来跟UI主线程交互用。

比如可以用handler发送一个message,然后在handler的线程中来接收、处理该消息,以避免直接在UI主线程中处理事务导致影响UI主线程的其他处理工作,Android提供了Handler作为主线程和子线程的纽带;也可以将handler对象传给其他进程,以便在其他进程中通过handler给你发送事件;还可以通过handler的延时发送message,可以延时处理一些事务的处理。

通常情况下,当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI控件,进行事件分发。如果此时需要一个耗时的操作,例如:联网读取数据,或者读取本地较大的一个文件的时候,不能把这些操作放在主线程中,如果你放在主线程中的话,界面会出现假死现象,如果5秒钟还没有完成的话,会收到Android系统的一个错误提示”强制关闭”. 而子线程是不能直接操作UI!

此时就需要把这些耗时的操作,放在一个子线程中,因为子线程涉及到UI更新,当子线程中有涉及到操作UI的操作时,就会对主线程产生危险,也就是说,更新UI只能在主线程中更新,在子线程中操作是危险的. 这个时候,Handler就出现了来解决这个复杂的问题,由于Handler运行在主线程中(UI线程中),它与子线程可以通过Message对象来传递数据,这个时候,Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传递)Message对象,(里面包含数据), 把这些消息放入主线程队列中,配合主线程进行更新UI。

二:特点:

handler可以分发Message对象和Runnable对象到主线程中, 每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程),它有两个作用:

(1)安排消息或Runnable 在某个主线程中某个地方执行;

(2)安排一个动作在不同的线程中执行。

Handler中分发消息的一些方法

post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnable long)
sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)


以上post类方法允许你排列一个Runnable对象到主线程队列中,

sendMessage类方法, 允许你安排一个带数据的Message对象到队列中,等待接收,然后更新相关数据。

三:使用

—-1:简单例子

public class FristActivity extends AppCompatActivity implements View.OnClickListener {
TextView textView;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_frist);
textView = (TextView) findViewById(R.id.textMsg);
findViewById(R.id.sendBtn).setOnClickListener(this);
}

Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 2:
textView.setText("msg.what=2");
break;
}
super.handleMessage(msg);
}
};

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.sendBtn:
Message message = new Message();
message.what = 2;
handler.sendMessage(message);
break;
}
}
}


—-2:发送一个空消息

//1 注意第一种与第二种参数不一样的问题
Message message = new Message();
message.what = 0;
handler.sendMessage(message);
//2:比第一种方式更节省运行内存
Message message1 = handler.obtainMessage();
message1.arg1 = 0;
handler.sendMessage(message1);
//3直接调用系统提供的方法
handler.sendEmptyMessage(0);


—-3:稍微复杂一点的例子:



public class OneActivity extends AppCompatActivity {

TextView textView;

MyHandler myHandler;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_frist);
textView = (TextView) findViewById(R.id.textMsg);
myHandler = new MyHandler();
MyThred m = new MyThred();
new Thread(m).start();
}

class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Bundle bundle = msg.getData();
String msgString = bundle.getString("msg");
textView.setText(msgString);
}
}

class MyThred extends Thread {
@Override
public void run() {
super.run();
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
Message message = myHandler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putString("msg", "msg=====null");
message.setData(bundle);

myHandler.sendMessage(message);
}
}


}

—-4:从消息队列中移除<避免重复发送消息>

myHandler.removeMessages(int what);

myHandler.removeMessages(int what,Object o);

myHandler.removeCallbacksAndMessages(Object o);

myHandler.removeCallbacks(Runnable r,Object o);

myHandler.removeMessages(int what);

myHandler.removeCallbacks(Runnable r);

—-5:<简单操作可以使用本例子>

运行结果是每隔三秒就打印出来数据。

—-是因为实现了Runable接口,runable对象进入了空的消息队列即被立即执行Run方法,而在Run方法内部,在三秒之后将其再次发送到消息队列里面。

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button).setOnClickListener(this);
findViewById(R.id.button2).setOnClickListener(this);
}

Handler handler = new Handler();

Runnable runnable = new Runnable() {
@Override
public void run() {
Log.i("start", "start");
handler.postDelayed(runnable, 3000);
}
};

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button:
handler.post(runnable);
break;
case R.id.button2:
handler.removeCallbacks(runnable);
break;
}
}
}


总结:

post方法虽然发送的是一个实现了Runnable接口的类对象,但是它并非创建了一个新线程,而是执行了该对象中的run方法。也就是说,整个run中的操作和主线程处于同一个线程。

—-6:

<
HandlerThread就是可以处理消息循环的线程,它是一个拥有Looper的线程,可以处理消息循环;说Handler和一个线程绑定,倒不如说Handler和Looper是一一对应的
>


–1:获取当前线程的ID

Thread.currentThread().getId()


–2:HandlerThread

–3:创建一个HandlerThread,即创建了一个包含Looper的线程<在使用HandlerThread的getLooper()方法之前,必须先调用该类的start(),同时开启一个新线程>

HandlerThread       handlerThread = new HandlerThread("leochin.com");
handlerThread.start();       //创建HandlerThread后一定要记得start()


–4:获取HandlerThread的Looper

Looper looper =  handlerThread.getLooper();


–5:创建Handler,通过Looper初始化

Handler handler = new Handler(looper);


通过以上三步我们就成功创建HandlerThread。通过handler发送消息,就会在子线程中执行。

如果想让HandlerThread退出,则需要调用handlerThread.quit();

在使用sendMessage方法传递消息或者使用post方法传递Runnable对象时,就会把它们传递到与handler对象绑定的处于另外一个线程的消息队列中,它们将在另外的消息队列中被处理。而主线程还会在发送操作完成时候继续进行,不会影响当前的操作。<参考前面例子>

–7:重点:

在主线程通过Handler handler = new Handler();即使用默认构造函数构造Handler时,是默认使用主线程的Looper对象,通过这种方式构造的Handler是属于主线程的,也就是Handler和Looper是绑定在一起的,如果构造Handler时指定一个新线程的Looper对象,则该Handler对象是属于该子线程的。

mHandler=new Handler();
mHandler.post(new Runnable(){
void run(){

}
});


这个线程其实是在UI线程之内运行的,并没有新建线程!

常见的新建线程的方法是:

Thread thread = new Thread();
thread.start();

HandlerThread thread = new HandlerThread("string");
thread.start();


—-8:

UI线程它已经建立了Looper,因为主线程默认有一个自己的Looper对象和Message对象,非主线程默认是没有自己的Looper,需要自己去创建:通过Looper.prepare创建一个Looper对象,以及 Looper.loop()创建消息循环队列;在新线程(非主线程)中创建Handler对象,有两种方法实现:

1–创建Handler之前通过 Looper.prepare()方法创建Looper对象;<非主线程>

Looper.prepare();// 创建该线程的Looper对象,用于接收消息,在非主线程中是没有looper的所以在创建handler前一定要使用prepare()创建一个Looper
Handler myThreadHandler = new Handler(){};


2–使用主线程的Looper对象,因为每个主线程默认已经创建了自己的Looper对象;

<Looper.getMainLooper()><主线程>


Handler threadMainLoopHandler = new Handler(Looper.getMainLooper()){};


—-9:

在一个新线程中要创建一个Handler就需要这样写:

class MyThread extends Thread {
public void run() {
myThreadHandler = new Handler() {
public void handleMessage(Message msg{

}
};
Looper.myLooper().loop();//建立一个消息循环,该线程不会退出
}
}


四:源码分析:

—-MessageQueue队列

—–队列属于某一个Looper

—–每个Looper对象通过ThreadLocal.set(new Looper())跟一个Thread绑定

—-Looper对象所属的线程在Looper.Loop方法中循环执行从MessageQueue队列读取Message对象,并把Message对象交由Handler处理,调用Handler的dispatchMessage方法

参考:http://blog.csdn.net/stonecao/article/details/6417364

五:源码:

public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}


dispatchMessage定义看出,如果Message对象自带callback对象,handler不会执行handleMessage方法而是执行message.callback中定义的run方法,当然callback还是在handler关联的looper所绑定的线程中执行的。实际上Handler.post(Runnable r)方法就是把r添加到一个msg.callback中。

—-1:

Handler handler = new Handler();

Message message = Message.obtain(handler, new Runnable() {
@Override
public void run() {

}
});
handler.sendMessage(message);


—-2:

Handler handler = new Handler();

handler.post(new Runnable() {
@Override
public void run() {

}
});


以上两种方式来说,代码功能没有区别!

注意:本文里面一些创建Handler的方式并不是都说最好的,有些只是为了演示简化步骤,故在使用过程中,请注意按照最优的创建方式创建对象并使用!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android ui 事务