android之TheadLocal,还有Handler

android中把java中TheadLocal类中内部类ThreadLocalMap换成了Values,并且方法也换了;

android中线程存储的就是ThreadLocal.Values了;

线程中用Handler的方式:

new Thread(){

   public void run(){

Looper.prepare();

Handler handler = new Handler();

Looper.loop();

}

};

Looper.loop();会阻塞线程,一直等待消息唤醒线程,继续执行;

来看看Handler:

  public Handler() {
        this(null, false);
    }
 public Handler(Callback callback) {
        this(callback, false);
    }
 public Handler(Looper looper) {
        this(looper, null, false);
    }
 public Handler(Looper looper, Callback callback) {
        this(looper, callback, false);
    }
 public Handler(boolean async) {
        this(null, async);
    }
  public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
以上就是Handler的构造函数;

无参数的构造函数实际上调用的是最后一个构造函数,那么看看最后一个构造函数:

1.检查当前Handler是否是静态的,否则有内存泄露风险;

2.获得当前线程的Loop对象;

3.获得消息队列对象;

4.Callback对象;

第二步如果没有获得Looper对象就会抛出

Can't create handler inside thread that has not called Looper.prepare()
因此内部线程需要Looper.prepare(),Looper.loop();

主线程即(ActivityThread)已经做好了Looper.prepare(),Looper.loop();因此主线程不需要,可以直接new Hander();

其他线程在创建Handler对象之前需要run方法中Looper.prepare();最后Looper.loop();


看看Looper类的prepare()方法:

    public static void prepare() {
        prepare(true);
    }

    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

从第二个函数可以知道 prepare()只能调用一次,每一个线程的Looper对象只能有一个;

以上代码也说明了prepare()方法是把looper对象绑定到当前线程上(通过ThreadLocal实现Looper对象绑定到线程);

看看Looper类的loop()方法:

prepare是绑定,那么loop()就是从消息队列中获取消息执行了;

分析源码:

    public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // This must be in a local variable, in case a UI event sets the logger
            Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            msg.target.dispatchMessage(msg);

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }

            msg.recycleUnchecked();
        }
    }
在无限循环中:
 Message msg = queue.next(); 
queue.next()是个阻塞方法,没有从消息队列中拿到消息线程就block状态;
获得消息后执行
 msg.target.dispatchMessage(msg);
msg.target也就是Message绑定的Handler对象;执行Handler中的dispatchMessage方法;

以上就是整个handler+looper+messagequeue+thread的流程;

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

看看Handler的dispatchMessage源码:

   public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

优先执行msg中的callback,handler.post(new Runnable(){});  callback就是new Runnable(){}对象;

再次执行mCallback中的handleMessage, mCallback是构造函数中传递的对象;

优先级最低的是handler自身的handleMessage对象;

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

回到Handler对象,handler对象实际上是与Looper对象绑定,绑定到哪个线程的looper对象上就能让哪个线程执行handler的处理代码逻辑;

因此不必在当前线程下创建Handler对象; HandlerThread体现了这种用法;

  

  <pre name="code" class="java"> MyHandlerThread handlerThread = new MyHandlerThread("myHanler");  
   handlerThread.start();  
   handler = new Handler(handlerThread.getLooper(), handlerThread); 

      
   private class MyHandlerThread extends HandlerThread implements Callback {  
  
        public MyHandlerThread(String name) {  
            super(name);  
        }  
  
        @Override  
        public boolean handleMessage(Message msg) {  
            //打印线程的名称  
            System.out.println(" handleMessage CurrentThread = " + Thread.currentThread().getName());  
            return true;  
        }              
    }
或者:

   MyHandlerThread handlerThread = new MyHandlerThread("myHanler");  
   handlerThread.start();  
   handler = new Handler(handlerThread.getLooper()); 
   handler.post(new Runnable() {  
                            @Override  
                            public void run() {  
                            
                            }  
                        });  














  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ThreadLocal是Java中的一个类,用于实现线程局部变量。它可以在每个线程中创建一个变量的副本,每个线程对该副本进行操作,互不影响。 当线程第一次调用ThreadLocal的set或者get方法时,会创建一个threadLocals变量,用于存储该线程的本地变量。具体而言,ThreadLocal实例本身相当于一个装载本地变量的工具壳,通过set方法将值添加到调用线程的threadLocals中,当调用线程调用get方法时,能够从自己的threadLocals中取出该变量。 在get方法的实现中,首先获取当前调用线程,如果当前线程的threadLocals不为null,就直接返回当前线程的threadLocals变量中的本地变量值,否则执行setInitialValue方法来初始化threadLocals变量。 需要注意的是,如果调用线程一直不终止,那么该本地变量将一直存放在threadLocals中,可能会导致内存溢出。因此,在使用完ThreadLocal后,需要调用remove方法将该线程的threadLocals中的本地变量删除。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [ThreadLocal详解](https://blog.csdn.net/m0_49508485/article/details/123234587)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值