zoukankan      html  css  js  c++  java
  • TII--Android技术篇Handler

    零、前言

    Handler也是个磨人的小妖精,一次又一次的败给她,现在总结一下用法
    Handler最主要的作用就是子线程更新UI的问题。
    Handler使用并不难,背后的一套机制理解起来怪麻烦,而且很重要。


    一、还是以最经典的:子线程更新UI来引入吧

    场景:点击按钮新建线程,在新线程里更改TextView的值,如下图

    9414344-73d33337ec8f9ef6.png
    handler1.png
    1、准备工作:
    public class HandlerActivity extends AppCompatActivity {
        private static final String TAG = "HandlerActivity";
        @BindView(R.id.id_tv_handler)
        TextView mIdTvHandler;
        @BindView(R.id.id_btn_change)
        Button mIdBtnChange;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
    
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_handler);
            ButterKnife.bind(this);
            Log.e(TAG, "onCreate: " + Thread.currentThread().getName());//main
        }
    
        @OnClick(R.id.id_btn_change)
        public void onViewClicked() {
            //新建线程
            new Thread() {
                @Override
                public void run() {
                    Log.e(TAG, "onViewClicked: " + Thread.currentThread().getName());//Thread-24375
                     mIdTvHandler.setText("你身上有米粒!");//更改视图
                }
            }.start();
        }
    }
    
    
    2.结果:
    9414344-f1ebb954395ef061.png
    结果.png

    看起来不太好,直接崩了,报了个CalledFromWrongThreadException:只有创建视图层的那个原始线程(main)才给摸他的视图。
    是啊,我穿(main线程)的衣服(View)凭什么给你(其他线程)乱摸(修改...),你又不是我女朋友。

    android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
    

    二、Handler的使用

    人家(其他线程)就是看你衣服上有个米粒,想把他拿掉,你(main线程)还不乐意了。好吧,我找你女友(Handler)去,让她把你拿掉

    
    public class HandlerActivity extends AppCompatActivity {
        private static final String TAG = "HandlerActivity";
        @BindView(R.id.id_tv_handler)
        TextView mIdTvHandler;
        @BindView(R.id.id_btn_change)
        Button mIdBtnChange;
        //新建Handler
        private Handler mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                String info = (String) (msg.obj);
                //更新UI
                mIdTvHandler.setText(info);
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_handler);
            ButterKnife.bind(this);
        }
    
        @OnClick(R.id.id_btn_change)
        public void onViewClicked() {
            new Thread() {
                @Override
                public void run() {
                    //拿到一个Message对象--或直接new,但不建议new。Message.obtain()使用享元模式
                    Message msg = Message.obtain();
                    //将数据放到信息里
                    msg.obj = "你身上有米粒!";
                    //发送消息
                    mHandler.sendMessage(msg);
                    
                    //或者
                    //msg.obj = "你身上有米粒";
                    ////使用handler.obtainMessage获得的msg 可以直接msg.sendToTarget()
                    //msg.sendToTarget();
                }
            }.start();
        }
    }
    
    9414344-a55e4b586ae059b6.png
    handler2.png

    二、发送空消息

    9414344-93051226c67cf3e1.png
    empty.png
    1.空消息
    1-1:空消息要有一个标识
    private int SEND_ID = 0;
    
    1-2:发送空消息:
    new Thread() {
         @Override
         public void run() {
             mHandler.sendEmptyMessage(SEND_ID);
         }
     }.start();
    
    1-3:Handler根据接收的标识执行动作
     private Handler mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                if (msg.what == SEND_ID) {
                    mIdTvHandler.setText("你身上有米粒!");
                }
            }
        };
    
    2.延迟空消息
     mHandler.sendEmptyMessageDelayed(SEND_ID,1000);
     //或:mHandler.sendEmptyMessageAtTime(SEND_ID, SystemClock.uptimeMillis()+1000);
    
    9414344-ccc782149571fb85.gif
    延迟.gif
    3.同样sendMessage延迟类似:
    mHandler.sendMessageDelayed(msg, 1000L);
    mHandler.sendMessageAtTime(msg, SystemClock.uptimeMillis()+1000);
    

    三、post发送消息:传入Runnable

    9414344-8b058ffa8608dcae.png
    post.png

    通过mHandler反复发信息可做到循环

    mRunnable = new Runnable() {
        @Override
        public void run() {
            index++;
            mIdTvHandler.setText("你身上有"+index+"個米粒");
            if (index < 10) {
                mHandler.postDelayed(this, 2000);
            }
        }
    };
    
    new Thread(){
        @Override
        public void run() {
            mHandler.postDelayed(mRunnable, 2000);
        }
    }.start();
    
    移除callback
    if (mRunnable != null) {
        mHandler.removeCallbacks(mRunnable);
    }
    

    四、Activity方法:runOnUiThread

    可见底层也是基于Handler机制的

    9414344-3a73f868156d9bbb.png
    runout.png
    new Thread(){
        @Override
        public void run() {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mIdTvHandler.setText("你身上有米粒!");
                }
            });
        }
    }.start();
    

    五、Handler和Timer结合

    public class HandlerTimerActivity extends AppCompatActivity {
        private static final String TAG = "HandlerActivity";
        @BindView(R.id.id_tv_handler)
        TextView mIdTvHandler;
        @BindView(R.id.id_btn_change)
        Button mIdBtnChange;
    
        private final Timer timer = new Timer();
        private TimerTask task;
        int count = 0;
    
        Handler mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                mIdTvHandler.setText("你身上有" + count + "個米粒!");
                super.handleMessage(msg);
            }
        };
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
    
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_handler);
            ButterKnife.bind(this);
    
        }
    
        @OnClick({R.id.id_tv_handler, R.id.id_btn_change})
        public void onViewClicked(View view) {
            switch (view.getId()) {
                case R.id.id_tv_handler:
                    timer.cancel();
                    
                    break;
                case R.id.id_btn_change:
    
                    task = new TimerTask() {
                        @Override
                        public void run() {
                            mHandler.sendEmptyMessage(0);
                            count++;
                        }
                    };
                    timer.schedule(task, 2000, 3000);
                    break;
            }
        }
    }
    
    

    后记、

    1.声明:

    [1]本文由张风捷特烈原创,转载请注明
    [2]欢迎广大编程爱好者共同交流
    [3]个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正
    [4]你的喜欢与支持将是我最大的动力

    2.连接传送门:

    更多安卓技术欢迎访问:安卓技术栈
    我的github地址:欢迎star
    简书首发,腾讯云+社区同步更新
    张风捷特烈个人网站,编程笔记请访问:http://www.toly1994.com

    3.联系我

    QQ:1981462002
    邮箱:1981462002@qq.com
    微信:zdl1994328

    4.欢迎关注我的微信公众号,最新精彩文章,及时送达:
    9414344-c474349cd3bd4b82.jpg
    公众号.jpg
  • 相关阅读:
    Eclipse中配置约束
    c++ 虚函数
    cocos3 menu
    cocos3 封装一个ball
    cocos3 内存管理机制
    cocos3 多文件拆分cocos
    cocos3 labelttf
    cocos3 messagebox
    cocos3 log
    cocos3 director sprite scene之间的关系
  • 原文地址:https://www.cnblogs.com/toly-top/p/9781892.html
Copyright © 2011-2022 走看看