[置顶] [Android基础]Android的消息机制

有时候需要在子线程中进行耗时的I/O操作,可能是读取文件或者访问网络等,当耗时操作完成以后需要在UI上做一些改变,由于Android开发规范的限制,我们并不能在子线程访问UI控件,否则就会触发程序异常,这个时候通过Handler就可以将更新UI的操作切换到主线程中执行。本质上来说, handler并不是专门用于更新UI的,它只是常被开发者用来更新UI。
Android的消息机制只要是指Handler的运行机制,Handler的运行需要底层的MessageQueue和Looper的支撑。

Handler类简介
主要作用:在新启动的线程中发送消息和在主线程中获取、处理消息。
通过疯狂讲义上一个简单例子来分析下:

public class HandlerTest extends Activity {
    int[] imageIds = new int[]
    {
        R.drawable.jay,
        R.drawable.jack,
        R.drawable.jason,
        R.drawable.sun,
        R.drawable.classic
    };
    int currentImageId = 0;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        final ImageView show = (ImageView) findViewById(R.id.show);
        final Handler myHandler = new Handler()
        {
            @Override
            public void handleMessage(Message msg)
            {
                //如果该消息是本程序发送的
                if (msg.what == 0x1233)
                {
                    show.setImageResource(imageIds[currentImageId++
                        % imageIds.length]);
                }
            }
        };
        new Timer().schedule(new TimerTask()
        {
            @Override
            public void run()
            {
                myHandler.sendEmptyMessage(0x1233);
            }
        }, 0, 1200);
    }
}

分析:TimerTask对象的本质就是启动一条新线程。Handler的handleMessage(Message msg)方法用于处理消息,当新线程发送消息时,该方法会被自动回调,handleMessage(Message msg)方法依然位于主线程,所以可以动态的修改ImageView的属性,从而实现动画效果。

我们要进一步了解Handler的工作原理,首先认识几个组件:
Message:Handler接收和处理的消息对象。
Looper:每个线程只能拥有一个Looper。它的loop方法负责读取MessageQueue中的消息,读到消息之后就把消息交给发送该消息的Handler进行处理。
MessageQueue:消息队列,它采用先进先出的方式来管理Message。程序创建Looper对象时会在它的构造器中创建Looper对象。
各自的作用为:
Looper:每个线程只有一个Looper,它负责管理MessageQueue,会不断的从MessageQueue中取出消息,并将消息分给对应的对应的Handler处理。
MessageQueue:由Looper负责管理,它采用先进先出的方式来管理Massage。
Handler:它能把消息发送给Looper管理的MessageQueue,并负责处理Looper分给它的消息。
在线程中使用Handler的步骤如下:*重点内容*
1、调用Looper的prepare()方法为当前线程创建Looper对象,创建Looper对象时,它的构造器会创建与之配套的MessageQueue。
2、有了Looper之后,创建Handler子类的实例,重写handleMessage()方法,该方法负责处理来自于其他线程的消息。
3、调用Looper的loop()方法启动Looper。
依然通过疯狂讲义上的一个实例来分析一下:

public class CalPrime extends Activity {
    static final String UPPER_NUM = "upper";
    EditText etNum;
    CalThread calThread;
    class CalThread extends Thread {
        public Handler mHandler;

        public void run()
        {
            Looper.prepare();
            mHandler = new Handler()
            {
                @Override
                public void handleMessage(Message msg)
                {
                    if(msg.what == 0x123)
                    {
                        int upper = msg.getData().getInt(UPPER_NUM);
                        List<Integer> nums = new ArrayList<Integer>();
                        outer:
                        for (int i = 2 ; i <= upper ; i++)
                        {
                            for (int j = 2 ; j <= Math.sqrt(i) ; j++)
                            {
                                if(i != 2 && i % j == 0)
                                {
                                    continue outer;
                                }
                            }
                            nums.add(i);
                        }
                        Toast.makeText(CalPrime.this , nums.toString()
                            , Toast.LENGTH_LONG).show();
                    }
                }
            };
            Looper.loop();
        }
    }
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        etNum = (EditText)findViewById(R.id.etNum);
        calThread = new CalThread();
        calThread.start();
    }
    public void cal(View source)
    {
        Message msg = new Message();
        msg.what = 0x123;
        Bundle bundle = new Bundle();
        bundle.putInt(UPPER_NUM ,
            Integer.parseInt(etNum.getText().toString()));
        msg.setData(bundle);
        calThread.mHandler.sendMessage(msg);
    }
}

不直接在UI线程中执行耗时操作,导致UI线程被阻塞,会引发ANR(程序无法响应),上面的代码在新线程中创建了一个Handler,创建Handler之前先创建Looper,并创建配套的MessageQueue,接下来创建了一个Handler对象,该Handler可以处理来自其他线程发送过来的信息,最后调用Looper的loop()方法。

你可能感兴趣的:(android,线程)