Handler与多线程
1、Handler介绍
在Android开发中,我们常会使用单独的线程来完成某些操作,比如用一个线程来完成从网络上下的图片,然后显示在一个ImageView上,在多线程操作时,Android中必须保证以下两点:
(1)不要阻塞UI线程
(2)不要再UI线程之外访问Android UI工具包
有了以上两点的限制,我们在程序之间的消息如何进行传递呢?
用Handler,消息的处理者。
public class MainActivity extends Activity {
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.tv);
}
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 100:
tv.setText("下载完成");
break;
}
}
};
public void downloadClick(View view) {
//使用线程模拟下载操作
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
handler.sendEmptyMessage(100);
}
}).start();
}
}
2、Handler常用API
使用handler可以完成以下两点工作:
(1)消息调度和在将来的某个时间点执行一个Runnable
(2)多个任务加入到一个队列中执行
Handler相关方法:
//发送一个空消息,即obj为空,标记为100
handler.sendEmptyMessage(100); //获取一个消息对象,返回一个Msg对象
Message msg = handler.obtainMessage();
msg.what = 100;
msg.obj = "要存的信息";//任意类型
handler.sendMessage(msg);//发送消息 //在制定时间后发送消息
handler.sendEmptyMessageAtTime(200, System.currentTimeMillis() + 3000);
//延迟2s后发送消息
handler.sendEmptyMessageDelayed(300, 2000);
3、Handler内部实现原理
Handler实现机制:
(1)Message对象,表示要传递的一个消息
(2)MessageQueue对象,存放消息对象的消息队列,先进先出原则
(3)Looper对象负责管理当前线程的消息队列(MessageQueue)
(4)Handler对象负责把消息push到消息队列中,以及接收Looper从消息队列中取出的消息
Android启动程序时会在UI线程创建一个MessageQueue。

/**
* Handler机制
* 1、Message 消息对象,内部使用链表数据结构实现一个消息池,用于重复利用,避免大量创建消息对象,造成内存浪费
* 2、Handler 消息处理者,通过该对象把消息存入消息队列,并最后通过HandlerMessage方法处理消息
* 3、MessageQueue 消息队列,用于存储Message对象的数据结构,先进先出
* 4、Looper 消息队列的处理者,用于循环检查消息队列,从消息队列中一个一个的取出消息对象,传入HandlerMessage方法
*/
4、Handler内存泄露问题分析
内存泄漏:当activity退出后,handler依然还占用activity的引用,导致activity没有真正退出,依然占用内存。解决方法如下:
/**
* Handler的内存泄露问题
* 1、定义一个内部类时,会默认拥有外部类对象的引用,所以建议使用内部类时,最好定义为一个静态内部类
* 2、引用的强弱,强引用->软引用 ->弱引用
*/ public class HandlerMemoryActivity extends Activity { private MyHandler handler; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_memory);
//使用Handler延迟执行一个Runnable(10分钟)
handler.postDelayed(new Runnable() {
@Override
public void run() {
System.out.println("!!!!!!run");
}
}, 1000 * 60 * 10);
//关闭当前的Activity
finish();
} private static class MyHandler extends Handler { WeakReference<HandlerMemoryActivity> weakReference; public MyHandler(HandlerMemoryActivity activity) {
weakReference = new WeakReference<HandlerMemoryActivity>(activity);
} @Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
HandlerMemoryActivity activity = weakReference.get();
if (activity != null) {
//做处理
}
}
}
}
5、AsyncTask
除了使用Handler实现线程间的通信外,Android提供了一个工具类:AsyncTask,他使创建需要与用户界面交互的长时间运行的任务变得简单,相对来说AsyncTask更清凉已写,适用与简单的异步处理,不需要借助线程和Handler即可实现。
AsyncTask是抽象类,AsyncTask定义了三种泛型类型:Params,Progress和Result
Params启动任务执行的输入参数,比如,Http请求的URL;
Progress后台任务执行的百分比
Result后台执行任务的最中返回结果,比如String
AsyncTask的执行步骤:
AsyncTask的执行分为四个步骤,每一步对应一个回调方法,我们需要的就是实现这些方法。
(1)首先定义一个类继承AsyncTask
(2)实现AsyncTask中定义的下面一个或几个方法
四个执行步骤分别为:
(1)onPreExecute():被UI Thread调用,该方法用来做已写准备工作,如在界面上显示一个进度条
(2)doInBackground(Params..):将在onPreExcute之后执行,运行在后台的线程中。负责执行耗时操作。可以调用publishProgress方法来更新实时任务进度
(3)onProgressUpdate(Progress..):在publishProgress方法被调用后,UI Thread将调用该方法在界面上展示任务的进展情况
(4)onPostExcute(Result):在doInBackground执行完成后,onPostExcute(Result)方法将被UI Thread调用,后台的计算结果将通过该方法传递到UI Thread。
AsyncTask准则:
(1)AsyncTask的实例必须在UI Thread中创建。
(2)excute方法必须在UI Thread中调用
(3)不要手动调用onPreExecute、onPostExecute、doInBackground和onProgressUpdate这借个方法
(4)改Task只能被执行一次,否则多次调用时会出现异常
(5)AsyncTask不能饿完全取代线程,在一些逻辑较为复杂或者后台反复执行的逻辑可能就需要线程来实现了
public class MainActivity extends Activity {
private TextView tv;
private ProgressBar progressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.tv);
progressBar = (ProgressBar) findViewById(R.id.progressBar);
}
public void downloadClick(View view) {
new MyAsyncTask(MainActivity.this).execute("http://a.hiphotos.baidu.com/image/pic/item/d50735fae6cd7b8926b326c20c2442a7d8330e97.jpg");
}
/**
* 通过AsyncTask实现一个异步任务
*/
private static class MyAsyncTask extends AsyncTask<String, Integer, Integer> {
private MainActivity activity;
public MyAsyncTask(MainActivity activity) {
this.activity = activity;
}
//执行任务之前触发的事件,可以在该方法中做一些初始化动作,例如显示一个dialog
//这个是在主线程中
@Override
protected void onPreExecute() {
super.onPreExecute();
activity.progressBar.setProgress(0);
}
//在子线程中
//执行后台任务的方法
@Override
protected Integer doInBackground(String... params) {
String s = params[0];
try {
URL url = new URL(s);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
//获取文件的大小
int size = urlConnection.getContentLength();
//0是一个标记,表示需要更新的最大进度值,1表示更新当下下载的进度值
publishProgress(0, size);
byte[] bytes = new byte[100];
int len = -1;
FileInputStream in = (FileInputStream) urlConnection.getInputStream();
FileOutputStream out = new FileOutputStream("/sdcard/" + System.currentTimeMillis() + ".jpg");
while ((len = in.read(bytes)) != -1) {
out.write(bytes, 0, len);
//更新进度
publishProgress(1, len);
out.flush();
}
out.close();
in.close();
} catch (Exception e) {
e.printStackTrace();
}
return 200;
}
//更新进度
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
switch (values[0]) {
case 0:
activity.progressBar.setMax(values[1]);
break;
case 1:
activity.progressBar.incrementProgressBy(values[1]);
break;
}
}
@Override
protected void onPostExecute(Integer integer) {
super.onPostExecute(integer);
if (integer == 200) {
activity.tv.setText("下载完成");
}
}
}
}
Handler与多线程的更多相关文章
- Android Handler与多线程
本文首先解释一下handler是用来干嘛的,然后通过例子介绍其在多线程中的应用. 什么是Handler handler通俗一点讲就是用来在各个进程之间发送数据的处理对象.在任何进程中,只要获得了另一个 ...
- Android应用开发基础篇(5)-----Handler与多线程
链接地址:http://www.cnblogs.com/lknlfy/archive/2012/02/19/2358155.html 一.概述 Handler这个类主要用来发送和处理消息的.它有多个发 ...
- 10_Android中通过HttpUrlConnection访问网络,Handler和多线程使用,读取网络html代码并显示在界面上,ScrollView组件的使用
编写如下项目: 2 编写Android清单文件 <?xml version="1.0" encoding="utf-8"?> <mani ...
- Android多线程源码学习笔记一:handler、looper、message、messageQueue
最近在学习Android多线程相关知识的源码,现在把自己的笔记整理一下,写出来加深印象. Android多线程通讯的核心是handler.looper.message.messageQueue,这篇文 ...
- Android多线程:深入分析 Handler机制源码(二)
前言 在Android开发的多线程应用场景中,Handler机制十分常用 接下来,深入分析 Handler机制的源码,希望加深理解 目录 1. Handler 机制简介 定义一套 Android 消息 ...
- 【转】Handler学习笔记(一)
一.Handler的定义: Handler主要接收子线程发送的数据, 并用此数据配合主线程更新UI,用来跟UI主线程交互用.比如可以用handler发送一个message,然后在handler的线程中 ...
- android中handler用法总结
一.Handler的定义: Handler主要接收子线程发送的数据, 并用此数据配合主线程更新UI,用来跟UI主线程交互用.比如可以用handler发送一个message,然后在handler的线程中 ...
- Android Handler使用实例
本文主要介绍Android中Handler的简单使用方法,Handler跟多线程,消息队列联系很紧密,在平常的实际程序开发中比较常见.本文分为4个简单的例子来学校handler Handler使用例1 ...
- Android(java)学习笔记134:Handler用法总结 和 秒表案例
一.Handler的定义: Handler主要接收子线程发送的数据, 并用此数据配合主线程更新UI,用来跟UI主线程交互用.比如可以用handler发送一个message,然后在handler的线程中 ...
随机推荐
- Mysql教程:(四)连接查询
连接查询 1.左连接查询: mysql> select stu.*,sc.*,maths+sc.chinese+sc.english from student stu left join sco ...
- idea中的maven模块变成灰色
问题 在使用idea的过程中,遇到其中一个maven模块变成灰色,如下所示: 解决方法 方法一 造成这个的原因可能是忽略了maven模块,可以尝试如下解决方法:在idea中maven中找到ignore ...
- FZU ICPC 2020 寒假训练 6 —— 字符串处理
P1603 斯诺登的密码 题目描述 2013年X月X日,俄罗斯办理了斯诺登的护照,于是他混迹于一架开往委内瑞拉的飞机.但是,这件事情太不周密了,因为FBI的间谍早已获悉他的具体位置--但这不是最重要的 ...
- Python 数据类型常用的内置方法(二)
目录 Python 数据类型常用的内置方法(二) 1.字符串类型常用内置方法 1.upper.lower.isupper.islower 2.startswith.endswith 3.format ...
- Linux驱动实践:带你一步一步编译内核驱动程序
作 者:道哥,10+年嵌入式开发老兵,专注于:C/C++.嵌入式.Linux. 关注下方公众号,回复[书籍],获取 Linux.嵌入式领域经典书籍:回复[PDF],获取所有原创文章( PDF 格式). ...
- 【Tool】IntelliJ IDEA Ultimate2019.1 中文版 安装
IntelliJ IDEA Ultimate2019.1 2019-07-26 09:26:24 by冲冲 1. 下载 https://mp.weixin.qq.com/s/SdFQqGzMy-g ...
- nginx反向代理出错:proxy_pass
问题描述: 一台服务器代理访问另一台服务器,代码如下图所示: 重新加载nginx后不会跳到该域名,而是出现error的页面. 查看error.log日志为以下报错: 2021/03/09 23:07: ...
- 删除本地仓库中的lastUpdated文件.bat
@echo off @ ECHO. @ ECHO. @ ECHO. 说 明 @ ECHO ------------------------------------------------------- ...
- 关于 n 个 [0,1] 的随机变量第 k 小的期望值
今天做到一道题,感觉里面一个结论有点意思,就到网上扒了篇证明(bushi)下来了. 知乎回答习惯,先抛结论,再给证明(大雾 结论:对于 \(n\) 个取值范围为 \([0,1]\) 的随机变量 \(x ...
- python包之drmaa:集群任务管理
目录 1. drmaa简介 2. 安装和配置 3. 示例 3.1 开始和终止会话 3.2 运行工作 3.3 等待工作 3.4 控制工作 3.5 查询工作状态 4. 应用 4.1 写一个简单应用 4.2 ...