我们做的是Android的应用开发,凡是应用都会存在线程,存在线程就会需要用到多线程的机制;Android应用许多时候也要用到多线程,如UI更新、耗时的操作、网络编程等等。Android的多线程算是较为复杂的一种。首先我们知道Android基本是使用java来写的,所以Android的多线程应该也跟java差不多。首先我们知道java编写多线程有两种方式。
一、是继续Thread类
二、是实现Runable接口
想必学过java的人都不陌生,那按理说Android也应该如此,但是实际却还是有差别的;我们先用java的方式写下:
package com.maple.baiduweather;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
public class MainActivity extends Activity {
private static final String TAG = "mainActivity";
private TextView mTimeText = null;
private int timer = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTimeText = (TextView) findViewById(R.id.text_view);
new Thread() {
public void run() {
try {
Thread.sleep(1000);
timer++;
mTimeText.setText("时间:" + timer + "s");
Log.d(TAG, "time:"+timer);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
};
}.start();
}
}
看起来好像很完美对吧。但是运行时抛出如下异常
报异常:android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
【只有原始创建这个视图层次(view hierachy)的线程才能修改它的视图(view)】
这是异常解释,意思就是说只有主线程可以更新UI。这其实是Android的一种保护机制,因为子线程更新UI是不安全的,为什么这样呢?原因很简单,子线程有可能有很多个,如果它们同时更新一个UI控件的话,就有可能发生冲突,所以Android在这里限定了只有主线程有权利更新UI,你子线程要跟新,来告诉主线程,让主线程来操作。
那子线程如何通知主线程更新UI呢?这里就要使用Handle类了。
Handle
Handle是直接继承与java.lang.Object的。
一个Handle允许发送和处理Message或者Runnable对象,并且会关联到主线程MessageQueue中,每个Handler具有一个单独的线程,并且关联到一个消息队列的线程,就是说一个Handler有一个固有的消息队列。当实例化一个Handler 的时候,它就承载在一个线程和消息队列的线程,这个Handler可以把Message或Runnable压入到消息队列,并且从消息队列中取出 Message或Runnable,进而操作它们。
Handle的两个作用:①在工作线程中发送消息②在UI中处理和获取信息;
从上面我们可以知道Handle可以把一个Message对象或者Runnable对象压进线程的消息队列,然后主线程中获取Message对象或者Runnable对象。Handle压入消息队列有两个方法:Post和sendMessage;
- Post:Post允许把一个Runnable对象压入到消息队列中。它的方法有:post(Runnable)、postAtTime(Runnable,long)、postDelayed(Runnable,long)。
- sendMessage:sendMessage允许把一个包含消息数据的Message对象压入到消息队列中。它的方法有:sendEmptyMessage(int)、sendMessage(Message)、sendMessageAtTime(Message,long)、sendMessageDelayed(Message,long)。
具体我们看下方法,首先我们使用post方法:
new Thread(new Runnable(){
@Override
public void run() {
mHandle.post(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
timer++;
mTimeText.setText("时间:" + timer + "s");
Log.d(TAG, "time:"+timer);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}).start();
但是post方式有个局限性,那就是它的Runnable对象的run()方法的代码,都执行在UI线程上,一旦遇到那种无法执行在UI线程上的操作,就无法使用post方法了。
下面看下Message方法
private Handler mHandle = new Handler() {
// 在Handler中获取消息,重写handleMessage()方法
@Override
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case 1:
timer++;
mTimeText.setText("时间:" + timer + "s");
Log.d(TAG, "time:"+timer);
break;
default:
break;
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTimeText = (TextView) findViewById(R.id.text_view);
// 新启动一个子线程
new Thread(new Runnable(){
@Override
public void run() {
try {
Thread.sleep(1000);
Message msg = new Message();
msg.what = 1;
mHandle.sendMessage(msg);
Log.d(TAG, "time:"+timer);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();