一.首先来看一下进程和线程的联系:
1.线程和进程相似,是一段完成某个特定功能的代码,是程序中单个顺序的流控制。
但与进程不同的是,同类的多个线程共享一块内存空间和一组系统资源,所以系统在各个线程之间切换,资源占用要比进程小得多。
一个进程中包含多个线程。主线程负责管理子线程,即子线程的启动,挂起,停止等操作。
2.多线程指的是在单个程序中可以同时运行多个线程,执行不同的任务。多线程意味着一个程序的多行语句可以看上去几乎在同一个时间内同时执行。
3.在java中有两种实现线程的方式:继承Thread类,实现Runnable接口。
4.在android平台中多线程应用很广泛,在UI更新,游戏开发和耗时处理等方面都需要多线程,涉及的知识点有:Handler,Message,MessageQueue,Looper,HandlerThread.
二.接下来,来看下android中多线程涉及的主要的几个知识点的解析:
1.Message:
Message是记录消息信息的类:几个重要的字段:
1).arg1和agr2:用來存放传递的整型值
2).obj是object类型,让该字段传递某個多項到消息的接受者中。
3).what是消息的标志,根据该字段的不同值,進行不同的處理。
我們通过Message.obtain()或者Handler.obtainMessage()來获取Message對象。在这里并不是直接创建一个Message对象,而是先从消息池中看有没有可用的Message对象,
存在则直接取出并返回这个实例,否则即没有可用的Message实例,则根据给定的参数,新建一个Message对象。android系统默认在消息池中实例化了10个Message对象。
2.MessageQueue:
在一个线程中,如果存在Looper对象,则必定存在MessageQueue对象,并且只存在一个Looper对象和一个MessageQueue对象。除了主线程有默认的Looper对象,其它
线程默认是没有Looper对象。
如果想让我们新创建的线程拥有Looper对象时,我们首先应调用Looper.prepare()方法,然后再调用Looper.loop()方法。
3.Looper:
是MessageQueue的管理者,在一个线程中,如果存在Looper对象,必定存在MessageQueue对象,并且只存在一个Looper对象和一个MessageQueue对象,在android中,除了主线程有默认的Looper对象之外,其它线程没有默认的Looper对象,要想新创建的线程拥有Looper对象,必须首先调用Looper.prepare()和Looper.loop()方法。
典型的用法如下:
class looperThread extends Thread{
@Override
public void run()
{
Looper.prepare();
//处理其它操作
Looper.loop();
}
}
此外我们可以通过Looper.myLooper();方法获取当前线程的Looper对象,并且可以通过方法Looper.getMainLooper();来获取主线程的Looper对象
4.Handler:
消息处理者。我们通过Handler对象来封装Message对象,通过sendMessage()把Message对象添加到MessageQueue中,当MessageQueue队列循环到此Message对象,调用该Message对象对应的Handler对象的HandleMessage()方法进行处理。一般我们使用HandlerThread类,该类是Thread的一个子类,该类运行时将会创建Looper对象,避免我们自己去编写Thread类并创建Looper对象。
接下来看一个运用Handler来更新进度条的Demo:
package com.android.douf;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
public class HandlerDemo1Activity extends Activity {
/** Called when the activity is first created. */
private Button start;
private ProgressBar bar;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
bar = (ProgressBar) findViewById(R.id.bar);
start = (Button) findViewById(R.id.start);
start.setOnClickListener(new StartClickListener());
}
class StartClickListener implements OnClickListener{
@Override
public void onClick(View v)
{
//进度条显示可见
bar.setVisibility(View.VISIBLE);
//将线程加入到队列中去,启动线程的run()方法;
handler.post(barRunable);
}
}
Handler handler = new Handler(){
//此方法来接受有sendMessage()发送到消息队列中的的消息
@Override
public void handleMessage(Message msg)
{
//更新进度条
bar.setProgress(msg.arg1);
//将线程加入到线程队列中去,再次启动run()方法;
handler.post(barRunable);
}
};
//创建一个线程
Runnable barRunable = new Runnable()
{
int i = 0;
@Override
public void run()
{
i = i+10;
//获取消息对象
Message msg = handler.obtainMessage();
//将消息对象的参数arg1的值设置为i;
msg.arg1 = i;
try
{
//将此线程沉睡1秒钟
Thread.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
//将此消息对象发送到消息队列中去
handler.sendMessage(msg);
if (i>=100)
{
//当进度条更新完毕时,移除此线程
handler.removeCallbacks(barRunable);
//将进度条设置不可见
bar.setVisibility(View.GONE);
}
}
};
}
以上研究了Handler来处理消息队列,但是android中的handler不是另开一个线程来来执行的,而是仍在UI主线程中执行。那如果想另开启线程来处理该如何解决呢。这个时候就需要用到HandlerThread类,该类继承于Thread类,主要的功能是实现了一个自己的线程,并且创建自己的消息队列,有自己的Looper,可以在自己的线程中发布和处理消息。
我们一个Demo来解释这个HandlerThread实现异步的功能:
package com.android.douf;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
public class ThreadHandlerActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//打印当前线程对象的ID和线程名
System.out.println("activity:"+Thread.currentThread().getId());
System.out.println("activity:"+Thread.currentThread().getName());
//生成一个HandlerThread对象,实现了使用Looper来处理消息队列的功能。
HandlerThread handlerThread = new HandlerThread("handler_thread");
//在使用Looper对象之前,必须先启动该线程
handlerThread.start();
MyHandler myHandler = new MyHandler(handlerThread.getLooper());
//生成Message对象,将信息保存到Message对象中
Message msg = myHandler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putString("name", "douf");
bundle.putInt("age", 18);
msg.setData(bundle);
//将消息加入到消息队列中
myHandler.sendMessage(msg);
}
//自定义一个类继承Handler类
class MyHandler extends Handler{
public MyHandler()
{
}
public MyHandler(Looper looper)
{
super(looper);
}
//接受消息队列中的消息
@Override
public void handleMessage(Message msg)
{
super.handleMessage(msg);
System.out.println("handler:"+Thread.currentThread().getId());
System.out.println("handler:"+Thread.currentThread().getName());
Bundle b = msg.getData();
String name = b.getString("name");
int age = b.getInt("age");
System.out.println("name:"+name+"\n"+"age:"+age);
}
}
}
结果截图如下:
我们分别打印了UI线程和Handler处理的线程的ID和名,发现这时就是两个不同的线程,此时我们可以说实现了异步处理的功能,实现了其它线程向主线程传递消息,以及主线程接受来自其它线程的消息。