Handler与多线程

1、Handler介绍

在Android开发中,我们常会使用单独的线程来完成某些操作,比如用一个线程来完成从网络上下的图片,然后显示在一个ImageView上,在多线程操作时,Android中必须保证以下两点:

(1)不要阻塞UI线程

(2)不要再UI线程之外访问Android UI工具包

有了以上两点的限制,我们在程序之间的消息如何进行传递呢?

用Handler,消息的处理者。

public class MainActivity extends Activity {private TextView tv;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tv = (TextView) findViewById(R.id.tv);}private Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch (msg.what) {case 100:tv.setText("下载完成");break;}}};public void downloadClick(View view) {//使用线程模拟下载操作new Thread(new Runnable() {@Overridepublic 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为空,标记为100handler.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;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_handler_memory);//使用Handler延迟执行一个Runnable(10分钟)handler.postDelayed(new Runnable() {@Overridepublic 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);}@Overridepublic 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;@Overrideprotected 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//这个是在主线程中
        @Overrideprotected void onPreExecute() {super.onPreExecute();activity.progressBar.setProgress(0);}//在子线程中//执行后台任务的方法
        @Overrideprotected 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;}//更新进度
        @Overrideprotected 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;}}@Overrideprotected void onPostExecute(Integer integer) {super.onPostExecute(integer);if (integer == 200) {activity.tv.setText("下载完成");}}}
}

 

转载于:https://www.cnblogs.com/chhom/p/4732041.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/273052.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

oracle语法官方文档,Oracle官方文档必备语法知识

很多Oracle DBA虽然接触Oracle时间很长&#xff0c;但是一旦想不起语法或找不出相应参数时&#xff0c;习惯百度或谷歌。虽然已经下载了官方文档&#xff0c;但是Oracle官方文档必备语法知识[日期&#xff1a;2015-04-21]来源&#xff1a;Linux社区作者&#xff1a;kuqlan[字体…

新中大oracle实列名,新中大财务软件操作流程(完整版)

新中大财务软件最基本的三个模块&#xff1a;核算单位、财务处理系统、报表处理系统。简单地说&#xff0c;核算单位模块是用于建账&#xff0c;财务处理系统用于登账&#xff0c;报表处理系统用于出报表的。一、总账处理系统1、建账套双击财务软件图标 → 在登录界面选择用户编…

linux切换任务命令,Linux top详解之交互命令、命令行选项

top交互命令我们之前说过top是一个交互命令。上一节我们已经遇到了一些命令。这里我们会探索更多的命令。2.1 ‘h’: 帮助首先&#xff0c;我们可以用’h’或者’?’显示交互命令的帮助菜单。2.2 “或者”: 刷新显示top命令默认在一个特定间隔(3秒)后刷新显示。要手动刷新&am…

linux系统硬盘设置密码,LUKS:Linux下磁盘加密

Linux下磁盘加密LUKS(Linux Unified Key Setup)为Linux硬盘加密提供了一种标准&#xff0c;它不仅能通用于不同的Linux发行版本&#xff0c;还支持多用户/口令。因为它的加密密钥独立于口令&#xff0c;所以如果口令失密&#xff0c;我们可以迅速改变口令而无需重新加密真个硬盘…

Hibernate查询

9.1 Hibernate数据查询 数据查询与检索是Hibernate的一个亮点。Hibernate的数据查询方式主要有3种&#xff0c;它们是&#xff1a; l Hibernate Query Language&#xff08;HQL&#xff09; l Criteria Query l Native SQL 下面对这3种查询方式分别进…

单例模式 创建对象

两种选择 1 使用pthread_once&#xff0c; once是类的成员变量 只执行一次Create create的作用是创建一个对象 2 使用 static lock 如下所示&#xff0c;注意lock必须是static的&#xff0c;否则是局部变量&#xff0c;每个线程都有自己的lock&#xff0c;无法保证只执行一次。…

opencv配置

OpenCV的简单安装和一次性配置在这里就不赘述了&#xff0c;网上教程很多&#xff0c;可以参考一下这个链接里面的教程http://wenku.baidu.com/view/3b40de25453610661ed9f46b.html。 但是很多情况下面&#xff0c;我们新建一个项目就要重新配置一次OpenCV&#xff0c;那就相当…

linux 动态执行cp,Linux常用命令之cp、mv、rm、cat、more、head、tail、ln命令讲解

上一章节中&#xff0c;我们了解到了Linux系统的最基础的几个文件处理命令&#xff0c;核心的是ls命令&#xff0c;在今天这章中&#xff0c;我们来继续学习Linux对于文件操作相关的一些命令&#xff0c;比如复制、移动、删除、查看等命令。1、cp 命令解释命令名称&#xff1a;…

Linux鼠标回报率修改,鼠标回报率怎么调? 设置鼠标回报率的三种方法

鼠标回报率如何设置呢&#xff1f;鼠标回报率又称刷新率&#xff0c;是指鼠标MCU与电脑传输数据频率。鼠标回报率对于游戏玩家而言至关重要&#xff0c;但同时鼠标回报率与电脑性能息息相关。只有电脑硬件性能良好&#xff0c;才能适当提升鼠标回报率&#xff0c;以实现更高的鼠…

[转载]孙婧妍:高考语文148分是这样炼成的(附:孙婧妍

原文地址&#xff1a;孙婧妍&#xff1a;高考语文148分是这样炼成的(附&#xff1a;孙婧妍2013高考作文《手机论》)作者&#xff1a; 语文新高考高考语文148分是这样炼成的 (附&#xff1a;孙婧妍2013高考作文《手机论》) 来源&#xff1a;网络 作者&#xff1a;孙婧妍…

c语言字符串逆置,字符串逆置

满意答案9n7j5j3m4o2013.12.03采纳率&#xff1a;49% 等级&#xff1a;11已帮助&#xff1a;15198人47911 zxl0714 1358 Accepted 164K 15MS G 0.46K 2007-04-08 10:32:38#include using namespace std;void reverse(char* ch){int i, len;char tmp;len strlen( ch );for (…

【Android基础】Fragment 详解之Fragment介绍

Fragment在Android 3.0&#xff08; API 11&#xff09;引入&#xff0c;是为了支持在大屏上显示更加动态、灵活的UI&#xff0c;比如在平板和电视上。Fragment可以看作是嵌套的Activity&#xff0c;类似ActivityGroup&#xff0c;但是开销肯定没有ActivityGroup那么大&#xf…

linux postfix 搭建,linux 下搭建postfix服务器

linux 下postfix邮箱的安装linux一、首先关闭sendmail服务service sendmail stop二、chkconfig sendmail off(关闭开机自启动)三、修改DNS正解文件&#xff0c;使DNS可以解析邮箱服务添加下面两行mail.zhubf.com. IN A 172.17.17.2zhubf.com. IN MX 10 …

android 飞框动画,AndroidTV中实现飞框选中效果

相信很多从事AndroidTV开发的朋友都对如何展示item的选中效果感到苦恼&#xff0c;电视端开发与移动端最大的不同是用户只能通过一个遥控器进行控制(当然如果你的电视是触屏的话除外……)&#xff0c;在这个时候&#xff0c;我们需要让用户知道当前选中的到底是哪一个项目&…

鸿蒙系统支持980,鸿蒙手机上线时间 鸿蒙系统支持哪些手机2021最新汇总

鸿蒙手机来了&#xff0c;从2019年公布到现在的正式发布&#xff0c;没想到华为这么迅速&#xff0c;而且华为EMUI微博更名HarmonyOS&#xff0c;在Android与iOS这两座大山面前&#xff0c;大家觉得鸿蒙系统值得更新体验吗&#xff1f;目前来说鸿蒙系统支持第三方手机有哪些呢&…

confluence正常安装网页报错_NAS折腾手记1:在OMV5上安装ZFS On Linux的正确步骤

起因是直接安装OVMExtra里自带的zfs插件会报错&#xff0c;所以需要使用命令行来做一些前置准备。源配置有两种方法。1是安装OMVExtra并在内直接启用所有测试源下载地址在此​omv-extras.org2是手动添加&#xff0c;执行以下命令vi /etc/apt/sources.list.d/buster-backports.l…

android sdk eclipse没导入,Android—新的eclipse导入SDK出错解决办法

原先系统崩溃&#xff0c;重装系统&#xff0c;加入一块内存条&#xff0c;从32位变成62位&#xff0c;原先的eclipse用不了&#xff1b;去官网下载64位的eclipse&#xff0c;安装&#xff0c;用一样的方法导入SDK。这时候肯定会提示错误&#xff0c;如下&#xff1a;1.This An…

两个分数化简比怎么化_我学《分数的意义》心得

停课不停学已经有将近两个月了&#xff0c;我们迈入了“分数”这一部分。听妈妈说&#xff0c;这一块内容很重要&#xff0c;可我觉得到目前为止(明天就学真分数、假分数和带分数了)&#xff0c;分数好像并不比四年级难。看了看书&#xff0c;再做点练习&#xff0c;把这点新的…

html在线拖拽环绕,jQuery实现html元素拖拽

代码很简单&#xff0c;效果非常棒&#xff0c;直接给大家上源码&#xff1a;html定投金额 :元10050010002000300040005000600070008000900010000单位:元css.money-input{margin:36px auto 0;width:330px;font-size:14px;color:#818181}.input-rela{width:250px;height:42px;di…

iphone 抹除设备是什么意思_SMT设备有哪些,SMT是什么意思?

SMT设备其实就是表面贴装技术所需要的机器&#xff0c;一般一条SMT整线常规包含以下设备&#xff1a;上板机、印刷机、接驳台、SPI、贴片机、插件机、回流焊、波峰焊、AOI、X-ray、下板机等设备&#xff0c;以上设备是一条比较完整的smt配线清单设备&#xff0c;不同工厂可根据…