浅析Android线程模型

合集下载

Android进阶——多线程系列之Thread、Runnable、Callable、Future、FutureTask

Android进阶——多线程系列之Thread、Runnable、Callable、Future、FutureTask

Android进阶——多线程系列之Thread、Runnable、Callable、Future、FutureTask前言多线程一直是初学者最抵触的东西,如果你想进阶的话,那必须闯过这道难关,特别是多线程中Thread、Runnable、Callable、Future、FutureTask这几个类往往是初学者容易搞混的。

这里先总结这几个类特点和区别,让大家带着模糊印象来学习这篇文章Thread、Runnable、Callable:都是线程Thread特点:提供了线程等待、线程睡眠、线程礼让等操作Runnable和Callable特点:都是接口,并提供对应的实现方法Runnable、Callable区别:Runnable无返回值,Callable有返回值Future:提供了对Runnable和Callable任务的执行结果进行取消、查询是否完成、获取结果、设置结果等操作FutureTask:Runnable和Future的结合体,即拥有Future的特性Thread和Runnable的关系我们对线程的使用,经常有这两种写法new Thread(new Runnable() {@Overridepublic void run() {//子线程操作}}).start();new Thread(){@Overridepublic void run() {//子线程操作}}.start();这也就是我们要讲的Thread和Runnable的关系,其实它们是一样的,都是线程,最终启动线程后都会执行run()方法里面的内容,具体是怎么一回事,让我们从Thread的源码开始分析class Thread implements Runnable {private Runnable target;//构造函数public Thread(ThreadGroup group, Runnable target) {init(group, target, "Thread-" + nextThreadNum(), 0);}//继续追踪init()方法private void init(ThreadGroup g, Runnable target, String name, long stackSize) { Thread parent = currentThread();if (g == null) {g = parent.getThreadGroup();}g.addUnstarted();this.group = g;this.target = target;this.priority = parent.getPriority();this.daemon = parent.isDaemon();setName(name);init2(parent);/* Stash the specified stack size in case the VM cares */this.stackSize = stackSize;tid = nextThreadID();}}可以看到Thread就是实现Runnable的,所以Thread也可以说是Runnable,它俩就像亲生兄弟一样。

Android系统Surface机制的SurfaceFlinger服务的线程模型分析剖析

Android系统Surface机制的SurfaceFlinger服务的线程模型分析剖析

Android系统Surface机制的SurfaceFlinger服务的线程模型分析在前面两篇文章中,我们分析了SurfaceFlinger服务的启动过程以及SurfaceFlinger服务初始化硬件帧缓冲区的过程。

从这两个过程可以知道,SurfaceFlinger服务在启动的过程中,一共涉及到了三种类型的线程,它们分别是Binder线程、UI渲染线程和控制台事件监控线程。

在本文中,我们就将详细分SurfaceFlinger服务的线程模型,即上述三种类型的线程是如何运行和交互的。

从一文可以知道,SurfaceFlinger服务是在System进程的主线程中启动的。

System进程的主线程在启动系统的关键服务之前,会先启动一个Binder线程池。

这样运行在System进程中的系统关系服务就可以与其它进程执行Binder进程间通信了。

SurfaceFlinger服务虽然是由System进程的主线程来负责启动的,但是最终它会运行在一个独立的线程中。

我们将这个独立的线程称为UI渲染线程,因为它负责渲染系统的UI。

从一文可以知道,SurfaceFlinger服务的UI渲染线程的启动的时候,会对系统的硬件帧缓冲区进行初始化。

在初始化的过程,又会创建另外一个线程来监控硬件帧缓冲区的睡眠/唤醒状态切换事件。

为了方便描述,我们这个线程称称为控制台事件监控线程。

上述的三种类型的线程的启动顺序,可以通过图1来描述,如下所示:从图1就可以清楚地看到,System进程的主线程负责启动Binder线程池,以及UI渲染线程,而UI渲染线程又负责启动控制台事件监控线程。

在这三种类型的线程中,UI渲染线程是主角,Binder线程和控制台事件监控线程是配角。

Binder线程池是为了让其它进程,例如Android应用程序进程,可以与SurfaceFlinger服务进行Binder进程间通信的,有一部分通信所执行的操作便是让UI渲染线程更新系统的UI。

Android多线程

Android多线程

Android多线程作者:陈正最本质的多线程:hanlder和message机制:为何需要多线程:在日常应用中,我们通常需要处理一些“后台,用户不可见”的操作,例如说,我们需要下载一个音乐,要是你的应用必须等用户下载完成之后才可以进行别的操作,那肯定让用户非常的不爽。

这时候,我们通常的做法是,让这些操作去后台执行,然后等后台执行完毕之后,再给用户弹出相应的提示信息。

这时候,我们就需要使用多线程机制,然后通过创建一个新的线程来执行这些操作。

明白了,实现需求,我们就准备着手实现了。

但是,经过进一步的了解,我们悲剧的发现,android中的线程机制是,只能在UI线程中和用户进行交互。

当我们创建了一个新线程,执行了一些后台操作,执行完成之后,我们想要给用户弹出对话框以确认,但是却悲剧的发现,我们根本无法返回UI主线程了。

(说明:何为UI线程:UI线程就是你当前看到的这些交互界面所属的线程)。

这时候,我们如果想要实现这些功能,我们就需要一个android为我们提供的handler 和message机制。

先讲解下编程机制:我们通常在UI线程中创建一个handler,handler相当于一个处理器,它主要负责处理和绑定到该handler的线程中的message。

每一个handler都必须关联一个looper,并且两者是一一对应的,注意,这点很重要哦!此外,looper负责从其内部的messageQueue中拿出一个个的message给handler进行处理。

因为我们这里handler是在UI线程中实现的,所以经过这么一个handler、message机制,我们就可以回到UI线程中了。

何为handler:处理后台进程返回数据的工作人员。

何为message:后台进程返回的数据,里面可以存储bundle等数据格式何为messageQueue:是线程对应looper的一部分,负责存储从后台进程中抛回的和当前handler绑定的message,是一个队列。

Android应用开发中的多线程编程技术详解

Android应用开发中的多线程编程技术详解

Android应用开发中的多线程编程技术详解在Android应用中,当我们需要执行一些耗时的操作,例如网络请求、磁盘读写等,如果在主线程中执行,会导致UI界面卡顿,用户体验下降。

而解决这个问题的办法就是使用多线程编程技术。

本文将详细介绍Android应用开发中的多线程编程技术。

1. 线程的基础知识在Java中,线程就是一个独立的执行单元,它可以独立运行,也可以和其它线程一起协作完成任务。

而在Android中,我们常用的线程有两种:主线程和子线程。

主线程是Android应用的UI线程,负责响应用户的交互事件,执行UI更新操作;而子线程则是我们在应用中创建的线程,用于执行耗时的操作。

在Java中,有两种方式来创建线程:继承Thread类和实现Runnable接口。

其中,实现Runnable接口是更加常用的做法,因为它能够避免单继承的限制。

下面是一个简单的示例代码,实现了一个通过实现Runnable接口创建子线程的例子:```public class MyThread implements Runnable {@Overridepublic void run() {// 子线程要执行的任务}}// 在主线程中创建子线程MyThread myThread = new MyThread();Thread thread = new Thread(myThread);thread.start();```当我们创建了一个子线程后,它就会独立地运行在一个新的线程中。

在子线程中,我们可以执行一些耗时的操作,并且不会卡住主线程。

2. Android中的主线程在Android应用中,主线程是非常重要的,它负责维护UI界面的显示和交互,处理用户的输入事件,并更新UI的状态。

因此,在主线程中执行一些耗时的操作,就会使得UI界面出现卡顿现象,用户体验大大降低。

为了避免这种情况,Android系统引入了一种机制,叫做ANR (Application Not Responding)。

Android UI线程分析

Android UI线程分析

理解UI线程——swt, Android, 和Swing的UI机理线程在做GUI的时候, 无论是SWT, AWT, Swing 还是Android, 都需要面对UI线程的问题, UI线程往往会被单独的提出来单独对待, 试着问自己,当GUI启动的时候, 后台会运行几个线程? 比如1. SWT 从Main函数启动2. Swing 从Main函数启动3. Android 界面启动常常我们被告知, 主线程, UI线程, 因此这里很多会回答, 有两个线程, 一个线程是Main, 另外一个是UI. 如果答案是这样, 这篇文章就是写给你的。

OK, 我们以SWT为例, 设计以下方案寻找答案, 第一步, 我们看能否找到两个线程:1. 从Main中启动SWT的界面, 在启动界面前, 将Main所在的线程打印出来这里设计为Shell中嵌入一个Button2. 点击Button, 运行一个耗时很长的操作, 反复修改Button的文字, 在该线程中打印该线程的名称代码是这样的:1.publicstaticvoid main(String[] args) {2.final Display display = Display.getDefault();3.final Shell shell = new Shell();4. shell.setSize(500, 375);5. shell.setText("SWT Application");6. shell.setLayout(new FillLayout());7. btn = new Button(shell, SWT.NULL);8. btn.setText("shit");9. registerAction();10. shell.open();11. yout();12.while (!shell.isDisposed()) {13.if (!display.readAndDispatch())14. display.sleep();15. }16. shell.dispose();17. display.dispose();18.}19.privatestaticvoid registerAction() {20. btn.addMouseListener(new MouseListener() {21. @Override22.publicvoid mouseDoubleClick(MouseEvent e) {23. // TODO Auto-generated method stub24. }25. @Override26.publicvoid mouseDown(MouseEvent e) {27. methodA();28. }29. @Override30.publicvoid mouseUp(MouseEvent e) {31. }32. });33.}34./**35.* 持续的跑动, 打印线程的名称, 注意拖拽不动, 界面死掉, 直到跑完36.*/37.privatestaticvoid methodA() {38.for (int i = 0; i < count; i++) {39. haveArest(300);40. System.out.println("MethodA:" +Thread.currentThread().getName());41. btn.setText(i + "");42. }43.}haveArest方法在最后出现, 只是封装了一个让线程等待一段时间, 打印的结果都为main, 于是得到第一个重要的结论:UI所在的线程和Main所在的线程都是同一个线程。

Android 线程模型和AsyncTask

Android 线程模型和AsyncTask

Android 线程模型和AsyncTaskandroid 的线程模型:当一个android 的应用运行后,就会有一个UI 的main 线程启动, 这是一个非常重要的线程,它负责把事件分派到相应的控件,其中就包括屏幕绘图事件,它同样是用户与android 控件交互的线程。

比如,当你在屏幕上的EditText 上输入文字,UI 线程会把这个事件分发给刚输入文字的EditText ,紧接会向事件队列发送一个更新(invalidate )请求。

UI 线程会把这个请求移出事件队列并通知EditText 在屏幕上重新绘制自身。

这种单线线程模型就会使得android 的应用程序性能低下,如果在这个单线程里执行一些耗时的操作,比如访问数据库,或是从网络端下载图片,就会会阻塞整个用户界面。

比如如下操作:view sourceprint ?1 Bitmap b = l oadImageFromNetwork();这个操作非常耗时,在这种情况下你会发现, 界面僵死在那里并且android 在系统5 秒中后没有反应,会显示一个关闭或等待的错误。

也许我们可以使用一个新的Thread 来解决它view sourceprint ?1 newThread(newRunnabl e() {2 publicvoidrun() {3 Bitmap b = l oadImageFromNetwork();4 mImageView.setImageBitmap( b );5 }6 }).start();但这样会发生一些很难察觉的错误,因为我们知道UI 线程不是线程安全的。

当然有很多种方法来处理这个问题:android 提供了几种在其他线程中访问UI 线程的方法。

•Activity.runOnUiThread( Runnabl e )•View.post( Runnabl e )•View.postDelayed( Runnabl e, l ong )•Hanl derview sourceprint ?1 newThread(newRunnabl e() {2 publicvoidrun() {3 finalBitmap b = l oadImageFromNetwork();4 mImageView.post(newRunnabl e() {5 mImageView.setImageBitmap( b );6 });7 }8 }).start();这种方法比较繁琐,同时当你需要实现一些很复杂的操作并需要频繁地更新UI 时这会变得更糟糕。

Android 多线程详解

Android 多线程详解

Thread类常用方法(1)public static Thread currentThread():返回当前调用的线程(2)public final String getName():返回当前线程名称(3)public long getId():返回当前线程标识id(4)public final void setName(String threadName):设置线程名称(5)public void start():执行一个新的线程(6)public final void stop():关闭一个线程,不推荐使用因为该方法可能会产生死锁,推荐使用在Thread中设置标识符结束运行的代码(7)public static void sleep(long time):等待一段时间后在运行线程,单位是毫秒进程概念在同一时间内执行多个程序的操作系统都有进程的概念。

一个进程就是一个执行中的程序,而每一个进程都有自己独立的一块内存空间、一组系统资源。

在进程的概念中,每一个进程的内部数据和状态都是完全独立的。

在Windows操作系统下我们可以通过〈Ctrl+Alt+Del〉组合键查看进程,在UNIX和Linux操作系统下是通过PS命令查看进程的。

打开Windows 当前运行的进程,如图在Windows操作系统中一个进程就是一个exe或dll程序,它们相互独立,互相也可以通信,在Android操作系统中进程间的通信应用也是很多Android空进程线程概念多线程指的是在单个程序中可以同时运行多个不同的线程,执行不同的任务。

多线程意味着一个程序的多行语句可以看上去几乎在同一时间内同时运行。

线程与进程相似,是一段完成某个特定功能的代码,是程序中单个顺序的流控制。

但与进程不同的是,同类的多个线程共享一块内存空间和一组系统资源,所以系统在各个线程之间切换时,资源占用要比进程小得多,正因如此,线程也被称为轻量级进程。

一个进程中可以包含多个线程。

Android系统的进程和线程

Android系统的进程和线程

Android中进程和线程当一个应用程序开始运行它的第一个组件时,Android会为它启动一个Linux进程,并在其中执行一个单一的线程。

默认情况下,应用程序所有的组件均在这个进程的这个线程中运行(就是我们常说的android app主线程)。

然而,你也可以安排组件在其他进程中运行,而且可以为任意进程创建额外的线程。

本章主要介绍android app下的线程和进程是如何工作的5.1 进程默认情况下,同一应用程序的所有组件运行在同一进程中。

不过,如果你需要控制某个组件属于哪个进程,也可以通过修改manifest文件来实现。

manifest文件中的所有组件节点如<activity>,<service>,<receiver>,<provider>都支持android:process这个属性并可以指定一个进程,这样这些组件就会在指定的进程中运行。

你可以设置这个属性使每个组件运行于其自己的进程或只是其中一些组件共享一个进程。

你也可以设置android:process让不同应用中的组件可以运行在同一个进程,但这样需要这些应用共享同一个Linux用户ID并且有相同的数字证书签名。

<application>元素也支持android:process属性,用于为所有的组件指定一个默认值,并应用于所有组件,如果你有这样的需求,可以省点事。

Android系统可能在某些时刻决定关闭一个进程,比如内存很少并且其他进程更迫切的需要服务用户而启动的情况。

进程被kill掉后,其中的组件们都被销毁。

如果再次需要这些组件工作时,进程又会被重新创建出来。

当系统决定关闭哪个进程时,Android系统会衡量进程与用户的相对重要性。

例如,比起一个在前台可见的activity所在的进程,和那些在后台不可见的activity所在的进程相比,显然后者更容易被系统关闭。

是否决定一个终止进程,取决于进程中所运行组件的状态。

剖析Android多线程

剖析Android多线程

Java- Android 多线程一.Java Thread 小结:1. 我们要实现多线程,必须编写一个继承了Thread 类的子类,子类要覆盖Thread 类中的run 函数,在子类的run 函数中调用想在新线程上运行的程序代码。

2. 启动一个新的线程,我们不是直接调用Thread 的子类对象的run 方法,而是调用Thread 子类对象的start (从Thread 类中继承的)方法,Thread 类对象的start 方法将产生一个新的线程(注意:对于同一个Thread对象,多次使用start方法,并不会创建多个线程!),并在该线程上运行该Thread 类对象中的run 方法,根据面向对象的多态性,在该线程上实际运行的是Thread 子类(也就是我们编写的那个类)对象中的run 方法。

3. 由于线程的代码段在run 方法中,那么该方法执行完成以后线程也就相应的结束了,因而我们可以通过控制run 方法中的循环条件来控制线程的终止。

二.用Runnable 接口创建多线程在JDK 文档中,我们还看到了一个Thread(Runnable target) 构造方法。

Runnable 是一个接口,不是一个线程,一般线程会实现Runnable。

从JDK 文档中查看Runnable 接口类的帮助,该接口中只有一个run() 方法,当我们使用Thread(Runnable target) 方法创建线程对象时,需为该方法传递一个实现了Runnable 接口的类对象。

这样创建的线程将调用那个实现了Runnable 接口的类对象中的run() 方法作为其运行代码(所以我们自己要实现Runnable的Run方法),而不再调用Thread 类中的run 方法了。

当然,还是要对Thread对象调用start方法的。

三.实现Runnable 接口相对于继承Thread 类来说,有如下显著的好处:1 、适合多个相同程序代码的线程去处理同一资源的情况,2 、可以避免由于Java 的单继承特性带来的局限。

12-Android 中的多线程

12-Android 中的多线程

Android中的多线程
线程之间的通信
– 概念介绍
Looper
– 该类用来为一个线程维护一个消息队列 – 默认的线程是没有和一个Looper实例关联的,需要在线程中使 用Looper.prepare();关联一个线程,使用Looper.loop()处理消 息直到结束 – 详细见文档
Android中的多线程
– 维护一个消息列表,该列表中的消息通过Looper对象来分发. – 调用Looper.myQueue()方法可以获得一个MessageQueue对 象.
Android中的多线程
线程之间的通信
– 概念介绍
Handler
– 用来处理消息和线程 – 每个Handler实例关联一个单线程和该线程的一个消息队列 – Handler可以执行一个线程对象(Runnable实现)也可以发送和处理 Handler Runnable 消息 post(Runnable) postAtTime(Runnable, longห้องสมุดไป่ตู้, postDelayed(Runnable, long), sendEmptyMessage(int) sendMessage(Message) sendMessageAtTime(Message, long) sendMessageDelayed(Message, long) handleMessage(Message)
OnClickListener l = new OnClickListener() { @Override public void onClick(View v) { //new UpdateThread().start(); new ChangeTask().execute("abc"); } };

从现实生活中理解android 线程消息机制

从现实生活中理解android 线程消息机制

从现实生活中理解线程消息机制android 有一种叫消息队列的说法,这里我们可以这样理解:假如一个隧道就是一个消息队列,那么里面的每一部汽车就是一个一个消息,这里我们先忽略掉超车等种种因素,只那么先进隧道的车将会先出,这个机制跟我们android 的消息机制是一样的。

Android 的线程消息机制android 在设计的时候引入了 wince 的消息机制,即将每一个消息发送到队列里面,遵循先进先出原则。

发送消息并不会阻塞线程,而接收线程会阻塞线程,这是因为 Android 的Handler 机制,当Handler 处理完一个 Message 对象才会接着去取下面一个消息进行处理,如下图:这里记住:Android里并没有Global的Message Queue数据结构,例如,不同APK里的对象不能透过Massage Queue来交换讯息(Message)。

例如:线程A的Handler对象可以传递消息给别的线程,让别的线程B或C等能送消息来给线程A(存于A的Message Queue里)。

线程A的Message Queue里的讯息,只有线程A所属的对象可以处理。

案例分析:经典的歌词同步,这时我们不仅要听到优质的歌曲,还要可以有歌词同步,这时另开一条线程来处理歌词的同步是比较好的解决办法,你可以根据自己的定义,抓取歌曲的duration 在线程中处理歌词的前进或者后退。

Demo 分析:下面我们来实现一个Iphone 上的一个通过按数字后,数字过多消除的按钮事件。

事件的原理如下,事件要的效果是这样的,当长按消除按钮后,数字会慢慢消除,过会消除速度会增快,那么实现这个效果我们就需要自己做一个小键盘,我做的键盘效果如下:我们通过点击来达到这个效果,使用的是android 的线程机制。

实现代码如下:private Thread thread;private TextView tv_call_no;protected static Runnable Runablerun = null;private Handler handler;private int textLength = 0;private boolean isStop = true;首先将要使用的数据类型声明在头部,将会使用到 java 的 Thread 和Android Handler 对象,首先实现Runable 对象,代码如下:Runablerun = new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubtry {int i = 0;do {i++;Thread.sleep(i > 15 ? 20 : 100);Message msg = handler.obtainMessage();msg.arg1 = i;msg.sendToTarget();if (i == textLength) {isStop = false;}} while (isStop);} catch (Exception e) {// TODO: handle exception}}};上面代码还可以如此写法:Message msg=new Message();msg.arg1=i;handler.sendMessage(msg);第一种写法是message 从handler 类获取,从而可以直接向该handler 对象发送消息,第二种写法是直接调用 handler 的发送消息方法发送消息。

Android应用开发中的多线程编程技术详解

Android应用开发中的多线程编程技术详解

Android应用开发中的多线程编程技术详解随着移动设备不断普及,Android应用的用户数量愈加庞大,因此,开发高质量、高效率的Android应用已经成为了一种竞争优势。

而在Android应用开发中,多线程编程技术就是必不可少的一个重要领域。

本文将详细探讨Android应用开发中的多线程编程技术,包括线程的概念、线程池和Handler机制、异步任务和Loader、消息队列和消息循环机制等内容。

通过深入了解这些多线程编程技术,开发者们可以更好地开发出高效率、高响应程序与丝滑顺畅的用户体验。

一、线程的概念线程可以理解为是一种轻量级进程(Lightweight Process),它是计算机中已被分配了系统资源的基本单位,可以执行一系列指令序列,并将结果返回给主线程。

在Android中,每个应用程序都是单独的进程,而每个进程又可以包含多个线程,这些线程使用操作系统调度算法来分享CPU资源,从而提高程序的执行效率和响应速度。

在Android中启动一个线程很简单,只需要使用Thread类即可。

一般情况下,我们需要自己定义一个类,这个类必须继承自Thread类,并重写其中的run()方法,run()方法中包含了子线程的代码逻辑。

下面是一个简单的线程启动示例:```javapublic class MyThread extends Thread {@Overridepublic void run() {// 线程代码逻辑super.run();}}//在主线程中启动MyThread线程MyThread thread = new MyThread();thread.start();```二、线程池和Handler机制虽然线程可以提高程序的响应速度和执行效率,但同时也存在一些问题。

比如,线程开启和销毁需要不少的时间和开销,频繁地调用可能会对系统稳定性产生影响。

因此,Android提供了线程池和Handler机制来解决这些问题。

android多线程讲解 看图理解

android多线程讲解 看图理解

本期的多线程主题与Android相关,侧重讲解在Android中如何用好多线程,需要你有Java 的多线程基础。

首先我们思考几个问题,在Android应用中为什么要用多线程?为了解决哪些问题?或者为了实现哪些功能?有哪些好处?请先思考一分钟,再继续往下看。

学习而不思考就像吃东西而不嚼,要么无法下咽,要么尝不出味道,同时都会影响消化吸收。

控制一下你那脱缰野马一样的好奇心吧,先思考再往下看。

————————————————飘过这条分隔线,我们继续——————————————————1.为什么要用多线程这里列出几个原因:a) 提高用户体验或者避免ANR在事件处理代码中需要使用多线程,否则会出现ANR(Application is not responding),或者因为响应较慢导致用户体验很差。

图1 ANR对话框b) 异步应用中有些情况下并不一定需要同步阻塞去等待返回结果,可以通过多线程来实现异步,例如:上一点中提到的,你的应用中的某个Activity需要从云端获取一些图片,加载图片比较耗时,这时需要使用异步加载,加载完成一个图片刷新一个,见下面图2、图3 。

c) 多任务例如多线程下载。

后两点与Java中的多线程应用没有太大区别,不细说。

下面重点说明第一点,即如何减少事件响应的时间从而提高用户体验,以及如何避免ANR。

2.为什么通过多线程可以提高用户体验、避免ANR大家还记得我在群里说过的移动开发的“三不要”原则吗?即:不要让我想、不要让我等、不要让我烦。

响应慢了用户需要等,等的次数多了就会烦,你的应用离被卸载不远了。

首先我们来了解一下Android应用程序的main线程,它负责处理UI的绘制,Android系统为了防止应用程序反应较慢导致系统无法正常运行做了一个处理,一种情况是当用户输入事件在5秒内无法得到响应,那么系统会弹出ANR对话框,由用户决定继续等待还是强制结束应用程序(另一种情况是BroadcastReciever 超过10秒没执行完也会弹出ANR对话框)。

【推荐下载】Android多线程理解

【推荐下载】Android多线程理解

Android 多线程理解2017/03/29 0 Android 理解多线程安卓应用程序通常是应用在一个单独的线程里的,即为主线程,用于显示用户界面以及响应用户的操作。

如果一些耗时任务也同时在主线程里去完成,则会影响用户体验,会阻塞UI 主线程。

我们会创建一个单独的线程或者子线程,去处理这些耗时操作(如网络请求、数据库操作等)。

那么这些子线程就是AsyncTask、Thread、HandlerThread,它们叫做安卓的工作者线程。

- AsyncTask - Handler一、AsyncTask 异步任务AsyncTask 是Android 的一个轻量级异步类,可以自定义类并继承AsyncTask,实现异步任务处理操作。

并且AsyncTask 提供了接口返回异步操作的进度,最后会返回结果到UI 主线程中。

优点:简单快捷,过程可以控制缺点:在处理多个异步操作时比较复杂参数说明Params 启动任务时输入的执行参数,一般为一个网络地址Progress异步任务执行的进度Result 异步任务执行后的结果的类型代码实例这是一个利用AsyncTask 加载网络图片的代码:public class MainActivity extends ActionBarActivity { private Button button1; private ImageView imageview1; private ProgressDialog dialog;private String image_uri=”https://imgsa.baidu/baike/c0%3Dbaike272%2C5%2C5%2C272%2C90/sign=c4f298bb9 7ef76c6c4dff379fc7f969f/9358d109b3de9c82f077b3156b81800a19d8431d.jpg”;@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(yout.activity_main); dialog = new ProgressDialog(this); dialog.setTitle(“图片下载”);dialog.setMessage(“正在下载,请稍后…”);button1 = (Button) findViewById(R.id.button1); imageview1 = (ImageView) findViewById(R.id.imageView1); button1.setOnClickListener(new OnClickListener() {@Override public void onClick(View v) { // TODO Auto-generated method stub new。

Android线程模型(Painless Threading)

Android线程模型(Painless Threading)

当第一次启动一个Android 程序时,Android 会自动创建一个称为“main”主线程的线程。

这个主线程(也称为UI 线程)很重要,因为它负责把事件分派到相应的控件,其中就包括屏幕绘图事件,它同样是用户与Andriod 控件交互的线程。

比如,当你在屏幕上按下一个按钮后,UI 线程会把这个事件分发给刚按得那个按钮,紧接着按钮设置它自身为被按下状态并向事件队列发送一个无效(invalidate )请求。

UI 线程会把这个请求移出事件队列并通知按钮在屏幕上重新绘制自身。

单线程模型会在没有考虑到它的影响的情况下引起Android 应用程序性能低下,因为所有的任务都在同一个线程中执行,如果执行一些耗时的操作,如访问网络或查询数据库,会阻塞整个用户界面。

当在执行一些耗时的操作的时候,不能及时地分发事件,包括用户界面重绘事件。

从用户的角度来看,应用程序看上去像挂掉了。

更糟糕的是,如果阻塞应用程序的时间过长(现在大概是5秒钟)Android 会向用户提示一些信息,即打开一个“应用程序没有相应(application not responding )”的对话框。

如果你想知道这有多糟糕,写一个简单的含有一个按钮的程序,并为按钮注册一个单击事件,并在事件处理器中调用这样的代码Thread.sleep(2000)。

在按下这个按钮这后恢复按钮的正常状态之前,它会保持按下状态大概2秒钟。

如果这样的情况在你编写的应用程序中发生,用户的第一反应就是你的程序运行很慢。

现在你知道你应该避免在UI 线程中执行耗时的操作,你很有可能会在后台线程或工作者线程中执行这些耗时的任务,这样做是否正确呢?让我们来看一个例子,在这个例子中按钮的单击事件从网络上下载一副图片并使用ImageView来展现这幅图片。

代码如下:new Thread( new Runnable() { public voidrun() { Bitmap b = loadImageFromNet work(); mImageView.setIma geBitmap( b ); }这段代码好像很好地解决了你遇到的问题,因为它不会阻塞UI 线程。

浅论Android线程模型

浅论Android线程模型

万方数据
2009
09 中 · 国 电 子 商 务
71
通 讯 桥 梁 的 角 色 。程 序 组 件 首 先 通 过 消 息 传 递 给 Handler 把 Looper, Looper 把 消 息 放 入 队 列 。Looper 也 把 消 息 队 列 里 的 消 息 广 播 给 所 有 的 受 到 消 息 后 调 用 Handler, Handler 接 han 行 处 理 。 dleMessage 进 在 了 解 了 消 息 队 列 及 其 相 关 组 件 的 设 计 思 想 后 , 我 们 将 把 天 气 预 报 的 案 例 通 过 消 息 队 列 来 重 新 实 现 : public void onCreate( Bundle savedInstanceState){ … … ) ; Looper looper = Looper. myLooper( 处 甚 至 可 以 不 需 要 设 置 因 为 认 就 / /此 Looper, Handler 默 Looper 使 用 当 前 线 程 的 looper) messageHandler = new MessageHandler( ; } public void onClick( View v){ / /创 建 一 个 子 线 程 去 做 耗 时 的 网 络 连 接 工 作 ){ new Thread( @ Override public void run( ){ 动 用 户 输 入 的 城 市 名 称 / /活 String city = editText. getText( . toString( ) ) ; 用 气 询 指 定 城 市 的 当 日 天 气 情 况 / /调 Google 天 API 查 ; String weather = getWetherByCity( city) / /创 Message 对 建 一 个 象 , 并 把 得 到 的 天 气 信 息 赋 值 给 象 Message 对 ) ; Message message = Message. obtain( message. obj = weather; 过 布 携 带 有 天 气 情 况 的 消 息 / /通 Handler 发 messageHandler. sendMessage( message) ; } ) ; . start( } } 类 化 一 个 / /子 Handler 67 页 ses 公 司 内 小 量 用 户 使 用 服 务 器 压 力 不 大 , 用 (上 接 )是 用 户 登 录 信 息 保 存 在 服 务 器 端 还 可 方 便 查 询 。另 外 注 sion 把 示 。注 册 后 进 册 用 户 后 会 自 动 为 用 户 登 录 到 系 统 , 如 ( 图 1 )所 3) 入 ( 图 状 态 。 3. 3 新 建 记 录 新 建 记 录 ( 三 种 类 型 ) 是 一 个 页 面 实 现 的 , 其 好 处 也 是 方 便 代 码 维 护 程 序 升 级 更 加 容 易 , 在 选 择 类 型 时 , 会 按 记 录 类 型 和 不 同 的 用 户 权 限 显 示 相 应 的 选 项 : 工 作 联 系 , 需 要 指 定 接 收 者 , 指 定 审 核 者 , 计 划 完 成 时 间 ; 工 作 安 排 , 需 要 指 定 接 收 者 , 计 划 完 成 时 间 ; 工 作 记 录 , 只 需 要 添 写 计 划 完 成 时 间 。只 有 领 导 可 所 示 。 2) 以 发 工 作 安 排 , 一 般 用 户 不 能 新 建 工 作 安 排 。如 ( 图 3. 4 查 看 记 录 查 看 记 录 时 可 以 显 示 记 录 类 型 , 发 送 者 , 接 收 者 , 标 题 内 容 , 录 入 时 间 , 计 划 完 成 时 间 , 是 否 签 收 , 是 否 完 成 , 和 查 看 详 细 。详 细 说 明 如 下 : 如 果 是 工 作 记 录 , 则 新 建 记 录 时 发 送 者 和 接 收 者 自 动 设 置 真 ) 。 Y( 为 新 建 记 录 的 用 户 。同 时 已 签 收 也 记 录 为 是 否 签 收 , 主 要 用 在 工 作 联 系 和 工 作 安 排 中 , 工 作 分 配 给 谁 , 谁 就 需 要 签 收 , 签 收 说 明 签 收 人 已 经 知 道 此 事 , 并 会 记 录 签 收 时 间 。而 工 作 联 系 还 需 要 审 核 , 意 思 是 发 起 的 工 作 联 系 单 需 要 谁 知 道 这 件 事 , 并 同 意 方 可 生 效 。 查 看 记 录 时 , 有 三 种 颜 色 显 示 每 一 行 , 分 别 为 黄 色 , 橙 色 和 绿 色 , 黄 色 表 示 未 完 成 记 录 , 橙 色 表 示 未 签 收 记 录 , 绿 色 表 示 已 完 成 记 录 。 考 虑 到 以 后 记 录 可 能 会 很 多 , 系 统 还 设 计 了 分 页 显 示 功 能 , 可 设 置 每 页 显 示 记 录 数 。 查 看 详 细 会 显 示 记 录 的 详 细 内 容 , 查 看 详 细 界 面 与 新 建 记 录 界 面 类 似 , 只 是 在 详 细 内 容 界 面 还 可 以 添 加 本 记 录 的 备 注 。

Android的单线程模型

Android的单线程模型

Android的单线程模型当⼀个程序第⼀次启动时,Android会同时启动⼀个对应的主线程(Main Thread),主线程主要负责处理与UI相关的事件,如:⽤户的按键事件,⽤户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进⾏处理。

所以主线程通常⼜被叫做UI线程。

在开发Android 应⽤时必须遵守单线程模型的原则: Android UI操作并不是线程安全的并且这些操作必须在UI线程中执⾏。

如果在⾮UI线程中直接操作UI线程,会抛出android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views,这与普通的java程序不同。

由于UI线程负责事件的监听和绘图,因此,必须保证UI线程能够随时响应⽤户的需求,UI线程⾥的操作应该向中断事件那样短⼩,费时的操作(如⽹络连接)需要另开线程,否则,如果UI线程超过5s没有响应⽤户请求,会弹出对话框提醒⽤户终⽌应⽤程序。

如果在新开的线程中需要对UI进⾏设定,就可能违反单线程模型,因此android采⽤⼀种复杂的Message Queue机制保证线程间通信。

Message Queue:Message Queue是⼀个消息队列,⽤来存放通过Handler发布的消息。

Android在第⼀次启动程序时会默认会为UI thread创建⼀个关联的消息队列,可以通过Looper.myQueue()得到当前线程的消息队列,⽤来管理程序的⼀些上层组件,activities,broadcast receivers 等等。

你可以在⾃⼰的⼦线程中创建Handler与UI thread通讯。

通过Handler你可以发布或者处理⼀个消息或者是⼀个Runnable的实例。

每个Handler都会与唯⼀的⼀个线程以及该线程的消息队列管理。

Android主线程和子线程区别详解

Android主线程和子线程区别详解

Android主线程和⼦线程区别详解主线程和⼦线程的区别每个线程都有⼀个唯⼀标⽰符,来区分线程中的主次关系的说法。

线程唯⼀标⽰符:Thread.CurrentThread.ManagedThreadID;UI界⾯和Main函数均为主线程。

被Thread包含的“⽅法体”或者“委托”均为⼦线程。

委托可以包含多个⽅法体,利⽤this.Invoke去执⾏。

也可以定义多种⽅法体,放在Thread⾥⾯去执⾏。

则此⽅法体均为⼦线程。

注意如果要修改UI界⾯的显⽰。

则需要使⽤this.Invoke,否则会报异常。

Main函数为主线程,id标⽰符与UI界⾯主线程相等不多说了。

看下⾯的测试代码注释吧。

public delegate void dele();public partial class Form1 : Form{int idA;public dele getlab;public Form1(){InitializeComponent();idA = Thread.CurrentThread.ManagedThreadId;//UI界⾯主线程/** Main函数为主线程,id标⽰符与UI界⾯主线程相同。

*/}Thread thread;private void getbtu_Click(object sender, EventArgs e)//UI控件属于主线程{int idB = Thread.CurrentThread.ManagedThreadId;getlab = new dele(getLabel);//委托添加⽅法getlab += new dele(gg);//委托在叠加⼀个⽅法getlab += new dele(kk);//委托在叠加⼀个⽅法//thread = new Thread(new ThreadStart(delegate{int idC = Thread.CurrentThread.ManagedThreadId;//Thread开辟⼀个⼦线程//gg();//⽅法直接在thread⾥⾯调⽤均为⼦线程//kk();//⽅法直接在thread⾥⾯调⽤均为⼦线程getlab();//委托直接在thread⾥⾯调⽤,委托⾥⾯的⽅法为⼦线程//以上因为都包含在thread⾥⾯MessageBox.Show("显⽰完成");//this.Invoke(getlab);/*错误提⽰:主线程调⽤主线程当然会假死*/}));thread.IsBackground = true;thread.Start();}public void kk()//委托中的⽅法委托⽅法三{int idR = Thread.CurrentThread.ManagedThreadId;this.Invoke((dele)(() =>//修改UI界⾯值则需要加this.Invoke{label2.Text = "ABC";}));}public void gg()//委托中的⽅法委托⽅法⼆{int idP = Thread.CurrentThread.ManagedThreadId;this.Invoke((dele)(() =>//修改UI界⾯值则需要加this.Invoke{label3.Text = "QWE";}));}public void getLabel()//委托中的⽅法委托⽅法⼀{int idD = Thread.CurrentThread.ManagedThreadId;//⼦线程for (int i = 0; i <= 1000; i++){Thread.Sleep(10);//this.Invoke为主线程,执⾏⼦线程的内容this.Invoke((dele)(() =>{getlabel.Text = i.ToString();int idE = Thread.CurrentThread.ManagedThreadId;//主线程Console.WriteLine("线程idE:" + idE);}));Console.WriteLine(i);}MessageBox.Show("显⽰完成");}private void sleepbtu_Click(object sender, EventArgs e)//UI控件属于主线程{int idF = Thread.CurrentThread.ManagedThreadId;try{if (thread.ThreadState != ThreadState.Suspended){thread.Suspend();}}catch (Exception r){MessageBox.Show(r.Message);}}private void setbtu_Click(object sender, EventArgs e)//UI控件属于主线程{int idG = Thread.CurrentThread.ManagedThreadId;try{if (thread.ThreadState != ThreadState.Running){thread.Resume();}}catch (Exception r){MessageBox.Show(r.Message);}}public void getlabel_Click(object sender, EventArgs e){}}总结:1. 什么是⼦线程?包含在 Thread thread = new Thread(new ThreadStart(delegate{}));⾥⾯均视为⼦线程。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Button button = (Button) findViewById(R.id.goQuery);
button.setOnClickListener(this);
}
@Override
public void onClick(View v) {
} finally {
httpClient.getConnectionManager().shutdown();
}
return NETWORK_ERROR;
}
}
当用户输入城市名称,然后单击按钮进行查询后,程序会调用Google API的接口获得指定城市的当日天气情况。由于需要访问网络,所以当网络出现异常或者服务繁忙的时候都会使访问网络的动作很耗时。本文为了 要演示超时的现象,只需要制造一种网络异常的状况,最简单的方式就是断开网络连接,然后启动该程序,同时触发一个用户事件,比如按一下MENU键, 由于主线程因为网络异常而被长时间阻塞,所以用户的按键事件在5秒 钟内得不到响应,Android会 提示一个程序无法响应的异常,如下图:
l 后台进程
运行着一个对用户不可见的activity(调用过 onStop() 方法).这些进程对用户体验没有直接的影响,可以在服务进程、可见进程、前台进 程需要内存的时候回收。通常,系统中会有很多不可见进程在运行,他们被保存在LRU (least recently used) 列表中,以便内存不足的时候被第一时间回收。如果一个activity正 确的执行了它的生命周期,关闭这个进程对于用户体验没有太大的影响。
//获得用户输入的城市名称
String city = editText.getText().toString();
//调用Google 天气API查询指定城市的当日天气 情况
String weather = getWetherByCity(city);
super.onCreate(savedInstanceState);
setContentView(yout.main);
editText = (EditText) findViewById(R.id.weather_city_edit);
public void onClick(View v) {
//创建一个子线程执行耗时的从网络上获取天气信息的操作
new Thread() {
@Override
public void run() {
//把天气信息显示在title上
setTitle(weather);
}
public String getWetherByCity(String city) {
HttpClient httpClient = new DefaultHttpClient();
2单线程模型
当一个程序第一次启动时,Android会同时启动一个对应的 主线程(Main Thread),主线程主要负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事 件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线 程。在开发Android应用时必须遵守单线程模型的原则: Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。
l 空进程
未运行任何程序组件。运行这些进程的唯一原因是作为一个缓存,缩短下次程序需要重新使用的启动时间。系统经常中止这些进程,这样可以调节程序缓存和系统缓 存的平衡。
Android 对进程的重要性评级的时候,选取它最高的级别。另外,当被另外的一个进程依赖的时候,某个进程的级别可能会增高。一个为其他进程服务的进程永远不会比被服 务的进程重要级低。因为服务进程比后台activity进程重 要级高,因此一个要进行耗时工作的activity最好启动一 个service来做这个工作,而不是开启一个子进程――特别 是这个操作需要的时间比activity存在的时间还要长的时 候。例如,在后台播放音乐,向网上上传摄像头拍到的图片,使用service可 以使进程最少获取到“服务进程”级别的重要级,而不用考虑activity目 前是什么状态。broadcast receivers做费时的工作的时候,也应该启用一个服务而不是开一个线程。
该对话框会询问用户 是继续等待还是强行退出程序。当你的程序需要去访问未知的网络的时候都会可能会发生类似的超时的情况,用户的响应得不到及时的回应会大大的降低用户体验。 所以我们需要参试以别的方式来实现
2.1 子线程更新UI
显然如果你的程序需要执行耗时的操作的话,如果像上例一样由主线程来负责执行 该操作是错误的。所以我们需要在onClick方 法中创建一个新的子线程来负责调用GOOGLE API来获得天气数据。刚接触Android的 开发者最容易想到的方式就是如下:
public class WeatherReport extends Activity implements OnClickListener {
private static final String GOOGLE_API_URL = "/ig/api?weather=";
//获得用户输入的城市名称
String city = editText.getText().toString();
//调用Google 天气API查询指定城市的当日天气 情况
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
httpGet.abort();
} else {
HttpEntity httpEntity = response.getEntity();
private static final String NETWORK_ERROR = "网络异常";
private EditText editText;
@Override
public void onCreate(Bundle savedInstanceState) {
1引言
Android一词本义指机器人,Google于2007年11月发布了以Android命名的开源移动设备综合平台,包括其基于Linux的操作系统、中间件和关键的手机应用。并且组建了开放手机联盟,其成员囊括了全球著名的各大手机生产 商和移动运营商。2008年8月,Google又发布了网上应用商店Android Market。任何一个开发者只需要借助Android发 布的SDK开发手机应用,即可把开发的应用在Android Market上销售。目前Android Market上已经有一万多的应用程序,大大丰富了Android手机用户的功能。一个完整的产业链已经形成。因此开源Android吸引了原来越多的开发人员加入进来。本文将跟读者一起学习Android的线程模型。
2. 用户在输入框内输入需要查询的 城市名称,然后点击查询按钮
3. 当用户点击查询按钮后,使用已 经内置在Android SDK中的HttpClient API来调用GOOGLE 的 天气查询API, 然后解析返回的指定城市的天气信息,并把该天气信息显示在Title上
主要代码如下:
return parseWeather(httpEntity.getContent());
}
} catch (Exception e) {
Log.e("WeatherReport", "Failed to get weather", e);
l 前台进程
前台进程是用户当前正在使用的进程。只有一些前台进程可以在任何时候都存在。他们是最后一个被结束的,当内存低到根本连他们都不能运行的时候。一般来说, 在这种情况下,设备会进行内存调度,中止一些前台进程来保持对用户交互的响应。
l 可见进程
可见进程不包含前台的组件但是会在屏幕上显示一个可见的进程是的重要程度很高,除非前台进程需要获取它的资源,不然不会被中止。
2 Android进程
在了解Android线程之间得先了解一下Android的进程。当一个程序第一次启动的时候,Android会启动一个LINUX进程和一个主线程。默认的情况下,所有该程序的组件都将在该进程和线程中运行。同时,Android会为每个应用程序分配一个单独的LINUX用户。Android会劲量保留一个正在运行进程,只在内存资源出现不足时,Android会参试停止一些进程从而释放足够的资源给其他新的进程使用, 也能保证用户正在访问的当前进程有足够的资源去及时的响应用户的事件。Android会 根据进程中运行的组件类别以及组件的状态来判断该进程的重要性,Android会 首先停止那些不重要的进程。按照重要性从高到低一共有五个级别:
HttpContext localContext = new BasicHttpContext();
HttpGet httpGet = new HttpGet(GOOGLE_API_URL + city);
try {
HttpResponse response = httpClient.execute(httpGet, localContext);
l 服务进程
运行着一个通过startService() 方法启动的service,这个service不属于上面提到的2种更高重要性的。service所在的进程虽然对用户不是直接可见的,但是他们执行了用户非常关注的任务(比如播放mp3,从网络下载数据)。只要前台进程和可见进程有足够的内存,系统不会 回收他们。
本程序将设计和实现查看指定城市的当天天气情况的功能,
1. 首先,需要选择一个天气查询的 服务接口,目前可供选择的接口很多,诸如YAHOO的 天气API和Google提 供的天气API。 本文将选择GOOGLE 的 天气查询API。 该接口提供了多种查询方式,可以通过指定具体城市的经纬度进行查询,也可以通过城市名称进行查询。
相关文档
最新文档