安卓学习-Handler

#安卓学习-Handler
##Handler
    1.更新UI的一套机制(解决多线程更新ui造成混乱,如果加锁同步性能又降低的问题)
    2.消息处理的机制(发送,处理)
##Handler中常用的方法
    
###1.post(Runnable r)
###2.postDelayed(Runnable r, long delayMillis)
###3.sendMessage(Message msg)
###4.sendMessageDelayed(Message msg, long delayMillis)
    1.post(Runnable r)
    直接在子线程中使用
    new Thread(){
            public void run() {
                
                handler.post(new Runnable() {
                    
                    @Override
                    public void run() {
                        tv_tv.setText("handler");
                        
                    }
                });
            };
        }.start();

    2.postDelayed(Runnable r, long delayMillis)(延迟执行)
      用法与post类似
      可用于隔一段时间无限执行某事
      如下图,tv中的内容1秒变化一次
      tv = ((TextView) findViewById(R.id.tv));
        ra = new Runnable(){
           @Override
           public void run() {
               i++;
               tv.setText(i+"");
               handler.postDelayed(ra, 1000);
           }
       };
        handler.postDelayed(ra, 1000);
    3.sendMessage(Message msg)
      在子线程中发送消息给主线程

         new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Message m = new Message();
                m.what = 0;
                m.obj = new Date();
                handler.sendMessage(m);
            }
        }.start();

        主线程中handler重写handleMessage(Message msg)处理传过来的消息
        Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            int a=msg.what;
        }
           };
    
    获得消息对象三种方式的差异
    一般使用bc两种方式
    a.Message m = new Message();无消息池,无handler关联
    b.Message.obtain();有消息池,无handler关联
     c.handler.obtainMessage();有消息池,有handler关联

    4.sendMessageDelayed(Message msg, long delayMillis)
    用法与postDelayed类似

##主线程与子线程相互发送消息(以下会出现空指针异常)
    实现一个与线程相关的handler
     class MyRunble implements Runnable {
        public Handler handlerThread;
        public Looper looper;

        @Override
        public void run() {
            //在其他线程中必须创建与该线程相关的Looper
           ** Looper.prepare();
            looper = Looper.myLooper();
            //子线程中的handler
            handlerThread = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    //子线程接收到消息后发送消息给主线程
                    handler.sendEmptyMessage(0);
                    Log.i("test", Thread.currentThread().getName());
                }
            };
            
            Looper.loop();**
        }
    }
    
    //主线程中的handler
     Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            //此时 myRunble可能为空,子线程中可能还没有创建对象
            //looper也可能为空
            //主线程接收到消息后发送消息给子线程
            myRunble.handlerThread.sendEmptyMessage(0);
        }
    };
    //开启子线程
     myRunble = new MyRunble();
     new Thread(myRunble).start();
    //给主线程发送空消息
     handler.sendEmptyMessage(0);
##主线程给子线程发送消息(多线程并发导致的空指针异常解决)
     HandlerThread ht=new HandlerThread("bbbbb");
     ht.start();
     Handler handlerThread = new Handler(ht.getLooper()){
         @Override
         public void handleMessage(Message msg) {
                Log.d("MainActivity", "子线程接收到消息了" + Thread.currentThread().getName());

        }
     };
    给子线程发送消息,此时不会出现空指针异常
     handlerThread.sendEmptyMessage(0);

    原理:ht开启后,子线程就开始执行run方法得到Looper
    ht.getLooper()中如果mLooper==null等待,直到不等于空时被唤醒。

##Handler中消息截获
    要截取使用这个构造 Handler(Callback callback)
    代码如下:
    public class MainActivity extends AppCompatActivity {
    Handler handler=new Handler(new Handler.Callback() {
        @Override
        //接收到消息后先走Callback里的这个方法,若果返回true则截断消息,false则由handler中的handleMessage(Message msg)处理消息。    
        public boolean handleMessage(Message msg) {
            Toast.makeText(MainActivity.this, "Callback", Toast.LENGTH_SHORT).show();
            return false;
        }
    }){
        @Override
        public void handleMessage(Message msg) {
            Toast.makeText(MainActivity.this, "我收到消息了", Toast.LENGTH_SHORT).show();
            super.handleMessage(msg);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //发送消息
        handler.sendEmptyMessage(0);
    }

}
##总结
    1.handler负责发送和处理消息。
    2.Looper负责接收Handler发送的消息,并直接把消息回传给Handler自己。
    3.MessageQueue为消息列队,为储存消息的容器。
    4.在应用创建的时候,就已经创建了与UI线程相关的Looper,所以主线程中创建的无参的Handler,            默认与主线程相关的Looper相关联。   
    5.调用方法的Handler和哪个线程的Looper相关联,其消息就在哪个线程中处理。
##常见异常
    //在非主线程中更新UI
    1.android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
    //在子线程中创建handler之前没有先调用Looper.prepare()
    2.Can't create handler inside thread that has not called Looper.prepare()
##在子线程中更新UI的几种方法(本质都是handler发送和处理消息(底层源码))
    1.runOnUiThread(Runnable action)
    2.handler.sendMessage(Message msg)
    3.handler.post(Runnable r)
    4.View.post(Runnable action) 
##不能在非主线程中更新UI的底层原因(源代码)
    更新ui的时候会调用View的invalidate()方法,
    在这个方法中如果ViewParent不为null就检查当前线程是否为主线程,如果不为主线程就抛出异常,
    而ViewParent为ViewRootImpl的实现类,
    ViewRootImpl是在activity的onResume()中初始化的。
    (所以在ViewRootImpl初始化之前,在子线程中可以直接更新ui而不会抛出异常,一般不建议使用)
    
    
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值