Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one,

call prepare() in the thread that is to run the loop, and then loop() to have it process messages until the loop is stopped.

  1. class LooperThread extends Thread {
  2. public Handler mHandler;
  3. public void run() {
  4. Looper.prepare();
  5. mHandler = new Handler() {
  6. public void handleMessage(Message msg) {
  7. // process incoming messages here
  8. }
  9. };
  10. Looper.loop();
  11. }
  12. }

(1)提出问题:正如上面所说, 一个线程默认是没有Looper用来处理message队列的。但为什么我们在主线程时又没有自己创建Looper呢?

  1. public class Looper {
  2. private static final String TAG = "Looper";
  3.  
  4. // sThreadLocal.get() will return null unless you've called prepare().
  5. static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); //(1)又见到了眼熟的ThreadLocal,里面存放的是每个线程的Looper
  6. private static Looper sMainLooper; // guarded by Looper.class
  7.  
  8. final MessageQueue mQueue;
  9. final Thread mThread;
  10. volatile boolean mRun;
  11.  
  12. private Printer mLogging;
  13.  
  14. /** Initialize the current thread as a looper.
  15. * This gives you a chance to create handlers that then reference
  16. * this looper, before actually starting the loop. Be sure to call
  17. * {@link #loop()} after calling this method, and end it by calling
  18. * {@link #quit()}.
  19. */
  20. public static void prepare() {
  21. prepare(true);
  22. }
  23.  
  24. private static void prepare(boolean quitAllowed) {
  25. if (sThreadLocal.get() != null) {
  26. throw new RuntimeException("Only one Looper may be created per thread");
  27. }
  28. sThreadLocal.set(new Looper(quitAllowed));
  29. }
  30.  
  31. /**
  32. * Initialize the current thread as a looper, marking it as an
  33. * application's main looper. The main looper for your application
  34. * is created by the Android environment, so you should never need
  35. * to call this function yourself. See also: {@link #prepare()}
  36. */
  37. public static void prepareMainLooper() {
  38. prepare(false);
  39. synchronized (Looper.class) {
  40. if (sMainLooper != null) {
  41. throw new IllegalStateException("The main Looper has already been prepared.");
  42. }
  43. sMainLooper = myLooper(); //(2)为主线程的Looper赋值
  44. }
  45. }
  46.  
  47. /** Returns the application's main looper, which lives in the main thread of the application.
  48. */
  49. public static Looper getMainLooper() {
  50. synchronized (Looper.class) {
  51. return sMainLooper;
  52. }
  53. }
  54.  
  55. /**
  56. * Return the Looper object associated with the current thread. Returns
  57. * null if the calling thread is not associated with a Looper.
  58. */
  59. public static Looper myLooper() { //(3)为主线程Looper赋值的其实就是调用ThreadLocal的get()
  60. return sThreadLocal.get();
  61. }
  62.  
  63. }

2.如果不知道ThreadLocal是什么意思,自己去查API,我没这么大气和你讲。

3.所以我们可以这样用:

  1. public class MainActivity extends Activity {
  2.  
  3. private ProgressDialog mpDialog;
  4. private int mCount = 0;
  5.  
  6. private Handler handler = new Handler(){
  7.  
  8. @Override
  9. public void handleMessage(Message msg) {
  10. //update UI
  11. System.out.println("----------update ui ok--------------"+Thread.currentThread().getId()); // Thread id 为1 说明在主线程中执行。
  12. System.out.println("message arg1 : "+ msg.arg1); //因为这是主线程,所以可以在这时更新UI
  13. super.handleMessage(msg);
  14. }
  15. };
  16.  
  17. private Thread downThread = new Thread(){
  18.  
  19. @Override
  20. public void run() {
  21.  
  22. try{
  23. while(mCount<=100){
  24. mpDialog.setProgress(mCount++);
  25. Thread.sleep(100); //模拟下载过程
  26. }
  27. // This is essentially the same as calling dismiss(),
  28. //but it will also call your DialogInterface.OnCancelListener (if registered).
  29. mpDialog.cancel();
  30. System.out.println("------------download ok----------");
  31. Message message = handler.obtainMessage();
  32. message.arg1 = 10;
  33. handler.sendMessage(message);
  34. }catch(Exception ex){
  35. mpDialog.cancel();
  36. }
  37. }
  38.  
  39. };
  40.  
  41. @Override
  42. protected void onCreate(Bundle savedInstanceState) {
  43. super.onCreate(savedInstanceState);
  44. setContentView(R.layout.activity_main);
  45. Button button= (Button) this.findViewById(R.id.button);
  46. imageView = (ImageView) this.findViewById(R.id.imageView01);
  47. button.setOnClickListener(new OnClickListener(){
  48.  
  49. @Override
  50. public void onClick(View view) {
  51. System.out.println("--------------download start----------------"+Thread.currentThread().getId()); //主线程的id为1
  52. mCount = 0;
  53. mpDialog = new ProgressDialog(MainActivity.this);
  54. mpDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
  55. mpDialog.setTitle("dialogʾ");
  56. mpDialog.setIcon(R.drawable.ic_launcher);
  57. mpDialog.setMessage("好消息");
  58. mpDialog.setMax(100);
  59. mpDialog.setProgress(0);
  60. mpDialog.setSecondaryProgress(50);
  61. mpDialog.setIndeterminate(false);
  62. mpDialog.setCancelable(true);
  63. mpDialog.setButton("取消", new DialogInterface.OnClickListener(){
  64.  
  65. @Override
  66. public void onClick(DialogInterface dialog, int which) {
  67. dialog.cancel();
  68.  
  69. }
  70.  
  71. });
  72. downThread.start();
  73. mpDialog.show();
  74. }
  75.  
  76. });
  77. }
  78.  
  79. }

4.正如上面所说,一个新线程在默认情况下是没有Looper相关联的。所以需要自己创建。但android提供了一个HandlerThread,方便我们使用Looper。

  1. public class HandlerThread extends Thread {
  2.  
  3. Looper mLooper;
  4.  
  5. /**
  6. * Call back method that can be explicitly overridden if needed to execute some
  7. * setup before Looper loops.
  8. */
  9. protected void onLooperPrepared() {
  10. }
  11.  
  12. public void run() {
  13. mTid = Process.myTid();
  14. Looper.prepare();
  15. synchronized (this) {
  16. mLooper = Looper.myLooper();
  17. notifyAll();
  18. }
  19. Process.setThreadPriority(mPriority);
  20. onLooperPrepared();
  21. Looper.loop();
  22. mTid = -1;
  23. }
  24.  
  25. /**
  26. * This method returns the Looper associated with this thread. If this thread not been started
  27. * or for any reason is isAlive() returns false, this method will return null. If this thread
  28. * has been started, this method will block until the looper has been initialized.
  29. * @return The looper.
  30. */
  31. public Looper getLooper() {
  32. if (!isAlive()) {
  33. return null;
  34. }
  35.  
  36. // If the thread has been started, wait until the looper has been created.
  37. synchronized (this) {
  38. while (isAlive() && mLooper == null) {
  39. try {
  40. wait();
  41. } catch (InterruptedException e) {
  42. }
  43. }
  44. }
  45. return mLooper;
  46. }
  47.  
  48. }

Looper分析。ThreadLocal有关的更多相关文章

  1. 分析 ThreadLocal 内存泄漏问题

    ThreadLocal 的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度.但是如果滥用 ThreadLocal,就可能会导 ...

  2. 分析ThreadLocal的弱引用与内存泄漏问题

    目录 一.介绍 二.问题提出 2.1内存原理图 2.2几个问题 三.回答问题 3.1为什么会出现内存泄漏 3.2若Entry使用弱引用 3.3弱引用配合自动回收 四.总结 一.介绍 之前使用Threa ...

  3. Netty源码分析-- ThreadLocal分析(九)

    为了更好地探讨Netty的内存模型,后面会用到,这里我还是决定跟大家一起看下ThreadLocal和FastThreadLocal的源码,有的时候我们在看源码的时候会一层层的遇到很多之前没有看过的内容 ...

  4. ThreadLocal 工作原理、部分源码分析

    1.大概去哪里看 ThreadLocal 其根本实现方法,是在Thread里面,有一个ThreadLocal.ThreadLocalMap属性 ThreadLocal.ThreadLocalMap t ...

  5. Java 中 ThreadLocal 内存泄露的实例分析

    前言 之前写了一篇深入分析 ThreadLocal 内存泄漏问题是从理论上分析ThreadLocal的内存泄漏问题,这一篇文章我们来分析一下实际的内存泄漏案例.分析问题的过程比结果更重要,理论结合实际 ...

  6. ThreadLocal的原理,源码深度分析及使用

    文章简介 ThreadLocal应该都比较熟悉,这篇文章会基于ThreadLocal的应用以及实现原理做一个全面的分析 内容导航 什么是ThreadLocal ThreadLocal的使用 分析Thr ...

  7. ThreadLocal的使用及原理分析

    文章简介 ThreadLocal应该都比较熟悉,这篇文章会基于ThreadLocal的应用以及实现原理做一个全面的分析 内容导航 什么是ThreadLocal ThreadLocal的使用 分析Thr ...

  8. ThreadLocal和ThreadLocalMap源码分析

    目录 ThreadLocal和ThreadLocalMap源码分析 背景分析 定义 例子 源码分析 ThreadLocalMap源码分析 ThreadLocal源码分析 执行流程总结 源码分析总结 T ...

  9. 多线程之美2一ThreadLocal源代码分析

    目录结构 1.应用场景及作用 2.结构关系 2.1.三者关系类图 2.2.ThreadLocalMap结构图 2.3. 内存引用关系 2.4.存在内存泄漏原因 3.源码分析 3.1.重要代码片段 3. ...

随机推荐

  1. samba 服务器

    1.apt-get install smaba 2.安装完成后apt-get install smbclient 然后就是配置那个.conf文件,这个到网上搜下ubuntu下配置smaba服务器就可以 ...

  2. 51开发环境的搭建--KeilC51的安装及工程的创建

    学习单片机的开发,单靠书本的知识是远远不够的,必须实际操作编程才能领会书中的知识点,起到融会贯通的效果.51单片机作为入门级的单片机--上手容易.网上资源丰富.单片机稳定性及资源比较丰富.通过串口即可 ...

  3. socket.io websocket

    不能不知道的事: 在Http协议中,客户端向服务器端发送请求,服务器端收到请求再进行回应,整个过程中,服务器端是被动方,客户端是主动方: websoket是H5的一种基于TCP的新通信协议,它与Htt ...

  4. mysql分组查询获取组内某字段最大的记录

    id sid cid 1 1 12 1 23 2 1 以sid分组,最后取cid最大的那一条,以上要取第2.3条 1 方法一: select * from (select * from table o ...

  5. JS中方法判断存在

    function test(){ alert("test"); } if(typeof test!='undefined') {alert(1) test(); } else {a ...

  6. Linux设备驱动剖析之SPI(三)

    572至574行,分配内存,注意对象的类型是struct spidev_data,看下它在drivers/spi/spidev.c中的定义: struct spidev_data { dev_t de ...

  7. python编程中的if __name__ == 'main': 的作用和原理

    在大多数编排得好一点的脚本或者程序里面都有这段if __name__ == 'main': ,虽然一直知道他的作用,但是一直比较模糊,收集资料详细理解之后与打架分享. 1.这段代码的功能 一个pyth ...

  8. LeetCode 26 Remove Duplicates from Sorted Array (移除有序数组中重复数字)

    题目链接: https://leetcode.com/problems/remove-duplicates-from-sorted-array/?tab=Description   从有序数组中移除重 ...

  9. 部署OpenStack问题汇总(一)--使用packstack安装openstack:源问题的处理

    在安装的过程中,遇到了源的问题,找不到包的网页:    重新打开 预装源地址,打开epel-openstack-havana.repo 文件,显示如下: # Place this file in yo ...

  10. shell 进制转换

    包括: i.任意进制转化为十进制((num=base#number)) [base和number必须一致,是同一种进制] ii.十进制转化为任意进制`echo "obase=进制;值&quo ...