Skip to content

应用场景

Handler是一种异步消息传递机制,最基本的应用场景就是更新UI。其他的应用实例场景

  1. 传递消息更新UI
  2. 倒计时的View的实现
  3. 结合IntentService的使用

传递消息更新UI

代码转载自:https://www.jianshu.com/p/e172a2d58905

java
/** 
  * 方式1:新建Handler子类(内部类)
  */

    // 步骤1:自定义Handler子类(继承Handler类) & 复写handleMessage()方法
    class mHandler extends Handler {

        // 通过复写handlerMessage() 从而确定更新UI的操作
        @Override
        public void handleMessage(Message msg) {
         ...// 需执行的UI操作
            
        }
    }

    // 步骤2:在主线程中创建Handler实例
        private Handler mhandler = new mHandler();

    // 步骤3:创建所需的消息对象
        Message msg = Message.obtain(); // 实例化消息对象
        msg.what = 1; // 消息标识
        msg.obj = "AA"; // 消息内容存放

    // 步骤4:在工作线程中 通过Handler发送消息到消息队列中
    // 可通过sendMessage() / post()
    // 多线程可采用AsyncTask、继承Thread类、实现Runnable
        mHandler.sendMessage(msg);

    // 步骤5:开启工作线程(同时启动了Handler)
    // 多线程可采用AsyncTask、继承Thread类、实现Runnable


/** 
  * 方式2:匿名内部类
  */
   // 步骤1:在主线程中 通过匿名内部类 创建Handler类对象
            private Handler mhandler = new  Handler(){
                // 通过复写handlerMessage()从而确定更新UI的操作
                @Override
                public void handleMessage(Message msg) {
                        ...// 需执行的UI操作
                    }
            };

  // 步骤2:创建消息对象
    Message msg = Message.obtain(); // 实例化消息对象
  msg.what = 1; // 消息标识
  msg.obj = "AA"; // 消息内容存放
  
  // 步骤3:在工作线程中 通过Handler发送消息到消息队列中
  // 多线程可采用AsyncTask、继承Thread类、实现Runnable
   mHandler.sendMessage(msg);

  // 步骤4:开启工作线程(同时启动了Handler)
  // 多线程可采用AsyncTask、继承Thread类、实现Runnable

具体的应用实例

java
public class MainActivity extends AppCompatActivity {
    
    public TextView mTextView;
    public Handler mHandler;

    // 步骤1:(自定义)新创建Handler子类(继承Handler类) & 复写handleMessage()方法
    class Mhandler extends Handler {

        // 通过复写handlerMessage() 从而确定更新UI的操作
        @Override
        public void handleMessage(Message msg) {
            // 根据不同线程发送过来的消息,执行不同的UI操作
            // 根据 Message对象的what属性 标识不同的消息
            switch (msg.what) {
                case 1:
                    mTextView.setText("执行了线程1的UI操作");
                    break;
                case 2:
                    mTextView.setText("执行了线程2的UI操作");
                    break;
            }
        }
    }

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

        mTextView = (TextView) findViewById(R.id.show);

        // 步骤2:在主线程中创建Handler实例
        mHandler = new Mhandler();
       
        // 采用继承Thread类实现多线程演示
        new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                 // 步骤3:创建所需的消息对象
                 Message msg = Message.obtain();
                 msg.what = 1; // 消息标识
                 msg.obj = "A"; // 消息内存存放

                 // 步骤4:在工作线程中 通过Handler发送消息到消息队列中
                 mHandler.sendMessage(msg);
            }
        }.start();
        // 步骤5:开启工作线程(同时启动了Handler)

        // 此处用2个工作线程展示
        new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(6000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 通过sendMessage()发送
                 // a. 定义要发送的消息
                 Message msg = Message.obtain();
                 msg.what = 2; //消息的标识
                 msg.obj = "B"; // 消息的存放
                 // b. 通过Handler发送消息到其绑定的消息队列
                 mHandler.sendMessage(msg);
            }
        }.start();

    }
}

倒计时View的实现

倒计时的View其实挺常见的,比如我们在获取验证码的时候就需要设计一个倒计时的Button,用户点击后显示一个60s的倒计时,并且实时递减,更新在Button上,这就可以使用Handler实现。 代码转载自:https://www.jianshu.com/p/916bc0645295

java
public class CountDownView extends AppCompatTextView {
    /**
     * 总时间
     */
    private long seconds;
    /**
     * 当前分钟
     */
    private long minutes;
    /**
     * 当前秒数
     */
    private int second = 60;

    private static final int SECONDS_PER_MINUTE = 60;
    private static final int MILLS_PER_SECOND = 1000;
    private static final int MILLS_PER_MINUTE = SECONDS_PER_MINUTE * 1000;

    private static final int WHAT_DONE = 2;
    private static final int WHAT_TICK = 1;

    private int marginEnd;

    private StringBuilder content = new StringBuilder();

    public CountDownView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        DeviceProfile deviceProfile = Launcher.getLauncher(getContext()).getDeviceProfile();
        int size = (int) (MeasureSpec.getSize(widthMeasureSpec) / deviceProfile.inv.numColumns);
        marginEnd = marginEnd == 0 ? (size - deviceProfile.iconSizePx) / 2 : marginEnd;

        setMarginEnd(marginEnd);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    private void setMarginEnd(int marginEnd) {
        LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();
        layoutParams.setMarginEnd(marginEnd);
        layoutParams.resolveLayoutDirection(layoutParams.getLayoutDirection());
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (handler.hasMessages(WHAT_TICK)) {
            handler.removeMessages(WHAT_TICK);
        }
    }

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case WHAT_DONE:
                    setVisibility(View.GONE);
                    break;
                default:
                    setText(content.toString());
                    handler.post(runnable);
                    break;
            }
        }
    };

    /***
     * 设置倒计时
     * @param millis
     */
    public void setCountDownMills(long millis) {
        seconds = (long) Math.floor(millis / MILLS_PER_SECOND);
        minutes = (long) Math.floor(millis / MILLS_PER_MINUTE) - 1;
        // start after one second
        handler.postDelayed(runnable, MILLS_PER_SECOND);
    }

    private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            if (seconds <= 0) {
                handler.sendEmptyMessage(WHAT_DONE);
                return;
            }
            seconds--;
            if (second <= 0) {
                second = SECONDS_PER_MINUTE;
                minutes = (long) Math.floor(seconds / SECONDS_PER_MINUTE);
            }
            second--;
            content.delete(0, content.length());

            appendZeroWhenLower10(minutes);
            content.append(":");
            appendZeroWhenLower10(second);

            if (handler.hasMessages(WHAT_TICK)) {
                handler.removeMessages(WHAT_TICK);
            }
            handler.sendEmptyMessageDelayed(WHAT_TICK, MILLS_PER_SECOND);
        }
    };

    private StringBuilder appendZeroWhenLower10(long value) {
        if (value < 10) {
            content.append("0").append(value);
        } else {
            content.append(value);
        }
        return content;
    }
}