1、Handler的作用:
1)在Android中UI操作一般情况下不能放在子线程中进行操作,如果在子线程中操作会出现Only the original thread that created a view hierarchy can touch its views.错误,但是有的时候UI布局需要得到子线程的数据,这个时候就需要使用Handler来进行UI的操作。
2)如果UI布局还没有完成,这个时候是可以在子线程中进行UI的操作;代码如下:
public class MainActivity01 extends AppCompatActivity {
TextView textview;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textview = (TextView) findViewById(R.id.textview);
AThread aThread = new AThread(textview);
aThread.start();
}
class AThread extends Thread {
TextView textView;
public AThread(TextView textView) {
this.textView = textView;
}
@Override
public void run() {
String temp = "hahaha";
temp += "AAA";
textView.setText(temp);
}
}
}
原因是:android在编译的时候回先判断activity是否存在,如果存在了才会去判断后面的UI操作是否是在UI线程中进行的,如果不是就会出现错误,但是如果把子线程进行的UI操作写在前面,就会在activity还没有布局完成的时候就进行了UI操作,因为activity== null所以不会去判断该UI操作是否是在UI线程中进行的。但是这种操作没有什么意义,通常情况下都是activity已经存在,只是想得到子线程中的属性来给UI里面的控件进行更改,因此要使用Handler。
2、Handler的用法:
a.1:在UI线程中进行Handler的初始化,在把初始化后的结果传递到子线程中,把UI控件需要的值通过sendMessage()方法传递出来然后在UI线程中更改。这也是Handler最常用的方法;代码如下:
public class MainActivity02 extends Activity implements View.OnClickListener {
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textview);
textView.setOnClickListener(this);
}
@Override
public void onClick(View v) {
MyHandler myHanler = new MyHandler();
BThread bThread = new BThread(myHanler);
bThread.start();
}
class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
textView.setText(msg.obj.toString());
}
}
class BThread extends Thread {
Handler handler;
public BThread(Handler handler) {
this.handler = handler;
}
@Override
public void run() {
String temp = "哈哈哈";
temp += "BBB";
Message message = handler.obtainMessage();
message.obj = temp;
handler.sendMessage(message);
}
}
}
a.2 除此之外,其实我们还可以在子线程中定义Handler,通过把UI线程的Looper传递到子线程中来进行UI控件的操作设置;
代码如下:
UI线程代码:
public class MainActivity04 extends Activity implements View.OnClickListener{
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textview);
textView.setOnClickListener(this);
}
@Override
public void onClick(View v) {
DThread cThread = new DThread(textView, Looper.myLooper());
cThread.start();
}
}
子线程代码:
public class DThread extends Thread {
TextView textView;
Looper looper;
public DThread(TextView textView, Looper looper) {
this.textView = textView;
this.looper = looper;
}
@Override
public void run() {
Looper.prepare();
MyHandler myHandler = new MyHandler(looper);
Message message = myHandler.obtainMessage();
String temp = "DDD";
message.obj = temp;
message.setTarget(myHandler);
myHandler.sendMessage(message);
// looper.loop();
}
class MyHandler extends Handler{
public MyHandler(Looper looper){
super(looper);
}
@Override
public void handleMessage(Message msg) {
textView.setText(msg.obj.toString());
}
}
}
3、总结:
通过以上2中Handler的使用方法,我们可以发现不管在哪个线程进行Handler的定义,我们都可以完成UI控件的操作。是否能够进行UI控件的操作其实主要是看我们通过Handler把UI控件需要的子线程的哪个属性通过sendMessage()方法发送到了哪里,Handler发送的消息会被添加到被关联的MessageQueue中。我们就可以通过looper.loop()来遍历MessageQueue里面的信息只要MessageQueue是主线程的,那么这个信息就可以在主线程中得到就能够用得到的属性在UI线程中完成对控件的操作。
通过Handler的工作原理,我们可以直接写一个简单的自定义的Handler来完成对UI的操作;
代码如下:
自定义的Handler:
public class MyHand {
ArrayList<IMessage> arrayList;
public MyHand(ArrayList<IMessage> arrayList) {
this.arrayList = arrayList;
}
public void handleIMessage(IMessage iMessage){
}
public void sendIMessage(IMessage iMessage){
arrayList.add(iMessage);
}
}
信息:
public class IMessage {
Object object;
MyHand target;
}
子线程:
public class GThread extends Thread {
MyHand myHand;
public GThread(MyHand myHand) {
this.myHand = myHand;
}
@Override
public void run() {
String temp = "哈哈哈";
temp += "GGG";
IMessage iMessage = new IMessage();
iMessage.target = myHand;
iMessage.object = temp;
myHand.sendIMessage(iMessage);
}
}
主线程:
public class MainActivity07 extends Activity implements View.OnClickListener{
TextView textView;
Button button_check;
IMessage iMessage;
ArrayList<IMessage> arrayList;
MyHand myHand ;
boolean isFlag = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textview);
button_check = (Button) findViewById(R.id.button_check);
textView.setOnClickListener(this);
button_check.setOnClickListener(this);
arrayList = new ArrayList();
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.textview:
if (arrayList.size() > 0){
myHand = iMessage.target;
myHand.handleIMessage(iMessage);
}
break;
case R.id.button_check:
GThread gThread = new GThread(new Ghand(arrayList));
gThread.start();
while (isFlag){
if (arrayList.size() > 0){
iMessage = arrayList.get(0);
if (iMessage == null){
return;
}
isFlag = false;
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Ghand extends MyHand{
public Ghand(ArrayList<IMessage> arrayList) {
super(arrayList);
}
@Override
public void handleIMessage(IMessage iMessage) {
textView.setText(iMessage.object.toString());
}
}
}