现在大多数的移动设备已经变得越来越快,但是它们其实也不算是非常快。如果你想让你的APP既可以承受一些繁杂的工作而又不影响用户体验的话,那么必须把任务并行执行。在Android上,我们使用线程。

端一杯咖啡,然后仔细阅读这篇文章。我会给大家介绍一下线程的概念,还有在Java中怎么使用线程,在线程中怎么使用Handler等。

如果需要使用异步处理或者并行任务的话,那么你一定会用到线程。

什么是线程?

线程或者线程执行本质上就是一串命令(也是程序代码),然后我们把它发送给操作系统执行。

一般来说,我们的CPU在任何时候一个核只能处理一个线程。多核处理器(目前大多数Android设备已经都是多核)顾名思义,就是可以同时处理多线程(通俗地讲就是可以同时处理多件事)。

多核处理与单核多任务处理的实质

上面我说的是一般情况,并不是所有的描述都是一定正确的。因为单核也可以用多任务模拟出多线程。

每个运行在线程中的任务都可以分解成多条指令,而且这些指令不用同时执行。所以,单核设备可以首先切换到线程1去执行指令1A,然后切换到线程2去执行指令2A,接着返回到线程1再去执行1B、1C、1D,然后继续切换到线程2,执行2B、2C等等,以此类推。

这个线程之间的切换十分迅速,以至于在单核的设备中也会发生。几乎所有的线程都在相同的时间内进行任务处理。其实,这都是因为速度太快造成的假象,就像电影《黑客帝国》里的特工Brown一样,可以变幻出很多的头和手。

接下来我们来看一些代码。
Java核心里的线程
在Java中,如果要想做平行任务处理的话,会在Runnable里面执行你的代码。可以继承Thread类,或者实现Runnable接口:

// Version 1
public class IAmAThread extends Thread {public IAmAThread() {super("IAmAThread");}@Overridepublic void run() {// your code (sequence of instructions)}
}
// to execute this sequence of instructions in a separate thread.
new IAmAThread().start();// Version 2
public class IAmARunnable implements Runnable {@Overridepublic void run() {// your code (sequence of instructions)}
}
// to execute this sequence of instructions in a separate thread.
IAmARunnable myRunnable = new IAmARunnable();
new Thread(myRunnable).start();

这两个方法基本上是一样的。第一个版本是创建一个Thread类,第二个版本是需要创建一个Runnable对象,然后也需要一个Thread类来调用它。

第二个版是通常建议使用的方法。这也是一个很大的主题了,超过了本文的范围,以后会再做讨论。
Android上的线程
无论何时启动APP,所有的组件都会运行在一个单独的线程中(默认的)——叫做主线程。这个线程主要用于处理UI的操作并为视图组件和小部件分发事件等,因此主线程也被称作UI线程。

如果你在UI线程中运行一个耗时操作,那么UI就会被锁住,直到这个耗时操作结束。对于用户体验来说,这是非常糟糕的!这也就是为什么我们要理解Android上的线程机制了。理解这些机制就可以把一些复杂的工作移动到其它的线程中去执行。如果你在UI线程中运行一个耗时的任务,那么很有可能会发生ANR(应用无响应),这样用户就会很快地结束掉你的APP。

Android和Java一样,它支持使用Java里面的Thread类来进行一步任务处理。所以可以轻松地像上面Java的例子一样来使用Android上的线程,不过那好像还是有点困难。

为什么在Android上使用标准Java的线程会困难呢?
其实平行任务处理没有想象中的那么简单,你必须在多线程中保证并发,就像伟大的Tim Bray说的那样:ordinary humans can’t do concurrency at scale (or really at all) …

特别对于Android来说,以下这些功能就略显臃肿:

异步对于UI线程来说是一个主要的PITA(如果你需要在后台线程中向主线程更新界面,那么你就会用到)。
如果屏幕方向或者屏幕配置改变的话,就会出现一些更加奇怪的现象。因为改变屏幕方向,会引起Activity重建(所以后台线程就需要去改变被销毁的Activity的状态了,而如果后台线程不是在UI线程之上的话,那情况会更加复杂,原因如条件1)。
对于线程池来说,没有默认的处理方式。
取消线程操作需要自定义代码实现。

那么在Android上怎么进行任务并发处理呢?
你可能听过一些Android上一些常见的名词:

1、Handler
这就是我们今天要讨论的详细主题。

2、AsyncTask
使用AsyncTask是在Android上操作线程最简单的方式,也是最容易出错的方式。

3、IntentService
这种方式需要写更多的代码,但是这是把耗时任务移动到后台的很好的方式,也是我最喜欢的方式。配上使用一个EventBus机制的框架如Otto,这样的话实现IntentService就非常简单了。

4、Loader
关于处理异步任务,还有很多事情需要做,比如从数据库或者内容提供者那里处理一些数据。

5、Service
如果你曾经使用过Service的话,你应该知道这里会有一点误区,其中一个常见的误解就是服务是运行在后台线程的。其实不是!看似运行在后台是因为它们不与UI组件关联,但是它们(默认)是运行在UI线程上的……所以默认运行在UI线程上,甚至在上面没有UI部件。

如果想要把服务运行在后台线程中,那么必须自定义一个线程,然后把操作代码都运行在那个线程中(与上面提到的方法很类似)。事实上你应该使用IntentService实现,但是这不是本文讨论的主题。
Android上的Handler
以下是从 Android developer documentation for Handlers:中摘选的一段话:

A Handler allows you to send and process Message and Runnable objects associated with a thread’s MessageQueue. Each Handler instance is associated with a single thread and that thread’s message queue. When you create a new Handler, it is bound to the thread/message queue of the thread that is creating it — from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.

为了更好地了解这个概念,也许你需要去看看什么是Message Queues。

消息队列
在线程里基本都有一个叫做“消息队列”的东西,它负责线程间通信。这是一种设计模式,所有控制指令或者内容在线程间传递。

消息队列如同它的名字那样,对于线程来说,它就是一个指令队列。这里我们还可以做一些更酷的事:

定时消息和线程在某个时间点才执行。
需要在另一个线程中去添加入队动作,而不是在本线程中。
注意:这里说的“消息”和Runnable对象、指令队列的概念是一样的。

回到Android上的Handler……如果你仔细阅读的话,可以看到文档是这样说的:

A Handler allows you to send and process Message and Runnable objects associated with a thread’s MessageQueue.

所以Handler可以让你给线程队列发消息:

Each Handler instance is associated with a single thread and that thread’s message queue.

一个Handler对象只能和一个线程关联:

When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it

所以一个Handler到底和哪个线程关联呢?就是创造它的线程。

— from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.、

在我们了解这些知识后,请继续看……

小贴士: 这里有几点可能你还不知道。每个线程都和一个Handler类实例绑定,而且可以和别的线程一起运行,相互通信。

还有一个小建议(如果用过AsyncTask的话),AsyncTask内部也是使用Handler进行处理的,只是不是运行在UI线程而已,它会提供一个channel来和UI线程通信,使用postExecute方法即可实现。
这还挺酷的,那怎么创建Handler呢?
有两种方式:

1.使用默认的构造方法:new Handler()。

2.使用带参的构造方法,参数是一个Runnable对象或者回调对象

Handler里面有什么实用的API吗?
请记住:

  • Handler只是简单往消息队列中发送消息而已(或者使用post方式)
  • 它们有更方便的方法可以帮助与UI线程通信。
  • 如果你现在看看Handler的API,可以清楚看到这几个方法:

1.post
2.postDelayed
3.postAtTime

代码示例
这里的代码都是很基础的,不过你可以好好看看注释。

public class TestActivity extends Activity {// ...
// all standard stuff@Override
public void onCreate(Bundle savedInstanceState) {// ...// all standard stuff// we're creating a new handler here// and we're in the UI Thread (default)// so this Handler is associated with the UI threadHandler mHandler = new Handler();// I want to start doing something really long// which means I should run the fella in another thread.// I do that by sending a message - in the form of another runnable object// But first, I'm going to create a Runnable object or a message for thisRunnable mRunnableOnSeparateThread = new Runnable() {@Overridepublic void run () {// do some long operationlongOperation();// After mRunnableOnSeparateThread is done with it's job,// I need to tell the user that i'm done// which means I need to send a message back to the UI thread// who do we know that's associated with the UI thread?mHandler.post(new Runnable(){@Overridepublic void run(){// do some UI related thing// like update a progress bar or TextView// ....}});}};// Cool but I've not executed the mRunnableOnSeparateThread yet// I've only defined the message to be sent// When I execute it though, I want it to be in a different thread// that was the whole point.new Thread(mRunnableOnSeparateThread).start();
}}

如果根本就没有Handler对象,回调post方法会比较难办。

转自http://blog.jobbole.com/73267/

Android线程和Handler基础入门相关推荐

  1. Android——线程通讯 Handler、Looper、Message;

    线程通讯问题 (主要用到了Handler类,Looper类和Message类以及MessageQueue) 在Android中主线程如何向子线程中发送消息的问题.让我们来想想,这其中的过程,无非就是创 ...

  2. Android代码混淆方法,Android 代码混淆零基础入门

    内容提要 本篇文章主要有三个部分,让读者读完后能自己写规则混淆项目 对Android代码怎么开启混淆做一个简单的介绍. 对混淆规则做一个简单介绍: 在混淆过后Crash日志反推代码工具retrace. ...

  3. (4)Android之路====APK基础入门4(ListView控件)

    本次来说一下ListView控件的情况: (一)ListView 概念: ListView是Android中最重要的组件之一,几乎每个Android应用中都会使用ListView.它以垂直列表的方式列 ...

  4. Android线程和线程Handler基础一览

    线程概览 线程是任何多任务系统的基石.可以被认为是一个主进程的多个子进程.这样做的目的就是了增加应用的性能. 应用主线程 当一个Android应用被打开的时候,系统会默认开辟一个线程.这个线程就被叫做 ...

  5. Android基础入门教程——4.3.1 BroadcastReceiver牛刀小试

    Android基础入门教程--4.3.1 BroadcastReceiver牛刀小试 标签(空格分隔): Android基础入门教程 本节引言 本节我们将来学习Android四大组件中的第三个:Bro ...

  6. 最新Android基础入门教程目录(完结版)

    第一章:环境搭建与开发相关(已完结 10/10) https://blog.csdn.net/coder_pig/article/details/50000773 Android基础入门教程--1.1 ...

  7. Android基础入门视频培训教程-刘志远-专题视频课程

    Android基础入门视频培训教程-146257人已学习 课程介绍         Android基础入门视频培训课程,该教程内容涵盖Android入门开发基本技能(环境搭建.Lineralayout ...

  8. 学Android移动开发 第1章 Android基础入门

    文章目录 1.1 Android简介 什么是Android Android和iOS主要区别 1.1.1 通信技术 1.1.2 Android起源 1.1.3 Android体系结构 1.1.4 Dal ...

  9. Android基础入门教程——4.2.3 Service精通

    Android基础入门教程--4.2.3 Service精通 标签(空格分隔): Android基础入门教程 本节引言: 本节,我们继续来研究Service(服务)组件,本节将会学习下Android中 ...

  10. 2015年最新Android基础入门教程目录(完结版)

    2015年最新Android基础入门教程目录(完结版) 标签(空格分隔): Android基础入门教程 前言: 关于<2015年最新Android基础入门教程目录>终于在今天落下了帷幕,全 ...

最新文章

  1. 93. Restore IP Addresses 复原IP地址
  2. centos7怎么重置mysql密码_centOS7.4 重置mysql 密码
  3. 基于人工神经网络的识别C语言,实验一基于人工神经网络的数码识别.doc
  4. Intellij IDEA 快捷键(Mac)
  5. java变量命名规则_变量的概念和声明
  6. java中的链接之其他窗体_两个窗体之间的链接
  7. fast.ai 深度学习笔记:第一部分第五课
  8. 数据科学的原理与技巧 二、数据生成
  9. matlab各种出错,matlab常见错误命令汇总
  10. Telerik RadColorPicker 漂移问题的解决
  11. 《球球大作战》源码解析——(1)运行起来
  12. 发票识别系统流程以及应用场景
  13. Mac下PyCharm快捷键大全
  14. c# vs2019 AForge简单使用
  15. 格雷码与二进制的转换
  16. python 文件格式转换_如何把txt文件转换成py文件
  17. 用php搭建微信公众号淘客三合一系统
  18. 浙江大学计算机学院师资队伍,浙江大学计算机科学与技术学院导师教师师资介绍简介-朱建科...
  19. 写口算用计算机作文600字,口算考试作文600字
  20. MySQL设置索引used in key specification without a key length

热门文章

  1. 自考计算机专业选校,自考本科需要选择学校吗 最实用的专业有哪些
  2. linux nightshift调整,Nightshift
  3. java jedis 取消订阅_Jedis实现频道的订阅,取消订阅
  4. 中关村启动全国首个大数据交易平台
  5. 业界:区块链技术为版权保护与运营提供科技支撑
  6. 和计算机的聊天技巧,实战谈判技巧与话术7计算机软件及应用IT计算机专业资料-实战谈.pdf...
  7. php cms 的模板,phpcms模板
  8. 【CesiumJS入门】(8)自定义鼠标指针图标——地球范围内实现
  9. 剖析垂直搜索引擎,学习指引
  10. python实现opencv学习十六:Canny边缘检测算法