线程

由于Android的Activity中默认所有代码都在主线程(UI线程)中执行,如果在这里面执行耗时任务(例如下载),界面就会无反应且不可操作,直到耗时任务执行完毕。

如果想在执行耗时任务的同时又想让界面不会没有反应,就需要新开一个线程(Thread)。系统会在UI线程和新开的线程之间不断切换,由于切换速度极快且可以操作界面,就会给人一种没有在执行耗时任务的感觉。

JAVA中的线程

在JAVA中,有两个跟线程关系最紧密的类或接口:

  • Runnable接口:只有一个抽象方法run()。这是线程实际执行的方法,应该实现这个方法并把要在线程中执行的代码放到这里。

  • Tread类:实现了Runnable接口。通过执行start()来开启线程,并在新的线程中执行run()的代码。

    能否直接执行Tread的run()方法呢?答案是不行。如果直接在Thead执行run(),它仍然会在当前线程(例如UI线程)里执行run()的代码,而不是在新的线程中运行。

以下是线程的一种写法:

new Thread(new Runnable() {
@Override
public void run() {
// 在线程中运行的代码
}
}).start();

Android中的线程

任务(task):执行一个特定操作的一个Runnable对象或者Runnable对象集。

在Android中,可以使用上面介绍的方法开启线程。不过那样的写法会使得一旦线程的任务结束,不会再次运行这个线程(也就是一次性线程)。

当你想为不同数据集而重复执行某个任务时,可以使用IntentService。不过要注意,同一段时间只处理一个数据集。

如果上面两者都不符合你的要求,那么可以试试 ThreadPoolExecutor ,它可以实现以下功能:

  • 当资源准备好时自动执行任务
  • 多个任务同时执行

当 ThreadPoolExecutor 的线程池中有一个线程为空闲时, ThreadPoolExecutor 会从一个队列(queue)中取出一个任务来执行。

线程间数据交换

因为新开的线程和处理界面的线程是分开的,于是在Android中使用线程会遇到一个问题:线程处理完的数据如何更新到界面上?

JAVA

你可以实现 BlockingQueue 接口。将其实例传入线程中,在线程里面使用put(Object)将数据放入队列,使用take()从队列中取出数据。

以下是官方的例子:

 class Producer implements Runnable {
private final BlockingQueue queue;
Producer(BlockingQueue q) { queue = q; }
public void run() {
try {
while (true) { queue.put(produce()); }
} catch (InterruptedException ex) { ... handle ...}
}
Object produce() { ... }
} class Consumer implements Runnable {
private final BlockingQueue queue;
Consumer(BlockingQueue q) { queue = q; }
public void run() {
try {
while (true) { consume(queue.take()); }
} catch (InterruptedException ex) { ... handle ...}
}
void consume(Object x) { ... }
} class Setup {
void main() {
BlockingQueue q = new SomeQueueImplementation();
Producer p = new Producer(q);
Consumer c1 = new Consumer(q);
Consumer c2 = new Consumer(q);
new Thread(p).start();
new Thread(c1).start();
new Thread(c2).start();
}
}

Android

Android添加了几个类,用来处理数据交换。

  • Handler : 线程之间交换数据的通道,用于接收和发送消息。如果在UI线程里创建Handler,则该Handler里的handleMessage(Message)方法会在UI线程里执行。
  • Message : ​线程A发送消息给线程B时,需要将消息封装到Message里面。通过在线程A内部执行线程B的Handler.sendMessage(Message)将Message传给线程B,此时会执行Handler的handleMessage(Message)方法。
  • MessageQueue : 当发送多个Message时,为了不造成混乱,将这些Message组成一个队列,逐个处理。每个线程中只能有一个MessageQueue。这个队列由Looper管理。
  • Looper : 管理MessageQueue。每次从队列里面取出一个Message,交给Handler处理。Handler处理完毕后再去队列中取出Message。

这些类太多了,有时候写起来麻烦。为了简化线程的写法,Android将上面那些封装起来,于是就有了AsyncTask。

Android对线程类的封装

AsyncTask有四个重要的方法:

  • onPreExecute() :(UI线程)后台任务执行前在UI线程上做某些初始化操作
  • doInBackground(Params ...) :(子线程)相当于Runnable的run()方法。可以在这个方法内计算进度,并调用publishProgress(Progress ...)传递给onProgressUpdate(Progress ...)方法
  • onProgressUpdate(Progress ...) : ​(UI线程)用于更新界面上的进度信息
  • onPostExecute(Result) :(UI线程)用于子线程处理完毕后对结果进行处理

AsyncTask是一个抽象类,需要创建一个类去继承它。AsyncTask有三个泛型参数,它们用途依次为:

  • ​执行任务所需要的参数
  • 当前进度的单位
  • 任务的结果

执行AsyncTask的execute()方法以开始任务。

Android笔记(六):线程及线程通信的更多相关文章

  1. Android笔记(六十二)网络框架volley

    什么是Volley 很多时候,我们的APP都需要用到网络技术,使用HTTP协议来发送接收数据,谷歌推出了一个网络框架——volley,该框架适合进行数据量不大,但通信频繁的网络操作. 它的优点: (1 ...

  2. Android笔记(六十九) 仿微信界面(一)

          综合之前的Fragment和自定义组件的知识,实现微信界面 MainActivity.java package cn.lixyz.test; import android.app.Acti ...

  3. Android笔记(六十八) Fragment总结

    Fragment的产生: 为了适应各种尺寸的屏幕,谷歌推出Fragment,可以把Fragment成Activity的一个组成部分,它拥有自己的生命周期.可以接收并处理用户的各种事件,还可以动态的增删 ...

  4. Android笔记(六十七) 自定义控件

    实际编程中,系统提供的控件往往无法满足我们的需求,一来是样子丑陋,二来是一些复杂的组合需要多次使用的话,每次都写一堆控件的组合会很耗费时间,所以我们将这些组件的组合自定义为一个新的控件,以后使用的时候 ...

  5. Android笔记(六十六) android中的动画——XML文件定义属性动画

    除了直接在java代码中定义动画之外,还可以使用xml文件定义动画,以便重用. 如果想要使用XML来编写动画,首先要在res目录下面新建一个animator文件夹,所有属性动画的XML文件都应该存放在 ...

  6. Android笔记(六十五) android中的动画——属性动画(propertyanimation)

    补间动画只能定义起始和结束两个帧在“透明度”.“旋转”.“倾斜”.“位移”4个方面的变化,逐帧动画也只能是播放多个图片,无法满足我们日常复杂的动画需求,所以谷歌在3.0开始,推出了属性动画(prope ...

  7. Android笔记(六十四) android中的动画——补间动画(tweened animation)

    补间动画就是只需要定义动画开始和结束的位置,动画中间的变化由系统去补齐. 补间动画由一下四种方式: 1.AplhaAnimation——透明度动画效果 2.ScaleAnimation ——缩放动画效 ...

  8. Android笔记(六十三) android中的动画——逐帧动画( frame-by-frame animation)

    就好像演电影一样,播放实现准备好的图片,来实现动画效果. 逐帧动画需要用到AnimationDrawable类,该类主要用于创建一个逐帧动画,然后我们把这个动画设置为view的背景即可. androi ...

  9. Android笔记(三十四) Android中线程之间的通信(六)Handle中的post()方法详解

    我们之前都是使用sendMessage()方法来发送消息,使用handleMessage来处理消息的,今天我们来看另外一种方法,先看代码: package cn.lixyz.handlertest; ...

  10. Android笔记(三十一)Android中线程之间的通信(三)子线程给主线程发送消息

    先看简单示例:点击按钮,2s之后,TextView改变内容. package cn.lixyz.handlertest; import android.app.Activity; import and ...

随机推荐

  1. zabbix3.0.4导入中文模板后乱码问题处理

    通过yum安装方式部署了zabbix3.0.4监控服务器,配置过程中发现当导入的模板中有中文时,图中的中文会变成方块 如下图所示: 这个问题是由于zabbix的web端没有中文字库,我们最需要把中文字 ...

  2. 支付宝&微信统一支付

    1.实体对应关系: Application  — 支付记录实体 --  支付记录详情 2.流程 1.生成订单选择支付类型 2.支付宝:PC端.手机端.扫码:微信:微信公众号支付.扫码支付.H5支付. ...

  3. Android ImageView 的scaleType 属性图解

    ImageView 是 Android 中最常用的控件之一,而在使用ImageView时,必不可少的会使用到它的scaleType属性.该属性指定了你想让ImageView如何显示图片,包括是否进行缩 ...

  4. oracle进阶之connect by笔记

    本博客是自己在学习和工作途中的积累与总结,仅供自己参考,也欢迎大家转载,转载时请注明出处. http://www.cnblogs.com/king-xg/p/6794562.html 如果觉得对您有帮 ...

  5. Oracle 服务器结构

    [学习目标] 作为一个数据库管理员(DBA),经常会遇到各种没有见过的问题.除了宝贵的经验外, 通过理论基础去对问题进行判断.解决是至关重要的.因此,Oracle 服务器的结构和组成 是学习Oracl ...

  6. 数据流分段下载(Http之 Range)

    public FileStreamResult StreamUploadedSongs(int id) { byte[] song = db.UploadedSongs.Where(x => x ...

  7. (APIO2014)序列分割

    题解: 我也不知道为啥上午上课讲了我昨天看的3题 这题关键在于发现操作顺序无关的 可以发现最终答案是任意两段乘积的和 那这个东西显然是可以dp的 然后可以斜率优化一波 nklongn 另外上课讲的是当 ...

  8. Codeforces Round #395 (Div. 2)

    今天自己模拟了一套题,只写出两道来,第三道时间到了过了几分钟才写出来,啊,太菜了. A. Taymyr is calling you 水题,问你在z范围内  两个序列  n,2*n,3*n...... ...

  9. BZOJ1040 [ZJOI2008]骑士 基环树林(环套树) 树形动态规划

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题意概括 有n个人,每一个人有一个最恨的人. 并且,每一个人有一个权值. 一个人不可以和他最恨的人同时被选中. 现在请你求出在 ...

  10. Python中 各种数字类型的判别(numerica, digital, decimal)

    一. 全角和半角 全角:是指一个全角字符占用两个标准字符(或两个半角字符)的位置. 全角占两个字节. 汉字字符和规定了全角的英文字符及国标GB2312-80中的图形符号和特殊字符都是全角字符.在全角中 ...