zoukankan      html  css  js  c++  java
  • Android-Handler+Message-消息机制

    我的理解是,子线程要和主线程通讯,就需要Handler+Message-消息机制


    案例一:倒计时Demo(子线程+Handler+Message)

    package liudeli.async;
    
    import android.os.Handler;
    import android.os.Message;
    import android.os.SystemClock;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.TextView;
    
    public class MainActivity extends AppCompatActivity {
    
        private TextView tvInfo;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            tvInfo = findViewById(R.id.tv_info);
        }
    
        /**
         * 定义Handler
         */
        private Handler mHandler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
    
                if (msg.obj != null) {
                    tvInfo.setText(msg.obj.toString());
                    return;
                }
    
                tvInfo.setText(msg.what + "");
            }
        };
    
        /**
         * 耗时操作不能在主线程 定义主线程
         */
        private class MyTimeing implements Runnable {
    
            @Override
            public void run() {
                for (int i = 10; i >= 0; i--) {
                    // mHandler.obtainMessage(i); 这种消息池方式获取Message消耗小
                    Message message = mHandler.obtainMessage(i); // what 其实就是ID的意思,唯一标示
                    if (i <= 0) {
                        // obj 是Object 什么类型都可以传递: 传递T类型,获取的时候就强转T类型
                        message.obj = "倒计时完成✅";
                    }
                    // 用Android提供的睡眠方法,其实是封装来Thread.sleep
                    SystemClock.sleep(1000);
    
                    // 从子线程 发送消息 到---> 主线程的handleMessage方法
                    mHandler.sendMessage(message);
                }
            }
        }
    
        /**
         * 执行倒计时
         * @param view
         */
        public void timeing(View view) {
            // 主线程被阻塞 5秒 未响应,系统就会自动报错 ANR Application Not Responding
            /**
             * Android系统中,ActivityManagerService(简称AMS) 和 WindowManagerService(简称WMS)会检测App的响应时间
             * 如果App在特定时间无法响应屏幕触摸或键盘输入事件,或者特定事件没有处理完毕,就会出现ANR
             */
            // 启动自行车来做耗时操作
            new Thread(new MyTimeing()).start();
        }
    }
    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:gravity="center">
    
            <TextView
                android:id="@+id/tv_info"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="0000000"
                android:layout_gravity="center_vertical"
                android:textSize="20sp"
                android:layout_marginLeft="10dp"
                />
    
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="倒计时"
                android:onClick="timeing"
                android:layout_gravity="right"
                />
    
        </LinearLayout>
    
    </RelativeLayout>


    案例二:文字变化(Handler+Message)

    package liudeli.async;
    
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.os.SystemClock;
    import android.support.v7.app.AppCompatActivity;
    import android.view.View;
    import android.widget.TextView;
    
    public class MainActivity2 extends AppCompatActivity {
    
        private TextView tvInfo;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main2);
    
            tvInfo = findViewById(R.id.tv_info);
        }
    
        private int count;
    
        /**
         * 定义Handler
         */
        private Handler mHandler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
    
                if (msg.obj == null) {
                    return;
                }
                if (msg.what <= 7) {
                    tvInfo.setText(msg.obj.toString() + "");
                    Message message = mHandler.obtainMessage();
                    message.what = count++;
                    message.obj = "竟然渐渐清晰  想要说些什么  又不知从何说起" + count;
                    mHandler.sendMessageDelayed(message, 900);
                }
    
            }
        };
    
        /**
         * 执行文字变化
         * @param view
         */
        public void textChange(View view) {
            // mHandler.obtainMessage(i); 这种消息池方式获取Message消耗小
            Message message = mHandler.obtainMessage();
            message.what = 1;
            message.obj = "从那遥远海边  慢慢消失的你  本来模糊的脸";
            // 从主线程 发送消息 到---> 主线程的handleMessage方法
            mHandler.sendMessageDelayed(message, 800);
            count = 0;
        }
    }
    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:gravity="center">
    
            <TextView
                android:id="@+id/tv_info"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Test"
                android:layout_gravity="center_vertical"
                android:textSize="20sp"
                android:layout_marginLeft="10dp"
                />
    
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="文字变化"
                android:onClick="textChange"
                android:layout_gravity="right"
                android:layout_marginTop="20dp"
                />
    
        </LinearLayout>
    
    </RelativeLayout>


     注意:⚠️在Activity的 onDestroy() 方法中,一定要记得回收

    postDelayed 看似子线程,其实是属于主线程,postDelayed能延时run,但不能在子线程中执行,否则报错

    这个开启的Runnable会在这个Handler所依附线程中运行,而这个Handler是在UI线程中创建的,所以自然地依附在主线程中了。

      /**
         * 参数一:可以在Runnable中执行UI操作
         * 参数二:延时时间 毫秒
         * new Handler().postDelayed(Runnable r, long delayMillis);
         * @param view
         */
        public void test(View view) {
    
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(MainActivity2.this, "postDelayed", Toast.LENGTH_LONG).show();
                }
            }, 2000);
    }

    子线程 send 到 主线程 的常用方法

         // 参数一:Message消息,可传递数据
            // 参数二:delayMillis延时时间,延时多久才send,毫秒为单位
            // 特点是:send Message消息,并可设置延时时间
            // sendMessageDelayed(Message msg, long delayMillis)
    
            // 参数一:Message消息,可传递数据
            // 特点是:立即send,不延时
            // mHandler.sendMessage(Message msg)
    
            // 参数一:唯一标识what
            // 参数二:delayMillis延时时间,延时多久才send,毫秒为单位
            // 特点是:send 唯一标识what,并可设置延时时间
            // mHandler.sendEmptyMessageDelayed(int what, long delayMillis)
    
            // 参数一:唯一标识what
            // 特点是:send 唯一标识what,立即send
            // mHandler.sendEmptyMessage(int what)

    消息池的概念:

       Android操作系统启动后默认会有很多的消息池,这样的方式直接到系统里面消息池拿消息mHandler.obtainMessage(), 而new Message(); 是实例化消息(消耗多些) 

         推荐用mHandler.obtainMessage()方式


    面试题:postDelayed(Runnable r) Runnable 是属于子线程吗?

    答:和子线程没有半毛钱关系,命名叫Runnable而已,子线程必须是 有run方法,有.start();

         new Thread(){
                @Override
                public void run() {
                    super.run();
                }
            }.start();

    按原理来说:子线程是不能执行UI操作,确实不能执行UI操作,但Android设计了API看起来可以在子线程(这是假象),实际是对Handler+Message进行了封装

    /**
         * 在子线程中操作UI
         * @param view
         */
        public void uiRun(View view) {
            new Thread(){
                @Override
                public void run() {
                    super.run();
                    /**
                     * 第一种方式
                     */
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(MainActivity2.this, "runOnUiThread", Toast.LENGTH_LONG).show();
                        }
                    });
    
                    /**
                     * 第二种方式
                     */
                    Looper.prepare();
                    Toast.makeText(MainActivity2.this, "Looper", Toast.LENGTH_LONG).show();
                    Looper.loop();
                }
            }.start();
        }
  • 相关阅读:
    解决多版本sdk兼容问题
    ios5 UIKit新特性
    iPhone网络编程–一起来做网站客户端(一)
    八数码
    IOS开发中编码转换
    修复ipa图片png方法
    创建易读链接 搭建应用通往App Store的桥梁
    如何让IOS应用从容地崩溃
    详解IOS IAP
    jquery创建并行对象或者叫合并对象
  • 原文地址:https://www.cnblogs.com/android-deli/p/10113627.html
Copyright © 2011-2022 走看看