Android handler机制浅析

Android中的多线程编程与异步处理 在移动应用开发中,用户体验是至关重要的。一个流畅、高效的应用能够吸引用户并提升用户满意度。然而,移动应用面临着处理复杂业务逻辑、响应用户输入、处理网络请求等多个任务的挑战。为了确保应用的性能和用户体验,多线程编程和异步处理成为了不可或缺的技术手段。在移动应用中,涉及到耗时操作的任务包括但不限于:网络请求、数据库操作、图片加载、文件读写等。如果这些耗时操作都在应用的主线程(也称为UI线程)中执行,将导致应用界面的卡顿、卡死,甚至导致应用无响应(ANR)的错误。 阅读详情

1、 概述

android系统提供的线程间通信方式,就是使用Handler,在同一个应用内部不同线程之间通信。下面介绍几个主要的概念,Handler 、 Looper 、MessageQueue、Message。
Handler:桥梁,在两个线程之间传递消息
Message:传递的消息体,内部有一个变量target存储发送消息的handler,等到消息处理的时候找到target存储的变量handler,发到内部重写的handlerMessage方法处理
MessageQueue:消息队列,用来存储handler发送的消息,
Looper:循环体,内部维护一个容器MessageQueue,需要遍历MessageQueue取出消息,进行处理。内部存在一个无限循环体,遍历取出消息。
Looper.prepare():创建Looper对象,并存储在ThreadLocal中,后续取得时候也是从ThreadLocal中获取
Looper.loop():开启循环,循环从MessageQueue中取出消息

2、结构图

在这里插入图片描述

2.1 消息过程

从上面结构体中可以看出,存在两个线程,主线程和子线程,主线程内部存在一个Looper,内部维护消息队列MessageQueue,主线程内部可以定义几个handler全局变量,子线程持有handler,通过handler.sendMessage()发送消息到主线程的MessageQueue中,主线程的Looper无限循环,从消息队列中取消息,消息队列也有个无限循环取消息,如果有符合条件的消息,就返回给Looper进行处理;取到Message之后,通过Message.target找到对应的handler,通过内部重写的handleMessage方法处理消息。

2.2、handler发送消息机制

消息发送到队列中是按时间顺序排列,如果sendMessageDelayed()中when时间就是延迟后的时间,是会放在后面的。

2.3、handler取消息机制

消息也分为三类:
同步:发送的消息是同步的,会被障栅拦截
异步:发送异步消息,不会被障栅拦截
障栅(barrier):message中target为空的消息,为了拦截同步消息

MessageQueue内部取消息也有个无限循环
在这里插入图片描述
每次都是从头开始取消息,如果是障栅就要继续遍历查找异步消息进行处理,如果不是在障栅就取第一个满足条件的消息进行处理。
取消息时候都是会判断message.when时间是否在当前时间之前,如果在就会进行处理,如果不是,就表示是需要延时处理的,这条消息就不会处理,继续等待。
障栅只有满足条件才能删除,比如延迟处理消息的时候。

3、源码解析

3.1 Looper

对于Looper主要是prepare()和loop()两个方法。
首先看prepare()方法

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

sThreadLocal是一个ThreadLocal对象,可以在一个线程中存储变量,全局只有一个对象,因此才能每个线程维护一个Looper。可以看到,在第5行,将一个Looper的实例放入了ThreadLocal,并且2-4行判断了sThreadLocal是否为null,否则抛出异常。这也就说明了Looper.prepare()方法不能被调用两次,同时也保证了一个线程中只有一个Looper实例~相信有些哥们一定遇到这个错误。
下面看Looper的构造方法:

private Looper(boolean quitAllowed) {  
        mQueue = new MessageQueue(quitAllowed);  
        mRun = true;  
        mThread = Thread.currentThread();  
} 

在构造方法中,创建了一个MessageQueue(消息队列)。
然后我们看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.recycle();  
        }  
}  

第2行:

public static Looper myLooper() {
return sThreadLocal.get();
}

方法直接返回了sThreadLocal存储的Looper实例,如果me为null则抛出异常,也就是说looper方法必须在prepare方法之后运行。
第6行:拿到该looper实例中的mQueue(消息队列)
13到45行:就进入了我们所说的无限循环。
14行:取出一条消息,如果没有消息则阻塞。
27行:使用调用 msg.target.dispatchMessage(msg);把消息交给msg的target的dispatchMessage方法去处理。Msg的target是什么呢?其实就是handler对象,下面会进行分析。
44行:释放消息占据的资源。

Looper主要作用:
1、 与当前线程绑定,保证一个线程只会有一个Looper实例,同时一个Looper实例也只有一个MessageQueue。
2、 loop()方法,不断从MessageQueue中去取消息,交给消息的target属性的dispatchMessage去处理。
好了,我们的异步消息处理线程已经有了消息队列(MessageQueue),也有了在无限循环体中取出消息的哥们,现在缺的就是发送消息的对象了,于是乎:Handler登场了。

3.2、Handler

使用Handler之前,我们都是初始化一个实例,比如用于更新UI线程,我们会在声明的时候直接初始化,或者在onCreate中初始化Handler实例。所以我们首先看Handler的构造方法,看其如何与MessageQueue联系上的,它在子线程中发送的消息(一般发送消息都在非UI线程)怎么发送到MessageQueue中的。

public Handler() {  
        this(null, false);  
}  
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;  
    }  

14行:通过Looper.myLooper()获取了当前线程保存的Looper实例,然后在19行又获取了这个Looper实例中保存的MessageQueue(消息队列),这样就保证了handler的实例与我们Looper实例中MessageQueue关联上了。
然后看我们最常用的sendMessage方法
[java] view plain copy

public final boolean sendMessage(Message msg)  
 {  
     return sendMessageDelayed(msg, 0);  
 }  

[java] view plain copy

public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {  
     Message msg = Message.obtain();  
     msg.what = what;  
     return sendMessageDelayed(msg, delayMillis);  
 }  

[java] view plain copy

public final boolean sendMessageDelayed(Message msg, long delayMillis)  
   {  
       if (delayMillis < 0) {  
           delayMillis = 0;  
       }  
       return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);  
   }  

[java] view plain copy

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {  
       MessageQueue queue = mQueue;  
       if (queue == null) {  
           RuntimeException e = new RuntimeException(  
                   this + " sendMessageAtTime() called with no mQueue");  
           Log.w("Looper", e.getMessage(), e);  
           return false;  
       }  
       return enqueueMessage(queue, msg, uptimeMillis);      }

辗转反则最后调用了sendMessageAtTime,在此方法内部有直接获取MessageQueue然后调用了enqueueMessage方法,我们再来看看此方法:
[java] view plain copy

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {  
       msg.target = this;  
       if (mAsynchronous) {  
           msg.setAsynchronous(true);  
       }  
       return queue.enqueueMessage(msg, uptimeMillis);  
   }  

enqueueMessage中首先为meg.target赋值为this,【如果大家还记得Looper的loop方法会取出每个msg然后交给msg,target.dispatchMessage(msg)去处理消息】,也就是把当前的handler作为msg的target属性。最终会调用queue的enqueueMessage的方法,也就是说handler发出的消息,最终会保存到消息队列中去。

现在已经很清楚了Looper会调用prepare()和loop()方法,在当前执行的线程中保存一个Looper实例,这个实例会保存一个MessageQueue对象,然后当前线程进入一个无限循环中去,不断从MessageQueue中读取Handler发来的消息。然后再回调创建这个消息的handler中的dispathMessage方法,下面我们赶快去看一看这个方法:
[java] view plain copy

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

可以看到,第10行,调用了handleMessage方法,下面我们去看这个方法:

/** 
   * Subclasses must implement this to receive messages. 
   */  
  public void handleMessage(Message msg) {  
  }  

可以看到这是一个空方法,为什么呢,因为消息的最终回调是由我们控制的,我们在创建handler的时候都是复写handleMessage方法,然后根据msg.what进行消息处理。
例如:

private Handler mHandler = new Handler()  
    {  
        public void handleMessage(android.os.Message msg)  
        {  
            switch (msg.what)  
            {  
            case value:  
                  
                break;  
  
            default:  
                break;  
            }  
        };  
    };  

到此,这个流程已经解释完毕,让我们首先总结一下
1、首先Looper.prepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象;因为Looper.prepare()在一个线程中只能调用一次,所以MessageQueue在一个线程中只会存在一个。
2、Looper.loop()会让当前线程进入一个无限循环,不端从MessageQueue的实例中读取消息,然后回调msg.target.dispatchMessage(msg)方法。
3、Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。
4、Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。
5、在构造Handler实例时,我们会重写handleMessage方法,也就是msg.target.dispatchMessage(msg)最终调用的方法。
好了,总结完成,大家可能还会问,那么在Activity中,我们并没有显示的调用Looper.prepare()和Looper.loop()方法,为啥Handler可以成功创建呢,这是因为在Activity的启动代码中,已经在当前UI线程调用了Looper.prepare()和Looper.loop()方法。

3.3、Handler post

今天有人问我,你说Handler的post方法创建的线程和UI线程有什么关系?
其实这个问题也是出现这篇博客的原因之一;这里需要说明,有时候为了方便,我们会直接写如下代码:

mHandler.post(new Runnable()  
        {  
            @Override  
            public void run()  
            {  
                Log.e("TAG", Thread.currentThread().getName());  
                mTxt.setText("yoxi");  
            }  
        });  

然后run方法中可以写更新UI的代码,其实这个Runnable并没有创建什么线程,而是发送了一条消息,下面看源码:

public final boolean post(Runnable r)  
   {  
      return  sendMessageDelayed(getPostMessage(r), 0);  
   }  

private static Message getPostMessage(Runnable r) {  
      Message m = Message.obtain();  
      m.callback = r;  
      return m;  
  }  

可以看到,在getPostMessage中,得到了一个Message对象,然后将我们创建的Runable对象作为callback属性,赋值给了此message.
注:产生一个Message对象,可以new ,也可以使用Message.obtain()方法;两者都可以,但是更建议使用obtain方法,因为Message内部维护了一个Message池用于Message的复用,避免使用new 重新分配内存。
[java] view plain copy

public final boolean sendMessageDelayed(Message msg, long delayMillis)  
   {  
       if (delayMillis < 0) {  
           delayMillis = 0;  
       }  
       return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);  
   }  


public boolean sendMessageAtTime(Message msg, long uptimeMillis) {  
       MessageQueue queue = mQueue;  
       if (queue == null) {  
           RuntimeException e = new RuntimeException(  
                   this + " sendMessageAtTime() called with no mQueue");  
           Log.w("Looper", e.getMessage(), e);  
           return false;  
       }  
       return enqueueMessage(queue, msg, uptimeMillis);  
   } 

最终和handler.sendMessage一样,调用了sendMessageAtTime,然后调用了enqueueMessage方法,给msg.target赋值为handler,最终加入MessagQueue.
可以看到,这里msg的callback和target都有值,那么会执行哪个呢?
其实上面已经贴过代码,就是dispatchMessage方法:

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

第2行,如果不为null,则执行callback回调,也就是我们的Runnable对象。

4、后话

其实Handler不仅可以更新UI,你完全可以在一个子线程中去创建一个Handler,然后使用这个handler实例在任何其他线程中发送消息,最终处理消息的代码都会在你创建Handler实例的线程中运行。这个就是HandlerThread的实现原理。

new Thread()  
        {  
            private Handler handler;  
            public void run()  
            {  
  
                Looper.prepare();  
                  
                handler = new Handler()  
                {  
                    public void handleMessage(android.os.Message msg)  
                    {  
                        Log.e("TAG",Thread.currentThread().getName());  
                    };  
                };
            Looper.loop();                                                                                                                              }     
【Android 】零基础到飞升 | Handler消息传递机制浅析 3.3 Handler消息传递机制浅析 分类 Android 基础入门教程 本节引言 前两节中我们对Android中的两种事件处理机制进行了学习,关于响应的事件响应就这两种;本节给大家讲解的 是Activity中UI组件中的信息传递Handler,相信很多朋友都知道,Android为了线程安全,并不允许我们在UI线程外操作UI;很多时候我们做界面刷新都需要通过Handler来通知UI组件更新!除了用Handler完成界面更新外,还可以使用runO... 阅读详情

相关推荐

Android开发AsyncTask异步处理任务

NULL 博文链接:https://aking86.iteye.com/blog/1329089

【Android】多线程编程、异步消息处理机制以及new Handler()被标记为过时的解决办法,解决Handler内存泄漏问题和AsyncTask的基本用法

Android多线程编程、异步消息处理机制以及new Handler()被标记为过时的解决办法,解决Handler内存泄漏问(当Activity被销毁时,如果其中使用的Handler被持有,并且在外部引用它的对象的生命周期之外保持活动状态,这就可能导致内存泄漏。)、AsyncTask的基本用法

摸鱼小小虫的博客 2407

IBTrACS v04r01 数据提取实战:Pandas 筛选 JTWC/CMA/JMA 3机构最佳路径数据

本文详细介绍了如何使用 Pandas 高效提取和处理 IBTrACS v04r01 数据集中的最佳路径数据,特别针对 JTWC、CMA 和 JMA 三家权威机构的数据进行对比分析。通过构建可复用的数据提取函数,解决多机构数据质量差异问题,并提供高级分析与可视化应用示例,助力热带气旋研究。

clijovtbq401783153的博客 514

Android 异步任务的6种实现方式详解

使用 Thread 创建使用 Thread + Looper + handler使用 AsyncTask使用 HandlerThread使用 IntentService使用线程池来处理异步任务同时,我们也分析了,每种方式的使用的场景以及它的优点和缺点。**PS:更多精彩内容,请查看 -->《Android 开发》**PS:更多精彩内容,请查看 -->《Android 开发》**PS:更多精彩内容,请查看 -->《Android 开发》作者:卜大爷来源:优快云。

xiaowang_lj的博客 2812

Cocos Creator 3D音频定位实战:从原理到沉浸感实现

3D音频定位是游戏开发中实现沉浸感的关键技术,其核心原理基于HRTF(头部相关传输函数)模型,模拟声音在空间中的传播与双耳感知差异。这项技术通过赋予声音空间坐标、距离衰减和方向属性,将音频从背景元素提升为可交互的环境线索,极大增强了虚拟世界的真实感与玩家的空间认知。在工程实践中,开发者需要深入理解声源、听者、衰减曲线与多普勒效应等基础概念,并合理运用音频池、优先级管理与动态混音等技术手段来平衡效果与性能。对于Cocos Creator开发者而言,无论是使用引擎原生的AudioSource组件构建轻量级方案,

weixin_30972263的博客 291

搭建ROS小车真的难吗?

搭建ROS小车真的难吗?不难 1.引言 本着为大家谋福利的心态,根据自己以往的开发经验,打算写一个从零开始制作一个可以实现地图构建和导航的ROS小车。目前某宝上面有很多现成产品,但是我个人认为,一个好的移动机器人开发工程师,应该对机器人的整个流程都能具备维护的能力,然后再深入研究其中一个方向即可。看到网上很少有整个系列的开发教程,看到同学们大多东拼西凑,浪费了不少时间。我就想着利用空余时间,将我本人的开发过程输出给大家。有基础理论、有实际工程代码、有丰富的学习资料,尽最大努力帮大家进入移动机器人的大门。 国

「小白学移动机器人」一个专注分享移动机器人相关知识的公众号! 1万+

Android --- 异步操作

同步:在发生某件事后什么也不做,直到该事件完成后,再继续进行异步:在某件事发生后,可以在等待他完成的时候去处理其他事件,等到该事件发生完成后,再回过头来处理它。

weixin_43244083的博客 2116

【华为OD机试真题】459、小扇和小船的数字游戏、数字游戏 | 机试真题+思路参考+代码解析(CD卷)(C++、Java、Py)

### 🎃题目描述 >小扇和小船今天又玩起来了数字游戏,小船给小扇一个正整数 n(1  现在求 m 的最小值

KJ.JK 1717

Android知识体系总结2020之Android部分AsyncTask机制篇

Android面试系列文章2018之Android部分AsyncTask机制篇 1.AsyncTask是什么?   它本质上是一个封装了线程池和Handler的异步框架。 2.AsyncTask的基本用法   a.3个参数   b.5个方法   面试的时候说明这三个泛型参数,还有5个方法的作用即可:   http://blog.youkuaiyun.com/iisprin...

编程语言是方式,而思维是创造。 6493

汇川AM系列ethercat控制伺服的使用说明(含转矩模式)

本文以一个实际例子,介绍ethercat伺服驱动器的工作原理,以及在汇川AM系列PLC中,如何点动、定位、速度、转矩控制ethercat伺服。

qq_34047402的博客 5110

TC3XX - MCAL知识点(九):PWM EB-tresos配置说明及代码浅析

脉冲宽度调制(PWM)驱动器负责提供与AUTOSAR指定的PWM信号生成相关的标准服务。PWM通道的底层定时器驱动是GTM (TOM或ATOM片)或CCU6 (T12或T13片)定时器通道。软硬件匹配关系如下:PWM直接引用的是GTM与CCU6模块,然后GTM与CCU6再关联到Port的,根据软硬件匹配关系,也能调用中断来使用,本例子没使用中断。CCU6是一个高分辨率的16位捕获和比较单元,具有特定的应用模式,主要用于交流驱动控制。特殊的工作模式支持控制无刷直流电机使用霍尔传感器或反电动势检测。

梦想技术家 2882

浅析Android的Handler机制

文章目录浅析Android的Handler机制ThreadLocalHandler①专一的Looper与Thread????当你发送信息的时候你在想什么⚪循环,徘徊着等待她的消息 浅析Android的Handler机制 ThreadLocal 理解Java中的ThreadLocal position: package java.lang; Looper初始化的时候,会初始化ThreadLocal public final class Looper { /* * API Implementa

qq_42898299的博客 203

粒子群优化与蚁群算法求解多旅行商问题

它要求在给定一组城市和旅行商之间的距离矩阵的情况下,找到一条最优的路径方案,使得所有旅行商可以分别从起始城市出发,途径其他城市,并最终回到起始城市,同时总旅行距离达到最小。这两种算法都是基于群体智能的优化算法,在求解组合优化问题时具有较好的性能表现。假设有n个城市需要被m个旅行商访问,城市间的距离由距离矩阵D表示,其中D(i,j)表示第i个城市到第j个城市的距离。粒子群优化算法是一种基于群体智能的优化算法,其中的粒子代表了潜在的解,并通过模拟粒子在解空间中的移动来搜索最优解。一、多旅行商问题建模。

m0_47037246的博客 553

Android Handler机制浅析

本文是在读《Android开发艺术探索》这本书中关于“Android的消息机制”时所作记录,以便加深对Android的消息机制的理解。一、概述Android的消息机制主要是指Handler的运行机制,Handler的运行需要底层的MessageQueue 和 Looper的支撑。MessageQueue以队列的形式对外提供插入和删除的工作,虽然叫Queue,但实际上它是采用单链表的数据结构来存储消...

Superior's Blog 269

llama.cpp 参数调优大全(4060 最优配置)

本文针对NVIDIA RTX 4060(8GB显存)显卡,提供了llama.cpp参数调优的实战指南。核心策略是采用小模型(7B/8B)配合Q4_K_M量化,通过合理设置GPU层数(-ngl 28)、上下文长度(-c 2048)和批量大小(-b 512)来平衡性能和显存占用。重点推荐启用flash-attn加速和mlock内存锁定,并给出标准、高性能和保守三种配置方案。调优优先级为:GPU利用率>吞吐量>显存>线程数,同时警示避免常见错误如过大上下文或GPU层数设置。最终推荐4060最佳配置为7B Q4_

刘一说的IT专栏 3402

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Android Looper Handler 机制浅析

最近想写个播放器demo,里面要用到 Looper Handler,看了很多资料都没能理解透彻,于是决定自己看看相关的源码,并在此记录心得体会,希望能够帮助到有需要的人。本文会以猜想 + log验证的方式来学习 Android Looper Handler,对于一些复杂的代码会进行跳过,能够理解它们的设计原理即可。本文观点皆个人拙见,如有错误恳请赐教。

青山渺渺 3304

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

浅析Android Handler机制原理。

首先我们要知道以下几个方面:(基础很重要,要知道的) 第一点:在Android中,只有在UIThread(主线程)中才能直接更新界面。 第二点:在Android中,长时间的工作(联网)都需要在workerThread中执行。 第三点:在子线程中获取服务器的数据之后,要马上到主线程中更新界面。那么怎么才能在主线程中更新界面呢。哈哈那么我们只需要在子线程中new一个runOnUiThread()---> handler。

小学留了三年级的博客 573

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

浅析Android Handler消息机制的实现原理

0. 背景描述 Android系统出于对简单、高效的考虑,在设计UI体系时采用了单线程模型,即不会在多个线程中对同一个UI界面执行操作。简单是指单线程模型可以不用考虑和处理在多线程环境下操作UI带来的线程安全问题,高效是指单线程模型下无需通过额外的手段处理多线程安全问题(一般通过加锁等方式解决线程安全问题,而使用锁进行同步就会存在性能开销)。同时,因为Android应用属于UI交互型应用,需要对用户的操作进行快速响应,因此在处理UI操作的线程中不能执行网络请求、本地IO等这一类耗时操作,否则会导致用户的操作

boker_han的博客 1328

Android中消息机制:Handler机制源码浅析

Android中的消息机制一直都是新手头疼的问题,对于Handler机制的理解是Android重中之重,经常在面试和日常开发中遇到,所以,这篇文章目的是通过解析源码来帮助梳理Handler的工作机制和运行流程。

Geek的博客 506

android handler的机制和原理_浅析Android消息机制 handler之原理分析

前言在日常的开发过程中我们经常会用到Android消息机制,其中Handler尤为常见。比如当我们执行一些耗时操作,例如读写文件,网络IO时是不建议在主线程也就是UI线程上直接进行,而是重新开一个子线程去完成这些耗时操作,而有一些耗时操作需要更改UI,比如我们需要从网络上下载一些图面显示在界面上,当图片下载完成时,由于Android的机制,子线程是无法更改UI的,所以这时候就需要切换到主...

weixin_39665992的博客 330

Android 消息机制-Handler浅析

Android的消息机制其实主要值得就是Handler的运行机制。 Handler的运行需要底层MessageQueue和Looper支撑。

longge33445的博客 408

Android-消息机制(Handler机制)浅析

Android-消息机制浅析 简介 Android消息机制主要就是指Handler的运行机制; 借用网络的图片 图解: 1.以Handler的sendMessage方法为例,当发送一个消息后,会将此消息加入消息队列MessageQueue中。 2.Looper负责去遍历消息队列并且将队列中的消息分发给对应的Handler进行处理。 3.在Handler的handleMessage方法中处理该消息,这就完成了一个消息的发送和处理过程。 这里从图中可以看到参与消息处理有四个对象,它们分别是 Handler,

weixin_43506260的博客 474

浅析Android消息机制 handler之原理分析

前言 在日常的开发过程中我们经常会用到Android消息机制,其中Handler尤为常见。比如当我们执行一些耗时操作,例如读写文件,网络IO时是不建议在主线程也就是UI线程上直接进行,而是重新开一个子线程去完成这些耗时操作,而有一些耗时操作需要更改UI,比如我们需要从网络上下载一些图面显示在界面上,当图片下载完成时,由于Android的机制,子线程是无法更改UI的,所以这时候就需要切换到主线程去更改UI,而这个过程就是由Handler配合完成的。当然更新UI只是Handler的一个功能,它还有更多有趣的功能

QStack的博客 252
上一篇: Android 网络请求混淆问题
下一篇: Android 获取控件宽高
明天的增加
博客等级 码龄11年 22粉丝 71原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值