2.Handler

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qingjianduoyun/article/details/80623421

一、几个概念

1.UI线程、主线程、ActivityThread

当每个应用启动时都会启动一个主进程,接着这个主进程会开启一个主线程(主线程可以叫做UI线程,主要负责处理界面上UI相关的消息的分发)。一个Android 程序默认情况下也只有一个进程Process,但可以有许多个线程Thread。

2.线程不安全

具体参考博文:android 那些事—主线程是线程不安全的

3.消息循环机制

具体参见博文:Android消息循环机制

4.Handler、Looper、Message、MessageQueue

具体参考上面的博客Android消息循环机制,四者之间的关系如下图所示:
这里写图片描述

二、Handler的使用

1.在主线程中使用Handler

新建一个名为Handler的项目,MainActivity.java代码如下:

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //创建Handler
        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                //处理消息
                Log.d(TAG, "handleMessage: " + msg.what);
            }
        };

        //在主线程中发送一条空消息
        handler.sendEmptyMessage(1001);
    }
}

输出结果如下图所示:
这里写图片描述

2.可能会发生的问题

2.1 子线程无法更新UI

实现效果为:点击按钮,改变TextView中的内容
为此需修改activity_main.xml中代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button" />
</LinearLayout>

MainActivity.java代码修改如下:

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";
    private TextView textView;
    private Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();

        //创建Handler
        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                //处理消息
                Log.d(TAG, "handleMessage: " + msg.what);
            }
        };

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        textView.setText("hello");
                    }
                }).start();
            }
        });
    }

    private void initView() {
        textView = findViewById(R.id.textView);
        button = findViewById(R.id.button);
    }
}

运行程序,点击按钮,程序崩溃,打开日志打印窗口,查看错误如下图所示:
这里写图片描述

这说明,我们新创建的子线程无法更改UI界面,那么该怎么办呢?这时我们就要告诉主线程(即将消息传给主线程),让主线程来更新UI。

2.2 告诉主线程,让主线程来操纵UI

MainActivity.java代码修改如下:

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";
    private TextView textView;
    private Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        /**
         * UI线程
         */
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();

        //创建Handler
        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                /**
                 * 接收子线程发来的消息,并处理消息
                 */
                Log.d(TAG, "handleMessage: " + msg.what);
                if (msg.what == 1001) {
                    textView.setText("hello,handler!");
                }
            }
        };

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                /**
                 * 子线程:有可能做大量耗时操作
                 */
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        /**
                         * 通知UI更新
                         */
                        //调用此方法会触发主线程(UI线程)中Handler对象中的handleMessage方法,并将消息传递给主线程
                        handler.sendEmptyMessage(1001);
                    }
                }).start();
            }
        });
    }

    private void initView() {
        textView = findViewById(R.id.textView);
        button = findViewById(R.id.button);
    }
}

效果图如下所示:
这里写图片描述

3.Handler发送消息的常见方法

3.1 message的几个参数

如下代码所示:

Message message =Message.obtain();
message.what = 1002;
message.arg1 = 1003;
message.arg2 = 1004;
message.obj = MainActivity.this;      
handler.sendMessage(message);

这里不建议使用Message message=new Message();,我们来看看源码:
这里写图片描述
Message有obtain方法,在Message对象有的情况下直接使用就行,没有的话会自动为我们创建。

3.2 Handler发送消息的常见方法

代码如下:

//定时发送
handler.sendMessageAtTime(message, SystemClock.uptimeMillis() + 6000);
//延时发送
handler.sendMessageDelayed(message, 3000);
Runnable runnable = new Runnable() {
       @Override
         public void run() {

        }
};
 handler.post(runnable);
 handler.postDelayed(runnable, 2000);

三、总结

官方API文档给出的Handler主要有两方面的功能:
1. 安排将来要执行的消息和可运行的程序
2. 排队在不同于你自己的线程上执行的动作
说白了就是进行定时任务,在子线程汇总执行一些耗时操作。

四、敲代码时Get到的技巧

更多见博客:Android Studio快速打印Log

猜你喜欢

转载自blog.csdn.net/qingjianduoyun/article/details/80623421