- 浏览: 5132897 次
- 性别:
- 来自: 天津
博客专栏
-
实战 Groovy
浏览量:29021
文章分类
- 全部博客 (639)
- 代码之谜 (6)
- JavaScript quirks (5)
- 程序员 (92)
- Java (93)
- BT编程 (7)
- html/css (64)
- Groovy&Grails (42)
- Android (20)
- C/C++ (5)
- PHP/Perl/Python (46)
- 经典文章 (51)
- CodeIgniter (14)
- JQuery (10)
- 笑话 (4)
- 其他 (32)
- javascript (69)
- 云计算 (0)
- html5 (7)
- 面试 (8)
- google (3)
- nosql (2)
- nodejs (11)
- go (5)
- erlang (1)
- 小常识 (3)
- 冷知识 (5)
- database (4)
- web (12)
- 架构 (12)
- Exception (0)
最新评论
-
jqw1992:
https://www.chromefor.com/libra ...
[福利] 开发者必备的 Chrome 插件——ChromeSnifferPlus -
litjerk:
初步算了一下,目前最最精简的Win98版是5M,他5个小时多敲 ...
让人目瞪口呆的三位世界级电脑大师 -
379855529:
。。似乎重点没说NIO啊,前面基础只是铺垫的很好的,可是我要的 ...
Java NIO与IO的详细区别(通俗篇) -
springmvc_springjpa:
spring mvc demo教程源代码下载,地址:http: ...
一步步开发 Spring MVC 应用 -
匡建武:
Good
四个程序员的一天
在Android下面也有多线程的概念,在C/C++中,子线程可以是一个函数,一般都是一个带有循环的函数,来处理某些数据,优先线程只是一个复杂的运算过程,所以可能不需要while循环,运算完成,函数结束,线程就销毁。对于那些需要控制的线程,一般我们都是和互斥锁相互关联,从而来控制线程的进度,一般我们创建子线程,一种线程是很常见的,那就是带有消息循环的线程。 消息循环是一个很有用的线程方式,曾经自己用C在Linux下面实现一个消息循环的机制,往消息队列里添加数据,然后异步的等待消息的返回。当消息队列为空的时候就会挂起线程,等待新的消息的加入。这是一个很通用的机制。 在Android,这里的线程分为有消息循环的线程和没有消息循环的线程,有消息循环的线程一般都会有一个Looper,这个事android的新概念。我们的主线程(UI线程)就是一个消息循环的线程。针对这种消息循环的机制,我们引入一个新的机制Handle,我们有消息循环,就要往消息循环里面发送相应的消息,自定义消息一般都会有自己对应的处理,消息的发送和清除,消息的的处理,把这些都封装在Handle里面,注意Handle只是针对那些有Looper的线程,不管是UI线程还是子线程,只要你有Looper,我就可以往你的消息队列里面添加东西,并做相应的处理。 但是这里还有一点,就是只要是关于UI相关的东西,就不能放在子线程中,因为子线程是不能操作UI的,只能进行数据、系统等其他非UI的操作。 那么什么情况下面我们的子线程才能看做是一个有Looper的线程呢?我们如何得到它Looper的句柄呢? Looper.myLooper();获得当前的Looper Looper.getMainLooper () 获得UI线程的Lopper 我们看看Handle的初始化函数,如果没有参数,那么他就默认使用的是当前的Looper,如果有Looper参数,就是用对应的线程的Looper。 如果一个线程中调用Looper.prepare(),那么系统就会自动的为该线程建立一个消息队列,然后调用 Looper.loop();之后就进入了消息循环,这个之后就可以发消息、取消息、和处理消息。这个如何发送消息和如何处理消息可以再其他的线程中通过Handle来做,但前提是我们的Hanle知道这个子线程的Looper,但是你如果不是在子线程运行 Looper.myLooper(),一般是得不到子线程的looper的。
所以很多人都是这样做的:我直接在子线程中新建handle,然后在子线程中发送消息,这样的话就失去了我们多线程的意义了。
class myThread extends Thread{ private EHandler mHandler ; public void run() { Looper myLooper, mainLooper; myLooper = Looper.myLooper (); mainLooper = Looper.getMainLooper (); String obj; if (myLooper == null ){ mHandler = new EHandler(mainLooper); obj = "current thread has no looper!" ; } else { mHandler = new EHandler(myLooper); obj = "This is from current thread." ; } mHandler .removeMessages(0); Message m = mHandler .obtainMessage(1, 1, 1, obj); mHandler .sendMessage(m); } }
可以让其他的线程来控制我们的handle,可以把 private EHandler mHandler ;放在外面,这样我们的发消息和处理消息都可以在外面来定义,这样增加程序代码的美观,结构更加清晰。
对如任何的Handle,里面必须要重载一个函数
public void handleMessage(Message msg)
这个函数就是我们的消息处理,如何处理,这里完全取决于你,然后通过 obtainMessage和 sendMessage等来生成和发送消息, removeMessages(0)来清除消息队列。Google真是太智慧了,这种框架的产生,我们写代码更加轻松了。
有的时候,我们的子线程想去改变UI了,这个时候千万不要再子线程中去修改,获得UI线程的Looper,然后发送消息即可。
我们来看看高焕堂的代码:
// class ac01 extends Activity { // ……… public void onClick(View v) { switch (v.getId()){ case 101: t = new myThread(); t .start(); break ; case 102: finish(); break ; } } //------------------------------------------------------ class EHandler extends Handler { public EHandler(Looper looper) { super (looper); } @Override public void handleMessage(Message msg) { tv .setText((String)msg. obj ); } } //------------------------------------------------------ class myThread extends Thread{ private EHandler mHandler ; public void run() { Looper myLooper, mainLooper; myLooper = Looper.myLooper (); mainLooper = Looper.getMainLooper (); String obj; if (myLooper == null ){ mHandler = new EHandler(mainLooper); obj = "current thread has no looper!" ; } else { mHandler = new EHandler(myLooper); obj = "This is from current thread." ; } mHandler .removeMessages(0); Message m = mHandler .obtainMessage(1, 1, 1, obj); mHandler .sendMessage(m); } } }
完全是不知所云,一坨狗屎。我们来看,在上面的run里面
Looper myLooper, mainLooper;
myLooper = Looper.myLooper (); //很明显这个会返回空,因为你还没有 prepare,不会返回Looper。
mainLooper = Looper.getMainLooper ();
建议大家在看Looper的时候不要看高焕堂的书,感觉他也不是很懂,倒还把我搞糊涂了。讲了那么多,完全是他自己的理解,他自己的理解很是复杂,关键的是把简单的问题复杂化,并且复杂之后的东西还是错的。我们看看Goole Music App的源代码。
在MediaPlaybackActivity.java中,我们可以看一下再OnCreate中的有这样的两句:
mAlbumArtWorker = new Worker("album art worker");
mAlbumArtHandler = new AlbumArtHandler(mAlbumArtWorker.getLooper());
很明显这两句,是构建了一个子线程。并且这个子线程还是Looper的子线程,这里很牛逼的使用了 mAlbumArtWorker.getLooper()这个函数,因为我们知道,我们能够得到子线程的Looper的途径只有一个:就是在子线程中调用 Looper.myLooper (),并且这个函数还要在我们perpare之后调用才能得到正确的Looper,但是他这里用了一个这样的什么东东 getLooper,不知道它是如何实现的?
这里有一个大概的思路,我们在子线程的的prepare之后调用 myLooper ()这个方法,然后保存在一个成员变量中,这个getLooper就返回这个东西,但是这里会碰到多线程的一个很突出的问题,同步。我们在父线程中调用 mAlbumArtWorker.getLooper(),但是想要这个返回正确的looper就必须要求我们的子线程运行了prepare,但是这个东西实在子线程运行的,我们如何保证呢?
我们看Google是如何实现的?
private class Worker implements Runnable { private final Object mLock = new Object(); private Looper mLooper; /** * Creates a worker thread with the given name. The thread * then runs a {@link android.os.Looper}. * @param name A name for the new thread */ Worker(String name) { Thread t = new Thread(null, this, name); t.setPriority(Thread.MIN_PRIORITY); t.start(); synchronized (mLock) { while (mLooper == null) { try { mLock.wait(); } catch (InterruptedException ex) { } } } } public Looper getLooper() { return mLooper; } public void run() { synchronized (mLock) { Looper.prepare(); mLooper = Looper.myLooper(); mLock.notifyAll(); } Looper.loop(); } public void quit() { mLooper.quit(); } }
我们知道,一个线程类的构造函数是在主线程中完成的,所以在我们的 Worker的构造函数中我们创佳一个线程,然后让这个线程运行,这一这个线程的创建是指定一个 Runnabl,这里就是我们的Worker本身,在主线程调用 t.start();,这后,我们子线程已经创建,并且开始执行work的run方法。然后下面的代码很艺术:
synchronized (mLock) { while (mLooper == null) { try { mLock.wait(); } catch (InterruptedException ex) { } } }
我们开始等待我们的子线程给mLooper赋值,如果不赋值我们就继续等,然后我们的子线程在运行run方法之后,在给 mLooper赋值之后,通知worker够着函数中的wait,然后我们的构造函数才能完成,所以我们说:
mAlbumArtWorker = new Worker("album art worker");
这句本身就是阻塞的,它创建了一个子线程,开启了子线程,并且等待子线程给mLooper赋值,赋值完成之后,这个函数才返回,这样才能保证我们的子线程的Looper的获取绝对是正确的,这个构思很有创意。值得借鉴。
发表评论
-
移动网页设计相关原则
2012-07-25 08:55 1076如何开始移动设计 对于我们中很多人来说,移动端设计是一个崭新的 ... -
10个常见的 Android 新手误区
2012-07-16 08:06 1696在过去十年的移动开发平台中,作为资深的移动开发人员,我们认为A ... -
Android手机内存的运行机制
2012-05-28 09:31 1565使用android手机的用户可能都安装了任务管理的软件,使用a ... -
android应用程序基本原理
2012-05-28 09:30 1781android应用程序是用Java ... -
最封闭的开源系统:话说 Android 的八宗罪
2010-07-16 17:53 2025你以为 Android 是开放的吗?Google 采用了一系 ... -
编写高效的Android代码
2010-06-26 10:48 1509虽然如此说,但似乎并没有什么好的办法:Android设备是 ... -
android 机器人:应用程序Manifest介绍
2010-06-25 15:43 2243每一个Android应用程 ... -
android 机器人:Styles和Themes(主题和风格)
2010-06-25 11:00 1413Styles和Themes 通过指定Views ... -
android 机器人:Animations
2010-06-25 11:00 2520Animations Android支持2种类 ... -
Android 机器人:使用系统资源
2010-06-25 10:59 1569Android本体应用程序具体化了很多自己的资源,各种 ... -
Android:实时改变配置
2010-06-25 10:59 2586Android通过终止、重 ... -
Android:Layouts介绍
2010-06-24 08:46 3243Layout管理器(一般称“layouts”)是Vie ... -
Android菜单系统介绍
2010-06-24 08:46 2131如果你曾经尝试用手写笔或轨迹球来导航移动电话的菜单系统 ... -
Android使用Intent Filter来响应隐式Intent
2010-06-24 08:45 3950如果一个Intent请求在一片数据上执行一个动作,An ... -
Android如何解析Intent Filter
2010-06-24 08:45 2163匿名性质的运行时绑定使得理解Android如何解析一个 ... -
android.app.Activity 的介绍
2010-06-23 08:53 10998发现当前Android的资料不是很多,而且对于Acti ... -
android sdk+eclipse+adt 配置与开发
2010-06-23 08:52 2843Android ADT插件配置 创建a ... -
Android入门 HelloWord
2010-06-23 08:52 2042先说说整个程序要做哪些内容吧,简单helloword 通 ... -
Android概述
2010-06-23 08:52 21221. Android是什么? ...
相关推荐
android下多线程示例代码 用5种不同线程清楚 理解多线程开发
android多线程机制教程 android多线程机制 android多线程机制 android多线程机制
该demo实现了android平台的多线程下载的功能,代码注释比较详细,可以看看
Android实现网络多线程下载,断点续传,压缩包内有两个项目: downloadDemo:多线程下载 MulThreadDownloader:断点续传(网上别人的项目)
Android 进行文件分段多线程下载的实例,用户可以指定线程数,还可以通过进度条查看下载的进度。
Android studio 多线程下载,Android studio 多线程下载
Android中多线程下载原理实现案例...
android多线程后台下载示例程序,android多线程后台下载示例程序,android多线程后台下载示例程序,android多线程后台下载示例程序,android多线程后台下载示例程序,android多线程后台下载示例程序
android——Handler与多线程应用范例
Android 多线程开发实例,对使用多线程的用户有一定的参考价值!
一个书上的例子,android多线程下载,支持下载暂停,断点续传
因Android Studio下整体项目太大,此文件仅包含核心代码,核心都在MainActivity中,包括: 1. 主线程直接加载,不可用; 2. 采用handler+Thread模式实现多线程异步加载; 3. 引入线程池来管理多线程 4. 引入线程池,...
Android多线程下载,支持断点续传,修改线程数。。。。。
android 实现多线程下载源代码 代码详细 很好学习资料
android多线程管理,实现多线程
android多线程
Android开发中的多线程编程技术资源包 TAG:Android 多线程 应用开发 Alfred整理发布,版权所有!
Android网络多线程断点续传下载 示例
Android多线程下载Demo
android多线程断点下载,完美封装,包括暂停功能。写好接口,android小白即能轻松上手。