• 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);
            }
    }
  • 相关阅读:
    Linux 实用指令(5)--组管理和权限管理
    Linux 实用指令(4)
    Linux用户管理 (3)
    Oracle如何用单字段或多字段进行查重
    SQL中的左连接与右连接,内连接有什么不同
    Markdown语法--整理
    应用程序无法正常启动0xc000007b
    Linux开机、重启和用户登录注销(2)
    Linux vi和vim编辑器(1)
    SecureCRT 64位 破解版和安装,以及解决乱码问题
  • 原文地址:https://www.cnblogs.com/vijay/p/3536000.html
Copyright © 2020-2023  润新知