转载请注明出处https://blog.csdn.net/zxw136511485/article/details/53032658/
本文描述的是Android中的Runnable接口 。因Android中的线程源自于Java,所以首先需要了解Java中的线程,有关Java中的线程请看这篇文章Android(线程一) 线程 !
Java开发中,我们实现多线程,有两种方式, 一种是继承Thread类,一种是实现Runnable接口。但是,我们真的理解Runnable?Runnable和Thread一样吗?都是开启新的线程吗? 为何明明在子线程使用Handler的post(Runnable),最终还是在主线程中执行呢?...带着这些疑问,我们来开始今天的博文。本文的例子是基于Android Studio。
一、首先通过例子实现这两种方式。
1、继承Thread类。
Thread类是在java.lang包中定义的。一个类只要继承了Thread类同时覆写了本类中的run()方法就可以实现多线程操作了。
首先新建一个MyThread类继承自Thread类,重写run()方法,在控制输入传递的文本,
-
public class MyThread extends Thread {
-
-
private String name;
-
-
public MyThread(String name) {
-
this.name = name;
-
}
-
-
-
public void run() {
-
System.out.println( "MyThread is " + name);
-
}
-
}
-
public class Test1 {
-
-
public static void main(String[] args){
-
MyThread myThread1= new MyThread( "线程1");
-
MyThread myThread2= new MyThread( "线程2");
-
MyThread myThread3= new MyThread( "线程3");
-
-
myThread1.start();
-
myThread2.start();
-
myThread3.start();
-
-
System.out.println( "myThread1 id ="+myThread1.getId());
-
System.out.println( "myThread1 id ="+myThread2.getId());
-
System.out.println( "myThread1 id ="+myThread3.getId());
-
-
-
}
-
-
}
控制台输出截图如下,
开启了三个线程。
PS:如果你也是使用Android Studio,控制台中文输出可能是乱码,那么可以参考这篇文章去解决,Android Studio中Java控制台中文输出乱码
2、实现Runnable接口。
Runnable只是一个接口,它里面只有一个run()方法,没有start()方法,
-
public interface Runnable{
-
public void run();
-
}
而Thread类,有一个构造方法,参数是Runnable对象,也就是说可以通过Thread类来启动Runnable实现的多线程。
-
public Thread(Runnable target) {
-
init( null, target, "Thread-" + nextThreadNum(), 0);
-
}
下面还是上案例说明,
创建一个类MyRunnable,实现Runnable接口,
-
public class MyRunnable implements Runnable {
-
-
private String name;
-
-
public MyRunnable(String name) {
-
this.name = name;
-
}
-
-
public void run() {
-
System.out.println( "MyRunnable is " + name);
-
}
-
}
下面是调用以及启动线程并打印线程的id,启动线程还是调用Thread类的start()方法,
-
public class Test1 {
-
-
public static void main(String[] args){
-
-
MyRunnable myRunnable1= new MyRunnable( "Runnable1");
-
MyRunnable myRunnable2= new MyRunnable( "Runnable2");
-
MyRunnable myRunnable3= new MyRunnable( "Runnable3");
-
-
Thread myThread1= new Thread(myRunnable1);
-
myThread1.start();
-
System.out.println( "myThread1 id ="+myThread1.getId());
-
Thread myThread2= new Thread(myRunnable2);
-
myThread2.start();
-
System.out.println( "myThread1 id ="+myThread2.getId());
-
Thread myThread3= new Thread(myRunnable3);
-
myThread3.start();
-
System.out.println( "myThread1 id ="+myThread3.getId());
-
}
-
-
}
控制台输出截图如下,
可以看到,启动了三个不同的线程。
小结:通过上面的两个小例子程序,我们可以得知,只是实现Runnable接口,并不能启动或者说实现一个线程。Runnable接口,并不能代表一个线程。Runnable接口和线程是两个不同的概念!
换句话说,一个类,实现Runnable接口,这个类可以做很多事情,不仅仅只被用于线程,也可以用于其他功能!
二、 为何明显使用Handler的post(Runnable),最终还是在主线程中执行呢?
1.我们都知道使用Handler更新UI,有时候会调用 Handler.post()方法更新UI, Handler.post()方法的源码如下,
-
public final boolean post(Runnable r)
-
{
-
return sendMessageDelayed(getPostMessage(r), 0);
-
}
getPostMessage()方法是创建一个Message对象,并且将参数的Runnable对象赋值给了该Message对象的callback属性,
-
private static Message getPostMessage(Runnable r) {
-
Message m = Message.obtain();
-
m.callback = r;
-
return m;
-
}
2.执行Looper.loop()方法,该方法将会从消息循环中循环取出消息,取出消息后,会执行下面的代码,
-
public void dispatchMessage(Message msg) {
-
if (msg.callback != null) {
-
handleCallback(msg);
-
} else {
-
if (mCallback != null) {
-
if (mCallback.handleMessage(msg)) {
-
return;
-
}
-
}
-
handleMessage(msg);
-
}
-
}
-
private static void handleCallback(Message message) {
-
message.callback.run();
-
}
message.callback.run();
很显然该方法仅仅是执行了消息的callback属性(Runnable对象)的run()方法,并没有开启子线程,它其实还是运行在Handler所在的线程即主线程中。
小结:使用Handler.post()方法更新UI,只是将消息加入到消息队列,并且设置消息的callback属性为参数Runnable对象的值;从消息循环中取出消息时,将执行消息对象的callback属性(Runnable对象)run()方法,还是在Handler所在的主线程中运行的,并没有开启新的子线程。
总结:读过本篇文章后,相信读者对Handler.post()方法更新UI理解会更清晰、完整、透彻,并且对Runnable接口会有新的不一样的认识。
PS:在使用Runnable时,可能会内存泄露。Runnable是一个匿名内部类,因此它对当前Activity有一个隐式引用。如果Activity在销毁之前,任务还未完成, 那么将导致Activity的内存资源无法回收,造成内存泄漏。那么该怎么解决这种问题呢?代码如下,
-
static class MyRunnable implements Runnable {
-
-
public void run() {
-
//执行任务
-
}
-
}
推荐文章: Android 更新UI的几种方法。
Android 源码解析Handler处理机制(一) 。