Handler机制.源码分析

Handler机制的原理 :

Android提供了handler looper 来满足线程之间的通信

Handler是先进先出的原则

一个线程可以产生一个looper对象,由它去管理线程里面消息队列 MessageQueue

Handler 你可以构造handler对象来与looper沟通.可以发送消息 和处理消息

 

MessageQueue 用来存放线程放入的消息

 

线程 一般值的是主线程 UIthread

Android启动程序的时候会替他建立一个MessageQueue

 
.Handler创建消息

消息池

 消息池

 

 

 

Handler发送消息

ThreadLocal

Handler 处理消息

 

andriod提供了Handler Looper 来满足线程间的通信。Handler先进先出原则。Looper类用来管理特定线程内对象之间的消息交换(MessageExchange)

1)Looper:
一个线程可以产生一个Looper对象,由它来管理此线程里的MessageQueue(消息队列)
2)Handler:
你可以构造Handler对象来与Looper沟通,以便push新消息到MessageQueue;或者接收LooperMessage Queue取出)所送来的消息。
3) Message Queue(
消息队列):用来存放线程放入的消息。

4)线程:UIthread 通常就是main thread,而Android启动程序时会替它建立一个MessageQueue

1.Handler创建消息

        每一个消息都需要被指定的Handler处理,通过Handler创建消息便可以完成此功能。Android消息机制中引入了消息池。Handler创建 消息时首先查询消息池中是否有消息存在,如果有直接从消息池中取得,如果没有则重新初始化一个消息实例。使用消息池的好处是:消息不被使用时,并不作为垃 圾回收,而是放入消息池,可供下次Handler创建消息时使用。消息池提高了消息对象的复用,减少系统垃圾回收的次数。消息的创建流程如图所示。

2.Handler发送消息

UI主线程初始化第一个Handler时会通过ThreadLocal创建一个Looper,该LooperUI主线程一一对应。使用 ThreadLocal的目的是保证每一个线程只创建唯一一个Looper。之后其他Handler初始化的时候直接获取第一个Handler创建的 LooperLooper初始化的时候会创建一个消息队列MessageQueue。至此,主线程、消息循环、消息队列之间的关系是1:1:1

HandlerLooperMessageQueue的初始化流程如图所示:

Hander持有对UI主线程消息队列MessageQueue和消息循环Looper的引用,子线程可以通过Handler将消息发送到UI线程的消息队列MessageQueue中。

3.Handler处理消息

UI主线程通过Looper循环查询消息队列UI_MQ,当发现有消息存在时会将消息从消息队列中取出。首先分析消息,通过消息的参数判断该消息对应的Handler,然后将消息分发到指定的Handler进行处理。

子线程通过HandlerLooperUI主线程通信的流程如图所示。

 

 

相关的术语 :

通信的同步 Synchronous指向客户端发送请求后,必须要在服务端有回应后客户端才继续发送其它的请求,所以这时所有请求将会在服务端得到同步,直到服务端返回请求。

通信的异步 Asynchronous  指客户端在发送请求后,不必等待服务端的回应就可以发送下一个请求。

 

 

所谓同步调用,就是在一个函数或方法调用时,没有得到结果之前,该调用就不返回,直到返回 结果。异步调用和同步是相对的,在一个异步调用发起后,被调用者立即返回给调用者,但是调用者不能立刻得到结果,被调用都在实际处理这个调用的请求完成 后,通过状态、通知或回调等方式来通知调用者请求处理的结果。

 

 

 

Android的消息处理有三个核心的类

Looper handler message 其实还有一个MessageQueue 但是它被封装在looper,不会直接和它打交道,所以不算是核心的类.


消息类Message  主要的功能是进行消息的封装,同时可以指定消息的操作形式

Int whatobject obj      Handler getTraget

尽管message有默认的构造,但是我们应该是通过Message.ontain() 来从消息池中获取消息对象,节省资源

如果是只是简单地携带int信息,优先使用Message.arg1Message.arg2来传递信息,这比Bundle更省内存

 

善用message.what 来标示信息,以便不同的方式来处理message

 

消息通道 looper 系统会自动创建looper对象,但是如果是用户自定义的一个类中,就需要手动的调用looper中的方法.才可以启动looper对象

表面的意思是循环者,它被设计一个普通的线程变成looper线程,所说的looper线程就是循环工作的线程 .looper.prepare()  ;    处理其他,比如实例化handler ……  looper.loop()

 

一个线程只可以有一个looper对象,为什么???

 

 public class Looper {
    
    
    // 每个线程中的Looper对象其实是一个ThreadLocal,即线程本地存储(TLS)对象
    
    
    private static final ThreadLocal sThreadLocal = new ThreadLocal();
    
    
    // Looper内的消息队列
    
    
    final MessageQueue mQueue;
    
    
    // 当前线程
    
    
    Thread mThread;
    
    
    //其他属性
    
    
    // 每个Looper对象中有它的消息队列,和它所属的线程
    
    
    private Looper() {
    
    
        mQueue = new MessageQueue();
    
    
        mRun = true;
    
    
        mThread = Thread.currentThread();
    
    
    }
    
    
    // 我们调用该方法会在调用线程的TLS中创建Looper对象
    
    
    public static final void prepare() {
    
    
        if (sThreadLocal.get() != null) {
    
    
            // 试图在有Looper的线程中再次创建Looper将抛出异常
    
    
            throw new RuntimeException("Only one Looper may be created per thread");
    
    
        }
    
    
        sThreadLocal.set(new Looper());
    
    
    }
    
    
    // 其他方法
    
    
}
   
   

 

 看源码 ,可以看出创建looper对象其实就是将looper对象定义为ThreadLocal,如果这个对象以前定义了,妮又尝试着去重新的定义,就是说threaLocal.get()!=null 这个时候对象存在,就会爆异常 .

 

 

 

looper.loop() 这个代表着启动looper 线程开始工作了.它不断的从队列里面取出消息.每次去的是第一个消息.源码分析 :

调用这个方法后,内部的执行流程


   
   
    
     
   
   
1.获取当前线程的looper对象 Looper me = myLooper();这个方法内部其实就是返回 ThreadLocal.get()
   
   

 

2. 获取消息队列 MessageQueue queue = me.mQueue;
   
   

 

3. 开启一个while死循环

用队列的对象取出下一个消息Message msg = queue.next();
   
   

判断消息是否为空,如果是空,就不会继续执行了

如果不是空,将消息交给handler msg.target.dispatchMessage(msg);
   
   
msg.recycle();回收msg资源
   
   

 

 

looper中的其他的方法 myLooper()   getThread()

       quit()  结束looper的循环 
   
   
public void quit() {
    
    
        // 创建一个空的message,它的targetNULL,表示结束循环消息
    
    
        Message msg = Message.obtain();
    
    
        // 发出消息
    
    
        mQueue.enqueueMessage(msg, 0);
    
    
    }
   
   

 

综上,Looper有以下几个要点:

1)每个线程有且只能有一个Looper对象,它是一个ThreadLocal

2Looper内部有一个消息队列,loop()方法调用后线程开始不断从队列中取出消息执行

3Looper使一个线程变成Looper线程。

那么,我们如何操作Message Queue上的消息呢?这就是Handler的用处了

 

 

 

 

消息操作类  handler

处理消息,但是很小气,只处理自己发出的消息

 

默认关联当前线程的looper   
mLooper = Looper.myLooper();
判断looper是不是空的,如果是空的就爆异常,就是指handler只可以在looper线程中使用,
   
   
关联looper的消息队列,因为他的消息要发送到looper的消息队列中
   
   
public class LooperThread extends Thread {
   
   
    private Handler handler1;
   
   
    private Handler handler2;
   
   

   
   
    
     
   
   
    @Override
   
   
    public void run() {
   
   
        // 将当前线程初始化为Looper线程
   
   
        Looper.prepare();
   
   
        
   
   
        // 实例化两个handler
   
   
        handler1 = new Handler();
   
   
        handler2 = new Handler();
   
   
        
   
   
        // 开始循环处理消息队列
   
   
        Looper.loop();
   
   
    }
   
   
}
   
   
一个线程可以有多个handler 但是只能有一个looper
   
   
有了handler之后 就可以发送消息; 
    
    
post(Runnable)
   
   
 postAtTime(Runnable, long)
   
   
 postDelayed(Runnable, long)
   
   
 sendEmptyMessage(int)
   
   
sendMessage(Message)
   
   
sendMessageAtTime(Message, long)
   
   
sendMessageDelayed(Message, long)
   
   

   
   
    
     
   
   
post发送消息最后都是把里面的Runnable封装成了message 
   
   
// 此方法用于向关联的MQ上发送Runnable对象,它的run方法将在handler关联的looper线程中执行
   
   
    public final boolean post(Runnable r)
   
   
    {
   
   
       // 注意getPostMessage(r)runnable封装成message
   
   
       return  sendMessageDelayed(getPostMessage(r), 0);
   
   
    }
   
   

   
   
    
     
   
   
    private final Message getPostMessage(Runnable r) {
   
   
        Message m = Message.obtain();  //得到空的message
   
   
        m.callback = r;  //runnable设为messagecallback
   
   
        return m;
   
   
    }
   
   

   
   
    
     
   
   
    public boolean sendMessageAtTime(Message msg, long uptimeMillis)
   
   
    {
   
   
        boolean sent = false;
   
   
        MessageQueue queue = mQueue;
   
   
        if (queue != null) {
   
   
            msg.target = this;  // messagetarget必须设为该handler
   
   
            sent = queue.enqueueMessage(msg, uptimeMillis);
   
   
        }
   
   
        else {
   
   
            RuntimeException e = new RuntimeException(
   
   
                this + " sendMessageAtTime() called with no mQueue");
   
   
            Log.w("Looper", e.getMessage(), e);
   
   
        }
   
   
        return sent;
   
   
    }
   
   

   
   
    
     
   
   
发送消息的时候 ,设置target为当前发送消息的handler,
   
   
这样就可以方便的找到处理消息的handler对象

发送消息之后,是怎么处理消息的 
    
    
dispathMessage(Message msg)  钩子方法 handleMessage(Message msg)
   
   
dispatchMessage(Message msg) {
   
   
         (msg.callback != ) {
   
   
                        handleCallback(msg);
   
   
        }  {
   
   
                         (mCallback != ) {
   
   
                 
   
   
                 (mCallback.handleMessage(msg)) {
   
   
                    ;
   
   
                }
   
   
            }
   
   
                        handleMessage(msg);
   
   
        }
   
   
    }
   
   
    
   
   
           handleCallback(Message message) {
   
   
        message.callback.run();      }
   
   
          handleMessage(Message msg) {
   
   
    }
   
   

   
   
    
     
   
   





使用优化算法,以优化VMD算法的惩罚因子惩罚因子 (α) 和分解层数 (K)。 1、将量子粒子群优化(QPSO)算法与变分模态分解(VMD)算法结合 VMD算法背景: VMD算法是一种自适应信号分解算法,主要用于分解信号为不同频率带宽的模态。 VMD的关键参数包括: 惩罚因子 α:控制带宽的限制。 分解层数 K:决定分解出的模态数。 QPSO算法背景: 量子粒子群优化(QPSO)是一种基于粒子群优化(PSO)的一种改进算法,通过量子行为模型增强全局搜索能力。 QPSO通过粒子的量子行为使其在搜索空间中不受位置限制,从而提高算法的收敛速度与全局优化能力。 任务: 使用QPSO优化VMD中的惩罚因子 α 和分解层数 K,以获得信号分解的最佳效果。 计划: 定义适应度函数:适应度函数根据VMD分解的效果来定义,通常使用重构信号的误差(例如均方误差、交叉熵等)来衡量分解的质量。 初始化QPSO粒子:定义粒子的位置和速度,表示 α 和 K 两个参数。初始化时需要在一个合理的范围内为每个粒子分配初始位置。 执行VMD分解:对每一组 α 和 K 参数,运行VMD算法分解信号。 更新QPSO粒子:使用QPSO算法更新粒子的状态,根据适应度函数调整粒子的搜索方向和位置。 迭代求解:重复QPSO的粒子更新步骤,直到满足终止条件(如适应度函数达到设定阈值,或最大迭代次数)。 输出优化结果:最终,QPSO算法会返回一个优化的 α 和 K,从而使VMD分解效果最佳。 2、将极光粒子(PLO)算法与变分模态分解(VMD)算法结合 PLO的优点与适用性 强大的全局搜索能力:PLO通过模拟极光粒子的运动,能够更高效地探索复杂的多峰优化问题,避免陷入局部最优。 鲁棒性强:PLO在面对高维、多模态问题时有较好的适应性,因此适合海上风电时间序列这种非线性、多噪声的数据。 应用场景:PLO适合用于优化VMD参数(α 和 K),并将其用于风电时间序列的预测任务。 进一步优化的建议 a. 实现更细致的PLO更新策略,优化极光粒子的运动模型。 b. 将PLO优化后的VMD应用于真实的海上风电数据,结合LSTM或XGBoost等模型进行风电功率预测。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值