Android-----Handler

Android开发过程中为什么要多线程?

答:我们创建的Service、Activity以及Broadcast均是一个主线程处理,这里我们可以理解为UI线程。但是在操作一些耗时操作时,比如I/O读写的大文件读写,数据库操作以及网络下载需要很长时间,为了不阻塞用户界面,出现ANR的响应提示窗口,这个时候我们可以考虑使用Thread线程来解决。

 

 

Android中使用Thread线程会遇到哪些问题?

答:对于Android平台来说UI控件都没有设计成为线程安全类型,所以需要引入一些同步的机制来使其刷新,这点Google在设计Android时倒是参考了下Win32的消息处理机制。

 

 

Handler原理:Handler主要接受子线程发送的数据,并用此数据配合主线程更新UI.

    当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI控件,进行事件分发,比如说,你要是点击一个 Button ,Android会分发事件到Button上,来响应你的操作。  如果此时需要一个耗时的操作,例如:联网读取数据, 或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,,如果你放在主线程中的话,界面会出现假死现象,如果5秒钟还没有完成的话,,会收到Android系统的一个错误提示  "强制关闭".  这个时候我们需要把这些耗时的操作,放在一个子线程中,因为子线程涉及到UI更新,,Android主线程是线程不安全的,也就是说,更新UI只能在主线程中更新,子线程中操作是危险的.这个时候,Handler就出现了,来解决这个复杂的问题, 由于Handler运行在主线程中(UI线程中),  它与子线程可以通过Message对象来传递数据,这个时候,Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传弟)Message对象,(里面包含数据)  ,把这些消息放入主线程队列中,配合主线程进行更新UI。

 

Handler一些特点:handler可以分发Message对象和Runnable对象到主线程中,每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程),它有两个作用: (1)安排消息或Runnable在某个主线程中某个地方执行
                     (2)安排一个动作在不同的线程中执行

 

Handler中分发消息的一些方法
         post(Runnable)
        postAtTime(Runnable,long)
        postDelayed(Runnable long)
        sendEmptyMessage(int)
        sendMessage(Message)
        sendMessageAtTime(Message,long)
        sendMessageDelayed(Message,long)
  以上post类方法允许你排列一个Runnable对象到主线程队列中,sendMessage类方法,允许你安排一个带数据的Message对象到队列中,等待更新.

 

Handler的用法:
 
Handler的基本概念
        包含线程队列和消息队列,实现异步的消息处理机制,跟web开发的ajax有异曲同工之妙。
创建一个Handler对象

Handler handler = new Handler();

 

将要执行的操作写在线程对象的run方法当中

Runnable updateThread = new Runnable(){
    public void run(){
        handler.postDelayed(updateThread,3000);
    }
}

 

 

一个点击监听事件,在handler中添加要执行的线程

Class StartButtonListener implements OnClickListener{
    public voidonClick(View v){
        //调用Handler的post方法,将要执行的线程对象添加到队列中
        handler.post(updateThread);
        }
}

 

 

一个点击监听事件,在handler中把线程移除

Class EndButtonListerger implements OnClickListener(){
    public void onClick(View v){
        handler.removeCallBacks(updateThread);
        }
}

 

使用Handler更新ProgressBar的方法
分别使用:
updateBarHandler.post(updateThread);
updateBarHandler.sendMessage(msg);
传递线程和消息。
通过Handler的handleMessage()方法处理消息。
 
首先使用匿名内部类来复写Handler当中的handlerMessage方法,该方法用于接收消息

Handler updateBarHandler = new Handler(){
    public void handleMessage(Message msg){
        bar.setProgress(msg.arg1);
        updateBarHandler.post(updateThread);
        }
};

 

创建一个线程类,用于控制进度条的进度,该类使用匿名内部类的方式进行声明

Runnable updateThread = new Runnable(){
    int i = 0;
    public void run(){
        i = i + 10;
        Message msg = updateBarHandle.obtainMessage();
        msg.arg1 = i;
        try{
            Thread.sleep(1000);
                } catch(InterruptedException e) {
                    e.printStackTrack();
                }
                //将msg对象加入到消息队列
                updateBarHandler.sendMessage(msg);
                if( i == 100){
                    updateBarHandler.removeCallbacks(updateThread);
                }
        }
}

 

点击按钮事件,加入队列,启动线程

class ButtonListener implements OnClickListener{
    public void onClick(View v){
        bar.setVisibility(View.VISIBLE);
        //线程队列
        updateBarHandler.post(updateThread);
    }
}

 

Handler中使用单独的线程
 
需要使用public Handler (Looper looper)
构造函数创建Handler对象。从而实现使用Looper来处理消息队列的功能。借助Bundle使用Message传递数据。
当使用
handler.post(new Runnable);
时Handler和Activity处于同一个线程当中,在同一个线程中调用run方法。
而使用
Thread t = new Thread(new Runnable());
t.start();
创建的线程和Activity处于不同的线程中

 

Bundle的用法

可以把Bundle看成是特殊的map,所有的key都是String类型的

在新线程当中处理消息的方法

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    //打印当前线程的ID
    System.out.println(Thread.currentThread().getId());
    //生成一个HandlerThread对象,实现了Looper来处理消息队列的功能,这个类由android应用框架提供
    HandlerThread handlerThread = new HandlerThread("hanlderThread");
    //必须先调用该类的start的方法,否则该获取的Looper对象为NULL
    handlerThread.start();
    MyHanlder myHandler = new MyHandler(handlerThread.getLooper());
    Message msg = myHandler.obtainMessage();
    Bundle bundle = new Bundle();
    bundle.putString("name","arthinking");
        msg.setData(b);
    msg.sendToTarget();
}

class MyHandler extends Handler{
    public MyHandler(){}
    public MyHandler(Looper looper){
        super(looper);
        }
        //每当有消息进入消息队列时就执行这个函数对消息进行操作
        public void handleMessage(Message msg){
            Bundle bundle = msg.getData();
            String name = bundle.getString("name");
            System.out.println(Thread.currentThread().getId());
            System.out.println(name);
        }
}

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。