Handler的简单使用

本文详细介绍了Android中的Handler机制,包括其在UI线程与子线程通信中的角色,Looper、MessageQueue和Message的作用。通过实例展示了如何使用Handler进行消息传递,以及在倒计时场景的应用。
  • 什么是Handler?
Handler是Android SDK中处理异步消息的核心类,其作用是让子线程通过与UI线程通信来更新UI界面
其运行机制如下:

  1. 创建一个Handler对象,系统把Handler对象,UI线程和UI线程的消息队列捆绑起来;
  2. 当我们在线程中处理完数据后,可以通过Handler对象将消息发出;
  3. 消息将会按先后顺序添加到队列中;
  4. UI线程中的Looper不断从消息队列中取消信息,刷新UI。
  • 什么是Looper和MessageQueue?
  1. 在Android中创建出的普通线程默认是没有消息循环的,run方法执行完毕,线程也就结束了;如果想让线程不停的循环工作时,可以使用Looper,将普通线程变成循环线程。
  2. 当创建出Looper时,会自动创建出MessageQueue,一个线程只会存在一个Looper和MessageQueue,当MessageQueue中有消息时,Looper将从MessageQueue中取出消息
  • 什么是Message?

Message是消息对象,子线程将需要传递到UI线程的消息放入Message对象中,Message对象可以通过Handler对象的obtainMessage方法获得

这里列举一些常用属性:

what属性:int类型的消息码,接收方用来识别是什么消息;

arg1,arg2属性:int类型,如果传递的消息仅仅是整型数字,可以将数字赋给arg1或arg2;

obj属性:Object类型,如果传递发的消息是String或任意类型时,可将数据赋给obj属性;

sendToTarget方法:将消息发送给指定的Handler对象。

  • 如何使用Handler?
  1. 第一步需要写好需要的xml布局,这个无需多说;
  2. 然后需要修改这个xml布局所对应的Java文件:
  • 在这个Java文件中,做好准备工作(xml文件中控件的定义与绑定ID,设置监听事件);
  • 然后在onCreat方法外定义handler对象,并调用handlerMessage方法;
  • 在监听事件中获取用户输入的数据(String类型),这里注意一个小问题,需要使用Integer.parseInt()方法将String类型数值转换为int类型数值。然后启动子线程 ,使用handler.sendMessage()或handler.sendEmptyMessage()方法将子线程的值返回给主线程
  • 主线程接收子线程发来的数值,并且更新UI。

  • 倒计时案例举例(附代码和效果图)
首先给出main.xml的布局文件:
<LinearLayout 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"
    android:orientation="vertical"
    tools:context="com.lenovo.handlerdemo.MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="设置时间"
            android:textSize="30sp"/>
        <EditText
            android:id="@+id/daojishi_edit"
            android:layout_width="40dp"
            android:layout_height="wrap_content" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="秒"
            android:textSize="30sp"/>
    </LinearLayout>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout
            android:id="@+id/time_layout"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:layout_centerInParent="true">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="倒计时:"
                android:textSize="30sp"/>
            <TextView
                android:id="@+id/daojishi_tv"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="0"
                android:textSize="30sp"/>
        </LinearLayout>

        <Button
            android:id="@+id/daojishi_btn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="开始计时"
            android:layout_below="@id/time_layout"/>
    </RelativeLayout>


</LinearLayout>
附上xml预览图


然后开始MainActivity.java的准备工作:
public class MainActivity extends AppCompatActivity {

    private Button daojishiBtn;
    private EditText daojishiEdit;
    private TextView daojishiTV;
    int time;


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

        bind();

        daojishiBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                
    }

    private void bind() {
        daojishiEdit = findViewById(R.id.daojishi_edit);
        daojishiTV = findViewById(R.id.daojishi_tv);
        daojishiBtn = findViewById(R.id.daojishi_btn);
    }


}
至此便可以开始写主线程了:
Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            
        }
    };
这里使用Handler方法定义了一个handler对象,用于全局的调用使用:
Handler handler = new Handler()    
调用的是handleMessage方法:
public void handleMessage(Message msg)
由于主线程不能够进行费时运行,所以需要使用子线程来进行,代码如下:
daojishiBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                time = Integer.parseInt(daojishiEdit.getText().toString());//类型转换

                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            for (int i = time; i > 0; i--) {
                                handler.sendEmptyMessage(i);//传递i给主线程
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        }
                    }).start();
            }
        });

整理一下思路,点击daijishiBtn按钮后,子线程需要获取用户输入的数值,所以定义一个全局变量time,用来获取数值

 time = Integer.parseInt(daojishiEdit.getText().toString());//类型转换使用方法Integer.parseInt()

接下来创建子线程,然后在run()方法内写for循环;

for循环判定循环条件后,传值给主线程:

handler.sendEmptyMessage(i);

设置休眠时间方便我们观看运行效果:

try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }

子线程的最后不要忘了Thread.start();

由于子线程无法更新UI界面,所以需要将数值传递给主线程,由主线程来更新UI,这里只需要调用setText()方法就可以更新UI

Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            daojishiTV.setText(msg.what+"");
        }
    };

到这里便完成了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值