每次在Android中遇到Handler,Runnable,Thread,HandlerThread,Message,Looper,MessageQueue及多线程的时候,我就一阵眩晕,感觉这些知识好难懂,今天就我的理解写一些总结,大部分内容都是从别人的博客中的理解。

首先,看看Java中的多线程是如何实现的,在Java中实现多线程有两种方式,当然这两种方式放在Android也是能运行的:

  

class MyThread extends Thread {
public void run() {
// 这里写上线程的内容
}
public static void main(String[] args) {
// 使用这个方法启动一个线程
new MyThread().start();
}
}
class MyThread implements Runnable{
public void run() {
// 这里写上线程的内容
}
public static void main(String[] args) {
// 使用这个方法启动一个线程
new Thread(new MyThread()).start();
}
}

前者是继承Thread类,后者是实现了Runnable接口,一般鼓励使用第二种方式,因为Java只允许单继承,但允许实现多个接口。

接下来,看看线程的状态,线程状态一共5种,分别是:

      新生状态(New): 当一个线程的实例被创建即使用new关键字和Thread类或其子类创建一个线程对象后,此时该线程处于新生(new)状态,处于新生状态的线程有自己的内存空间,但该线程并没有运行,此时线程还不是活着的(not alive);

  就绪状态(Runnable): 通过调用线程实例的start()方法来启动线程使线程进入就绪状态(runnable);处于就绪状态的线程已经具备了运行条件,但还没有被分配到CPU即不一定会被立即执行,此时处于线程就绪队列,等待系统为其分配CPCU,等待状态并不是执行状态; 此时线程是活着的(alive);

  运行状态(Running): 一旦获取CPU(被JVM选中),线程就进入运行(running)状态,线程的run()方法才开始被执行;在运行状态的线程执行自己的run()方法中的操作,直到调用其他的方法而终止、或者等待某种资源而阻塞、或者完成任务而死亡;如果在给定的时间片内没有执行结束,就会被系统给换下来回到线程的等待状态;此时线程是活着的(alive);

  阻塞状态(Blocked):通过调用join()、sleep()、wait()或者资源被暂用使线程处于阻塞(blocked)状态;处于Blocking状态的线程仍然是活着的(alive)

  死亡状态(Dead):当一个线程的run()方法运行完毕或被中断或被异常退出,该线程到达死亡(dead)状态。此时可能仍然存在一个该Thread的实例对象,当该Thread已经不可能在被作为一个可被独立执行的线程对待了,线程的独立的call stack已经被dissolved。一旦某一线程进入Dead状态,他就再也不能进入一个独立线程的生命周期了。对于一个处于Dead状态的线程调用start()方法,会出现一个运行期(runtime exception)的异常;处于Dead状态的线程不是活着的(not alive)。

     现在开始Android的消息队列模式,Activity、Looper、Handler,Thread之间的的关系,那么一个线程怎样把消息放入主线程的消息队列呢?答案是通过Handle对象,只要Handler对象以主线程的Looper创建,那么调用Handler的sendMessage等接口,将会把消息放入队列都将是放入主线程的消息队列。并且将会在Handler主线程中调用该handler的handleMessage接口来处理消息,见下图:

 

image

Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。

Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。

MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。

Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper

Thread:线程,负责调度整个消息循环,即消息循环的执行场所。

由上图可以看到Handler负责将Message放入到MessageQueue中,一个MessafeQueue可以对应多个Handler,那么Handler和Runnable是什么关系呢。

我们还是通过几个例子来具体看下:

package com.xue.threaddemo;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
public class ThreadDemo extends Activity {
    private static final String TAG = "ThreadDemo";
    private int count = 0;
    private Handler mHandler =  new Handler();
    
    private Runnable mRunnable = new Runnable() {
        
        public void run() {
            //为了方便 查看,我们用Log打印出来
            Log.e(TAG, Thread.currentThread().getName() + " " +count);
            count++;
            setTitle("" +count);
            //每2秒执行一次
            mHandler.postDelayed(mRunnable, 2000);
        }
        
    };
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main); 
        //通过Handler启动线程
        mHandler.post(mRunnable);
    }
    
    @Override
    protected void onDestroy() {
        //将线程销毁掉
        mHandler.removeCallbacks(mRunnable);
        super.onDestroy();
    }
}

由上面代码可以看出handler通过mHandler.post(mRunnable)方法启动一个Runnable,然后执行Runnable方式中的的run()方法的代码。下面看看另外一个例子:

package com.xue.handlerdemo;

import java.util.Timer;
import java.util.TimerTask;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.view.Menu;

public class MainActivity extends Activity {
    
    private int title = 0;
    private Handler handler =new Handler(){
        public void handleMessage(Message msg) {
            if(msg.what==1){
                updateTitle();
            }
        };
    };
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Timer timer = new Timer();
        timer.scheduleAtFixedRate(new MyTask(), 1, 5000);
    }
    class MyTask extends TimerTask{

        @Override
        public void run() {
            // TODO Auto-generated method stub
            Message message =new Message();
            message.what=1;
            handler.sendMessage(message);
        }
        
    }
    public void updateTitle(){
        setTitle("Welcome to Xue's APP " + title);
        title ++;
    }
}

上面代码中终于有Message出现了,在继承自TimerTask的类中,实例化一个Message对象,然后handler.sendMessage(message)把message传递给Handler,前面讲过Handler就是用来处理message的,上面代码中用sendmessage()发送消息,在Handler中用handleMessage(Message msg)接收消息,那么这个实例化的message在接收之前放在消息队列中,实例化的Message除了有what参数外常用的还有arg1,agr2,obj,前面两个是int类型,obj是object类型。下来看一个MARS老师的例子:

package mars.barhandler;

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 TestBarHandler extends Activity {
    /** Called when the activity is first created. */
    //声明控件变量
    ProgressBar bar = null;
    Button startButton = null;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        //根据控件的ID得到代表控件的对象,并为按钮设置监听器
        bar = (ProgressBar)findViewById(R.id.bar);
        startButton = (Button)findViewById(R.id.startButton);
        startButton.setOnClickListener(new ButtonListener());
    }
    //当点击startButton按钮时,就会执行ButtonListener的onClick方法
    class ButtonListener implements OnClickListener{

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            bar.setVisibility(View.VISIBLE);
            updateBarHandler.post(updateThread);
        }
        
    }
    //使用匿名内部类来复写Handler当中的handleMessage方法
    Handler updateBarHandler = new Handler(){

        @Override
        public void handleMessage(Message msg) {
            bar.setProgress(msg.arg1);
            Bundle bundle = msg.getData();
            updateBarHandler.post(updateThread);
            System.out.println("test---->" + bundle.getString("test"));
        }
        
    };
    //线程类,该类使用匿名内部类的方式进行声明
    Runnable updateThread = new Runnable(){
        int i = 0 ;
        @Override
        public void run() {
            System.out.println("Begin Thread" + i);
            i = i + 10 ;
            //得到一个消息对象,Message类是有Android操作系统提供
            Message msg = updateBarHandler.obtainMessage();
            
            //将msg对象的arg1参数的值设置为i,用arg1和arg2这两个成员变量传递消息,优点是系统性能消耗较少
            msg.arg1 = i ;
            Bundle bundle = new Bundle();
            bundle.putString("test", "test bundle");
            msg.setData(bundle);
            try {
                //设置当前显示睡眠1秒
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            //将msg对象加入到消息队列当中
            if( i > 100){
                //如果当i的值为100时,就将线程对象从handler当中移除
                updateBarHandler.removeCallbacks(updateThread);
                System.out.println(">>>>>>");
            }else{
                updateBarHandler.sendMessage(msg);
                System.out.println("<<<<<<");
            }
        }
    };
}

这个例子非常经典,点击开始按钮后,updateBarHandler.post(updateThread)通过post方法handler启动了一个runnable,在继承自Runnable的类中终于又出现Message啦,这次不仅简单的让msg.arg1=i而且还加入了Bundle类型的数据msg.setData(bundle);然后当然是sendMessage了,相应的在Handler中就会有handlerMessage接收消息,这儿可以注意到第一个例子没有使用Message机制,所以第一个例子仅仅是使用post方法启动了个runnable,而在runnable没有使用sendMessage方法发送消息,故Handler没有加入handlMessage方法,仅仅实例化了个Handler()。回到本例子中,Handler接收到消息后,bar.setProgress(msg.arg1)更新了UI,而且接收了Runnable发送的参数,然后再用post方法循环到Runnable一直到i>100,updateBarHandler.removeCallbacks(updateThread)这行代码非常重要,作用是把线程对象从handler当中移除,那么不移除会有什么后果,不移除的话即时关闭这个应用,线程不会停,依然在执行。
    许多初入Android或Java开发的新手对Thread、Looper、Handler和Message仍然比较迷惑,衍生的有HandlerThread、java.util.concurrent、Task、AsyncTask由于目前市面上的书籍等资料都没有谈到这些问题,遇到的时候总是感觉一阵眩晕,我的理解还是较为浅薄,望海涵。

 

    由于不满意自己对Handler的理解,贴上一篇博文,这里面讲的非常详细:http://52android.blog.51cto.com/2554429/470542

 

posted on 2013-05-21 17:43  移动互联奇葩  阅读(697)  评论(2编辑  收藏  举报