android之handler使用与原理

来源:互联网 发布:简述网络安全技术 编辑:程序博客网 时间:2024/06/13 15:17

下面的是个人对handler的一些感想,忘能帮助初学者
handler是什么
handler是android系统提供的一套消息机制的上层接口,使用handler可以轻松地切换任务线程那它可以用来干嘛呢。
当需要在子线程中进行耗时的I/O操作的时候,当耗时任务完成以后,需要在UI上做一些改变,但是在子线程不能访问handler这时就要使用handler。要记住一点,handler不是专门用来更新UI的。
接下来介绍几个概念。
MessageQueue
它是用来存储消息的,注意它是单链表的数据结构。
Looper
消息循环者,用来取MessageQueue的消息并处理,没消息阻塞。
好了,接下来慢慢介绍。
不知大家注意到了没子线程访问UI会报异常,这是因为不能再子线程更新UI,那么android是怎么确定的呢,因为ViewRootImpl会对UI操作进行验证,是由ViewRootImpl的checkThread来完成的。因此大家也别想着用什么办法绕过了,因为系统已经强制规定了。
Handler在创建的时候会用当前线程的Looper来构建消息循环系统,因此在子线程中直接使用Handler会报错,因为子线程是没有Looper的,那UI线程有没有呢,UI线程会在ActivityThread创建UI线程的时候初始化一个Looper,这也是主线程可以使用handler的原因,要在子线程使用handler,要先出初始化Looper,调用Looper.perpar()即可当调用handler的send方法时,它会调用MessageQueue的enqueueMessage()方法将消息放到队列中去,Looper发现有新消息时会处理消息,最终消息中的Runnable或者handler的handleMessage会调用。
这里要知道Looper是存储在ThreadLocal中的,它是一个作用域为当前线程的存储类。底下是个例子

 public class TestHandlerActivity extends AppCompatActivity {        private static final String TAG = "TestHandlerActivity";        private Handler mHandler = new Handler(){            @Override            public void handleMessage(Message msg) {                super.handleMessage(msg);                //获得刚才发送的Message对象,然后在这里进行UI操作                Log.e(TAG,"------------> msg.what = " + msg.what);            }        };        @Override        protected void onCreate(Bundle savedInstanceState) {            super.onCreate(savedInstanceState);            setContentView(R.layout.activity_handler_test);            initData();        }        private void initData() {            //开启一个线程模拟处理耗时的操作            new Thread(new Runnable() {                @Override                public void run() {                    SystemClock.sleep(2000);                    //通过Handler发送一个消息切换回主线程(mHandler所在的线程)                    mHandler.sendEmptyMessage(0);                }            }).start();        }   

这是一个很简单的例子,接下来再看用post方法发送已个Runnable接口的方法。

public class MainActivity extends Activity {    private TextView text_view = null;    private Button start = null;    private Button end = null;    //使用handler时首先要创建一个handler    Handler handler = new Handler();    //要用handler来处理多线程可以使用runnable接口,这里先定义该接口    //线程中运行该接口的run函数    Runnable update_thread = new Runnable()    {        public void run()        {            //线程每次执行时输出"UpdateThread..."文字,且自动换行            //textview的append功能和Qt中的append类似,不会覆盖前面            //的内容,只是Qt中的append默认是自动换行模式            text_view.append("\nUpdateThread...");            //延时1s后又将线程加入到线程队列中            handler.postDelayed(update_thread, 1000);        }    };    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        text_view = (TextView)findViewById(R.id.text_view);        start = (Button)findViewById(R.id.start);        start.setOnClickListener(new StartClickListener());        end = (Button)findViewById(R.id.end);        end.setOnClickListener(new EndClickListener());    }    private class StartClickListener implements OnClickListener    {        public void onClick(View v) {            // TODO Auto-generated method stub            //将线程接口立刻送到线程队列中            handler.post(update_thread);        }                    }    private class EndClickListener implements OnClickListener    {        public void onClick(View v) {            // TODO Auto-generated method stub            //将接口从线程队列中移除            handler.removeCallbacks(update_thread);        }    }    @Override    public boolean onCreateOptionsMenu(Menu menu) {        getMenuInflater().inflate(R.menu.activity_main, menu);        return true;    }}

接下来各自分析一下
MessageQueue
它主要用来存储消息,有两个基本操作,插入和读取,读取操作会伴随着删除操作,当Handler发送一条消息时会调用他的enqueueMessage方法插入消息,此时有了一条消息,接着它会调用自身的next方法读取消息并从队列中(数据结构是单链表)删除消息,接着Looper发现有消息就会把它交给handler去处理,handler调用自身的handlermessage()方法,这里要注意我们可以通过getMainLooper()得到UI现成的Looper,当在子线程创建Looper不用的时候要调用他的quitsafely()方法,否则Looper会一直阻塞。
好了,这就是消息处理机制了。

1 0
原创粉丝点击