Days 19 Handler

本文详细介绍了Android中的Handler机制,包括Handler的基本概念、工作原理及其应用场景。此外,还提供了多个实例演示如何利用Handler在子线程与主线程间进行消息传递,以实现对UI的操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、什么是Handler?
Handler通俗来讲就是用来在各个线程之间发送数据的处理对象。在B线程中,只要获得A线程的Handler,就可以通过handler.sendMessage(messge)方法向A线程发送数据。而当B线程处理完一些耗时操作后,A线程可以通过handler的handlerMessage()方法获得数据
2、主线程
运行所有UI组件。如果任何一个消息用时超过5秒,Android将抛出Application Not Responding,所以一个任务用时超过5秒,应该在一个独立线程中完成它,或者延迟处理它。
子线程没有办法对UI界面的内容进行操作,如果操作,将抛出CalledFromWrongThreadException。为了实现子线程中操作UI界面,Android中引入了Handler消息传递机制。至此,我们学过的子线程操作UI界面的方法有:1、异步任务;2、Loader;3、Handler
3、常用类
a、Handler :处理者,负责Message的发送及处理。主要作用:1、在工作线程中发送消息;2、在主线程中获取并处理消息。
b、Message:消息,其中包含了消息标识,消息处理对象以及处理的数据。由MessageQueue统一列队,最终由Handler处理
c、MessageQueue:消息队列,将Message串联起来,等到Looper的抽取,按照FIFO规则(先进先出)
d、Looper:消息泵,不断的从MessageQueue中抽取Message执行。一个MessageQueue需要对应一个Looper
4、常用类的方法及属性
a、Handler类
1、handleMessage()用在主线程中(可以根据获得的消息更新UI),构造Handler对象时,重写handleMessage()方法,根据工作线程返回的消息标识,获得消息并执行相应操作
2、sendEmptyMessage()用在工作线程中,发送空消息
3、sendMessage()用在工作线程中,将消息(Message对象)发送(给主线程)
b、Message类
1、arg1,arg2 用来存放整型数据,可节省系统资源arg1 and arg2 are lower-cost alternatives to using
2、obj 用来存放Object数据
3、what 就是一个消息的标记,用来区分消息,为int类型
b、Message类
1、message虽然可以通过new Message()方法获得,但是通常使用Message.obtain()方法或handler.obtainMessage()方法从消息池中获得空消息对象,节省系统资源
2、arg1、arg2 若传递的数据为int型,用此属性,节省内存
3、what 就是用于识别消息的标记
4、如果需要从工作线程返回很多消息信息,可以借助Bundle对象将这些数据集中在一起,放在obj属性中
5、备注:
a、通过getResource().getAssets().open(“文件名”);返回值为InputStream,以流的形式打开assets目录下的文件
b、Looper对象用来为一个线程开启一个消息循环,从而操作MessageQueue;
默认情况下,Android创建的线程没有开启消息循环Looper,但是主线程例外。
系统自动为主线程创建Looper对象,开启消息循环;
所以主线程中使用new来创建Handler对象。而子线程中不能直接new来创建Handler对象就会异常。
子线程中创建Handler对象,步骤如下:
Looper.prepare();
Handler handler = new Handler() {
//handlemessage(){}
}
Looper.loop();
Demo1:
构造Handler对象

private Handler handler = new Handler() {
        // 现在在主线程中,故可以更新UI(是主线程的接收处理方法)
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case 1:
                txtShow.setText(msg.arg1 + "  " + msg.arg2 + "  " + msg.obj);
                break;

            default:
                break;
            }
        };
    };

子线程:

new Thread() {
            public void run() {
                int count = 0;
                while (count < 100) {
                    Message message = new Message();

                    // message.what值为int类型,就是一个消息的标识,用来区分消息
                    message.what = 1;
                    // arg1,arg2可以传递整数类型,节省系统资源
                    // arg1 and arg2 are lower-cost alternatives to using
                    message.arg1 = count;
                    message.arg2 = count * 10;
                    // 用来存放非整形数据
                    message.obj = "count = " + count;

                    // (子线程中)通过handler对象的sendMessage()方法将消息(Message对象)发送(给主线程)
                    handler.sendMessage(message);

                    count++;
                    SystemClock.sleep(1000);
                }
            };
        }.start();

Demo2:
子线程下载图片数据,传给主线程更新UI
构建Handler对象

private Handler handler = new Handler() {
        //主线程handler对象根据message的不同标识采取相应操作
        @Override
        public void handleMessage(Message msg) {
            /**
             * 所犯错误:
             * pdShow若在外面创建,因为要走三遍handleMessage()方法,所以会创建三个pdShow
             * 而case 2的dismiss()只关闭了第三个Show()
             */
//          pdShow = new ProgressDialog(MainActivity.this);
            switch (msg.what) {
            //工作线程发送what为0,代表工作线程开启;主线程相应显示对话框
            case 0:
                pdShow = new ProgressDialog(MainActivity.this);
                pdShow.setTitle("title");
                pdShow.setIcon(R.drawable.ic_launcher);
                pdShow.setMessage("洪荒之力已开启");

                pdShow.show();
                break;

            //工作线程发送what为1,将代表需要的数据加载完毕,通过Message对象获得数据
            case 1:
                ivShow.setImageBitmap((Bitmap) msg.obj);
                break;
            //工作线程发送what为2,代表工作线程执行完毕,关闭对话框
            case 2:
                pdShow.dismiss();
                break;
            default:
                break;
            }

        }
    };

子线程:

public void start(View v) {
        new Thread() {
            public void run() {

                //当工作线程刚开始时,希望显示进度对话框,此时让handler发送一个空消息即可
                handler.sendEmptyMessage(0);

                byte[] data = OkHttpUtils.getByteArrayByUrl(url);

                Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0,
                        data.length);

                //Message虽然可以通过new来获取,
                //但是通常使用Message.obtain()方法或handler.obtainMessage()方法
                //来从消息池中获得空消息对象,以节省资源
                Message msg = Message.obtain();
                msg.what = 1;
                msg.obj = bitmap;

                handler.sendMessage(msg);

//              SystemClock.sleep(6000);
                //当工作线程执行完毕,希望关闭进度对话框,此时让handler发送一个空消息即可
                handler.sendEmptyMessage(2);
            };
        }.start();
    }

Demo3:
子线程不断发送图片的偏移量,主线程中(根据图片位置)设置使图片偏移

public class MainActivity extends Activity {

    private ImageView ivShow = null;
    private float x, y;
    //错误:这样声明falgX为false,flagY为true
//  private boolean flagX , flagY = true;
    private boolean flagX = true;//标志图片是否往上走
    private boolean flagY = true;

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
            case 1:
                if (x > 400) {
                    flagX = false;
                } else if (x < 10) {
                    flagX = true;
                }

                if (flagX) {
                    x += msg.arg1;
                } else {
                    x -= msg.arg1;
                }

                if (flagY) {
                    flagY = false;
                    y += msg.arg2;
                } else {
                    flagY = true;
                    y -= msg.arg2;
                }
                ivShow.setX(x);
                //在这里,y方向的正方向为向下,所以y += msg.arg2后,setY(y)向下移动
                ivShow.setY(y);
                break;

            default:
                break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();
    }

    private void initView() {
        ivShow = (ImageView) findViewById(R.id.ivShow);

        //在onAttachedToWindow()方法之前,ImageView都没有显示在屏幕上,所以getX()为0
        /**
         * onAttachedToWindow()方法,将控件显示在界面上
         */
//      x = ivShow.getX();
//      y = ivShow.getY();
    }

    public void play(View v) {
        //获得ivShow离父容器左边缘距离
        x = ivShow.getX();
        y = ivShow.getY();
        new Thread() {
            public void run() {
                while (!Thread.interrupted()) {
//                  Message msg = handler.obtainMessage();
                    Message msg = Message.obtain();

                    msg.arg1 = 10;
                    msg.arg2 = 50;
                    msg.what = 1;

                    handler.sendMessage(msg);
                    //生成100到600之间的随机数
                    SystemClock.sleep(new Random().nextInt(500)+100);
                }
            };
        }.start();
    }

}

Demo4:
设置一个页面,每一秒切换一张图片同时中间有秒倒计时

public class MainActivity extends Activity {

    private TextView txtShow = null;
    private ImageView ivShow = null;
    private List<Drawable> list = null;

    private boolean flag = true;
    private int index = 0;
    private int remain = 60;

    private Handler clockHandler = new Handler();

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
            case 0:
                ivShow.setImageDrawable(list.get(index++));

                if (index == list.size()) {
                    index = 0;
                }
                break;

            default:
                break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();

        setData();

        switchImage();

        setTime();
    }

    private void setTime() {
        new Thread() {
            public void run() {
                /** 
                 * 通过handler的post方法将Runnable对象发送到消息队列中
                 * 该Runnable将附加在当前handler定义的线程中即主线程中执行
                 * 此处如果使用的handler为设置图片的handler,则设置图片与设置时间会有先后(添加在一个队列中)
                 */
                clockHandler.post(new Runnable() {

                    @Override
                    public void run() {
                        remain--;

                        if (remain < 0) {
                            flag = false;
                            txtShow.setText("还看");
                        } else {
                            txtShow.setText("remain:" + remain);
                        }
                        /**
                         * handler的postDelayed(Runnable,delay)方法,
                         * 将此Runnable对象发送到消息队列中,延时delay时间后run
                         */
                        clockHandler.postDelayed(this, 1000);
                    }
                });
            };
        }.start();
    }

    private void switchImage() {
        new Thread() {
            public void run() {
                while (flag) {
                    Message msg = Message.obtain();

                    handler.sendEmptyMessage(0);

                    SystemClock.sleep(1000);
                }
            };
        }.start();
    }

    private void setData() {
        // getResources().obtainTypedArray()根据普通数组资源名称获取实际普通数组
        // 获得资源文件中TypeArray对象
        TypedArray typedArray = getResources().obtainTypedArray(
                R.array.arraysImgs);

        list = new ArrayList<Drawable>();
        for (int i = 0; i < typedArray.length(); i++) {
            list.add(typedArray.getDrawable(i));
        }
    }

    private void initView() {
        txtShow = (TextView) findViewById(R.id.txtShow);
        ivShow = (ImageView) findViewById(R.id.ivShow);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值