Handler的用法

因为不能在主线程中访问网络,所以需要新建线程
新建的线程获取数据后,需要传到主线程中(或者不用传,直接用),用于更新UI

之前一直使用AsyncTask来开启多线程

new AsyncTask<String, Void, String>() {
            //封装好的线程,可以进行网络通信
            @Override
            protected String doInBackground(String... params) {
            }
            //用于更新UI
            @Override
            protected void onPostExecute(String s) {
            }
        }.execute(url);

优点是简单,网络访问写在doInBackground中,更新UI写在onPostExecute中,实现功能简单的程序写起来很方便;
缺点呢是非常不灵活,只能按照套路来。。。比如我想将网上获取的数据保存到本地,以后直接调用,AsyncTask很难实现,这时Handler的优势就体现出来了

先来一个最简单的Handler写法

//直接在声明时就给它初始化了,方便就是有点乱。。。
private Handler handler = new Handler(){
    //重写它的HandlerMessage方法,数据就是从这个Message传过来的
    @Override
        public void handleMessage(Message msg) {
            //获取到Message传过来的值
            int arg1 = msg.arg1;
            int arg2 = msg.arg2;
            int what = msg.what;
            Object obj = msg.obj;
        }
};

//当你开启一个子线程时,不只是访问网络哦
public class MyThread implements Runnable{
    @Override
    public void run() {
        //访问网络
        ......
        //假设我们获取到了个图片
        byte[] data = EntityUtils.toByteArray(httpResponse.getEntity());
        //新建Message对象,这里推荐使用obtain(),而不是new一个新的
        //因为源码中它会判断消息池中是否有Message,有则复用,没有才new一个新的,节能环保重复利用
        Message message = Message.obtain();      //这里是最简单的用法
        //赋值
        message.obj = data;                      //obj是一个Object类型的值,可以传任意值
        message.what = 1;                        //what是一个int型,常用来作标志位
        message.arg1 = 111;                      
        message.arg2 = 222;                      //arg1和arg2都是int型,常用来表示传递数据的进度
        Bundle data = new Bundle();
        message.setData(data);                   //setData()可以用来传一个Bundle,传递复杂的数据
        handler.sendMessage(message);            //将message发送给handler
    }
}

是不是很简单?
Message.obtain()方法有多种重载方法
比如直接绑定handler啊,给arg1,arg2,obj,what直接赋值啊等等等

值得一提的是
直接绑定一个handler时
这时发送就不能用handler.sendMessage(message)了,而用Message.sendToTarget();

Message message = Message.obtain(handler);          
message.sendToTarget();

Yo,未完待续

<think>首先,用户的问题是:“我想了解Handler的使用方法 请问Handler的使用方法和示例”。我需要根据系统级指令来构建我的回答。 关键指令: - 所有行内数学表达式必须使用$...$格式。 - 独立公式使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识,例如:[^1] - 回答结构清晰,帮助用户逐步解决问题,保证回答真实可靠。 - 参考提供的引用内容。 提供的引用是关于Handler的使用: - [^1]: Handler使用方法详解(含实例)。方式二、使用Handler.post()方法... - [^2]: MyBatis TypeHandler基本用法与示例... - [^3]: android中handler,Android中Handler详解及使用示例... - [^4]: mybatis typehandler使用详解... 用户的问题是关于“Handler”的使用方法,但引用中提到了Android Handler和MyBatis TypeHandler。用户没有指定上下文,所以我需要假设是Android Handler,因为用户的问题直接提到“Handler”,而引用[1]和[3]是关于Android Handler的。 用户的问题:“我想了解Handler的使用方法 请问Handler的使用方法和示例”,结合引用,似乎是关于Android Handler,因为引用[1]和[3]具体讨论Android Handler。 所以,我将重点回答Android Handler的使用方法。 回答结构: 1. **介绍Handler**:简要解释Handler是什么及其在Android中的作用。 2. **核心概念**:解释Message, Looper, MessageQueue等。 3. **使用方法**: - 创建Handler。 - 发送消息(如post(), sendMessage())。 - 处理消息(handleMessage())。 4. **示例代码**:提供代码示例。 5. **注意事项**:如线程安全、主线程与子线程通信。 6. **生成相关问题**:在最后添加相关问题部分。 确保使用中文回答。 生成相关问题:在回答末尾添加“§§相关问题§§”部分,列出2-3个相关问题。 引用处理:在回答中引用段落时,末尾添加引用标识。例如,如果引用某个部分,加[^1]。参考提供的引用内容。 提供的引用: - [^1]: Android Handler使用post()方法示例。 - [^2]: MyBatis TypeHandler示例。 - [^3]: Android Handler的Looper和MessageQueue解释。 - [^4]: MyBatis自定义TypeHandler示例。 用户的问题是关于Handler,可能主要是Android Handler。所以,我将主要使用[^1]和[^3],因为[^2]和[^4]是关于MyBatis的,可能不相关,除非用户指定。但用户没有指定上下文,所以我应该专注于Android Handler。 在回答中,自然地引用: - 当解释Handler.post()时,引用[^1]。 - 当解释Looper时,引用[^3]。 现在,构建回答大纲: 1. **引言**:解释Handler在Android中的作用,用于线程间通信。 2. **基本组件**:描述Handler, Looper, MessageQueue的关系。 3. **创建Handler**:在主线程创建Handler实例。 4. **发送消息**: - 使用post(Runnable) - 使用sendMessage(Message) 5. **处理消息**:重写handleMessage()方法。 6. **示例代码**:提供一个完整的示例,展示在主线程和子线程中使用Handler。 7. **注意事项**:避免内存泄漏等。 8. **相关问题**:生成相关问题。 最后,添加相关问题部分。 确保代码块正确:在示例中使用代码块。 LaTeX:由于Handler不涉及数学公式,我可能不需要使用LaTeX,但如果有数学表达式,确保格式正确。这里可能不需要。 现在,编写回答。</think>### Handler的使用方法和示例 Handler 是 Android 开发中用于线程间通信的核心组件,它允许子线程与主线程(UI 线程)安全地交互,避免直接在子线程中更新 UI 导致的崩溃问题。Handler 基于消息队列(MessageQueue)和循环器(Looper)机制工作:每个线程都有一个 Looper 负责管理消息队列,Handler 则用于发送和处理消息。下面我将逐步解释其使用方法,并提供代码示例。内容基于 Android 官方文档和常见实践,确保真实可靠[^1][^3]。 #### 1. **Handler 的核心概念** - **Message**:封装数据的对象,包含 what(标识符)、arg1/arg2(整型数据)和 obj(对象)等字段。 - **MessageQueue**:消息队列,存储待处理的消息,按顺序执行。 - **Looper**:每个线程的循环器,不断从 MessageQueue 中取出消息并分发给 Handler。 - **Handler**:绑定到特定线程的 Looper,用于发送和处理消息。主线程默认有 Looper,子线程需手动创建[^3]。 #### 2. **Handler 的基本使用方法** Handler 的常见使用场景包括:子线程发送消息到主线程更新 UI,或延迟执行任务。以下是两种主要方法: - **方法一:使用 Handler.sendMessage()** 适用于传递复杂数据。步骤: 1. 在主线程创建 Handler 实例,并重写 `handleMessage()` 方法处理消息。 2. 在子线程中创建 Message 对象,并通过 Handler 发送。 ```java // 主线程中创建 Handler private Handler mHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { super.handleMessage(msg); // 处理消息,更新UI(例如TextView) if (msg.what == 1) { String text = (String) msg.obj; textView.setText(text); } } }; // 子线程中发送消息 new Thread(new Runnable() { @Override public void run() { // 模拟耗时操作 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } // 创建并发送消息 Message message = Message.obtain(); message.what = 1; // 消息标识 message.obj = "数据来自子线程"; // 传递对象 mHandler.sendMessage(message); } }).start(); ``` 此方法适合需要传递结构化数据的场景,如从网络请求中获取数据后更新 UI[^1][^3]。 - **方法二:使用 Handler.post()** 适用于执行简单任务(如 Runnable),无需传递额外数据。步骤: 1. 在主线程中创建 Handler 实例。 2. 在子线程中调用 `post()` 方法提交 Runnable 任务。 ```java // 主线程中创建 Handler private Handler mHandler = new Handler(); // 子线程中提交任务 new Thread(new Runnable() { @Override public void run() { // 耗时操作 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } // 通过post()在主线程执行UI操作 mHandler.post(new Runnable() { @Override public void run() { textView.setText("UI已更新"); } }); } }).start(); ``` 此方式简洁高效,适合快速更新 UI 元素[^1]。 #### 3. **完整示例:Handler 实现线程间通信** 以下是一个 Android Activity 的完整示例,展示 Handler 如何从子线程发送消息到主线程: ```java public class MainActivity extends AppCompatActivity { private TextView textView; private Handler mHandler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = findViewById(R.id.text_view); // 创建Handler,绑定主线程Looper mHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { if (msg.what == 1) { String data = (String) msg.obj; textView.setText(data); // 更新UI } } }; // 启动子线程 new Thread(new Runnable() { @Override public void run() { // 模拟网络请求 String result = fetchDataFromServer(); // 发送消息到主线程 Message message = Message.obtain(); message.what = 1; message.obj = result; mHandler.sendMessage(message); } }).start(); } // 模拟从服务器获取数据 private String fetchDataFromServer() { try { Thread.sleep(2000); // 模拟延迟 } catch (InterruptedException e) { e.printStackTrace(); } return "数据加载完成"; } } ``` 在此示例中: - `onCreate()` 初始化 Handler 并启动子线程。 - 子线程调用 `fetchDataFromServer()` 获取数据后,通过 `sendMessage()` 通知主线程。 - Handler 的 `handleMessage()` 在主线程执行,安全更新 UI。 #### 4. **注意事项** - **内存泄漏**:Handler 持有 Activity 引用时,可能导致内存泄漏。解决方法是使用静态内部类或 WeakReference。 - **子线程 Looper**:子线程使用 Handler 前需调用 `Looper.prepare()` 和 `Looper.loop()`,否则会崩溃。 - **性能优化**:避免频繁发送消息,使用 `postDelayed()` 实现延迟任务,而非 sleep。 - **替代方案**:现代 Android 开发中,可结合 Kotlin 协程或 LiveData 简化异步操作,但 Handler 仍是底层基础[^3]。 通过以上方法,Handler 能高效解决 Android 多线程通信问题。如需更深入讨论,请参考 Android 官方文档或相关教程[^1][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值