obtain_handler.obtainmessage() - CSDN
精华内容
参与话题
  • 1. 前言创建Message对象的时候,有三种方式,...2.Message msg2 = Message.obtain(); 3.Message msg1 = handler1.obtainMessage(); 这三种方式有什么区别呢?2.使用方式public class MainActivity extends Activ
    1. 前言

    创建Message对象的时候,有三种方式,分别为:
    1.Message msg = new Message();
    2.Message msg2 = Message.obtain();
    3.Message msg1 = handler1.obtainMessage();
    这三种方式有什么区别呢?

    2.使用方式

    public class MainActivity extends Activity {
    
        private Handler handler1 = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                Toast.makeText(MainActivity.this, "hanlder1", Toast.LENGTH_SHORT).show();
                super.handleMessage(msg);
            }
        };
        ;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            new Thread(new Runnable() {
                @Override
                public void run() {
    //                Message msg = new Message();
    //                Message msg2 = Message.obtain();
                    Message msg1 = handler1.obtainMessage();
                    msg1.arg1 = 1;
                    handler1.sendMessage(msg1);
                }
            }).start();
        }
    }
    

    3.源码讲解

    1)Message msg = new Message();这种就是直接初始化一个Message对象,没有什么特别的。
    2)Message msg2 = Message.obtain();

    /**
         * Return a new Message instance from the global pool. Allows us to
         * avoid allocating new objects in many cases.
         */
        public static Message obtain() {
            synchronized (sPoolSync) {
                if (sPool != null) {
                    Message m = sPool;
                    sPool = m.next;
                    m.next = null;
                    m.flags = 0; // clear in-use flag
                    sPoolSize--;
                    return m;
                }
            }
            return new Message();
        }
    

    从注释可以得知,从整个Messge池中返回一个新的Message实例,通过obtainMessage能避免重复Message创建对象。
    3)Message msg1 = handler1.obtainMessage();

    public final Message obtainMessage()
        {
            return Message.obtain(this);
        }
    
    public static Message obtain(Handler h) {
            Message m = obtain();
            m.target = h;
    
            return m;
        }
    
    public static Message obtain() {
            synchronized (sPoolSync) {
                if (sPool != null) {
                    Message m = sPool;
                    sPool = m.next;
                    m.next = null;
                    m.flags = 0; // clear in-use flag
                    sPoolSize--;
                    return m;
                }
            }
            return new Message();
        }
    

    可以看到,第二种跟第三种其实是一样的,都可以避免重复创建Message对象,所以建议用第二种或者第三种任何一个创建Message对象。
    详细的源码讲解请看下篇:源码角度讲解Android消息处理机制(Handler、Looper、MessageQueue与Message)


    如有错误欢迎指出来,一起学习。
    在这里插入图片描述

    展开全文
  • 谷歌推荐:Message.obtain() Message.obtain(),在这里我们的Message已经不是自己创建的了,而是从MessagePool(消息池)拿的,省去了创建对象申请内存的开销。 <script type="text/javascript"&...

    谷歌推荐:Message.obtain()

    Message.obtain(),在这里我们的Message已经不是自己创建的了,而是从MessagePool(消息池)拿的,省去了创建对象申请内存的开销。

    <script type="text/javascript"> $(function () { $('pre.prettyprint code').each(function () { var lines = $(this).text().split('\n').length; var $numbering = $('<ul/>').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($('<li/>').text(i)); }; $numbering.fadeIn(1700); }); }); </script>
    展开全文
  • 提供obtain 回收recycle提供obtain()在obtain的所有重载方法中,第一行都是Message m = obtain();,即调用空参的方法。 先来看一下这个空参方法public static Message obtain() { synchronized (sPoolSync) { if ...

    【Android自助餐】Handler消息机制完全解析(一)Message中obtain()与recycle()的来龙去脉

    提供obtain()

    在obtain的所有重载方法中,第一行都是Message m = obtain();,即调用空参的方法。
    先来看一下这个空参方法

    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

    很明显,这是个同步方法,sPoolSync即锁对象,该对象在定义时即被初始化private static final Object sPoolSync = new Object();,随后便只读不写。
    然后便是sPool,后面还有Message m = sPool;sPool = m.next;,很明显可以看出来,这是一个链表结构。sPool指向当前message,next指向下一个message。
    在解释这段代码前,需要先明确两点:sPool声明为private static Message sPool;next声明为/*package*/ Message next;。即前者为该类所有示例共享,后者则每个实例都有。
    现在为了便于理解,我们将Message抽象为C语言中的链表节点结构体,指针域便是用于指向下一个消息的next字段,其他则都视为数据域。
    假设该链表初始状态如下
    初始状态
    执行Message m = sPool;就变成下图
    Message m = sPool
    继续sPool = m.next;
    sPool = m.next
    然后m.next = null;
    m.next = null
    接下来m.flags=0;sPoolSize--;return m;便是表示m指向的对象已经从链表中取出并返回了。

    回收recycle()

    然后再看看sPoolSize是什么时候自增的。按图索骥便可找到recycle()方法和recycleUnchecked()方法。前者供开发者调用进行回收,后者执行回收操作。来看看回收操作都干了啥:

    void recycleUnchecked() {
        // Mark the message as in use while it remains in the recycled object pool.
        // Clear out all other details.
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = -1;
        when = 0;
        target = null;
        callback = null;
        data = null;
    
        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }

    前半段不必多说,显然是“重置”改对象的个个字段。后半段又是一个同步代码段,同样用图来解释一下(假设当前代码为message.recycle(),则需要被回收的则是message对象)。
    假设当前链表如下:
    初始状态
    执行next=sPool;
    next=sPool
    执行sPool=this;
    sPool=this
    现在可以很清楚的看到,Message类本身就组织了一个栈结构的缓冲池。并使用obtain()方法和recycler()方法来取出和放入。

    展开全文
  • 在上一讲中[Android消息处理机制之Handler与Message],我们学习了Handler类与... Message" 的方式来获取,而必须使用 Obtain()的方式来获取Message对象,这是为什么呢?  我们可以针对上一讲的例子中的代码如下: h

      阅读本文之前,请先阅读相关链接:

      Android 消息处理机制之一: Handler与Message

      Android 消息处理机制之三: Handler中sendMessage()源代码剖析

      在上一讲中[Android消息处理机制之Handler与Message],我们学习了Handler类与Message类的大概介绍,同事也遗留了一个问题,在获取Message对象的时候是不能用 "new Message" 的方式来获取,而必须使用 Obtain()的方式来获取Message对象,这是为什么呢?

      我们可以针对上一讲的例子中的代码如下:

                    httpResponse = httpClient.execute(httpGet);
                    if(200 == httpResponse.getStatusLine().getStatusCode()){
                        byte[] data = EntityUtils.toByteArray(httpResponse.getEntity());
                        // 这里的数据data我们必须发送给UI的主线程,所以我们通过Message的方式来做桥梁。
                        Message message = Message.obtain();
                        message.obj = data;
                        message.what = DOWNLOAD_IMG;
                        handler.sendMessage(message);
                    }

    1) 跟踪Message.java中的obtain()方法如下:

        private static final Object sPoolSync = new Object();
        private static Message sPool;
        private static int sPoolSize = 0;
    
        private static final int MAX_POOL_SIZE = 10;
        
        /**
         * Return a new Message instance from the global pool. Allows us to
         * avoid allocating new objects in many cases.
         */
        public static Message obtain() {
            synchronized (sPoolSync) {
                if (sPool != null) {
                    Message m = sPool;
                    sPool = m.next;
                    m.next = null;
                    sPoolSize--;
                    return m;
                }
            }
            return new Message();
        }

    【分析】: 从obtain()的源代码中我们可以知道,它是静态方法,而且只有在spool = null 的情况下才会new出一个Message(),返回一个Message对象,如果在不为空的情况下,Message的对象都是从Message对象池里面拿的实例从而重复使用的,这也为了Android中的Message对象能够更好的回收。

    查看Message的源代码,我们可以发现它有多个重载的obtain()方法,这一讲我们就来通过Demo和Message源码来剖析它们之间的不同。

    一. 先通过一个程序Demo来进入主题

      通过Thread + Handler + Message的方式在子线程中发送信息,然后在控制台中输出。代码与上一讲中的代码架构类似,我们主要是看一下子线程中run()的处理和Handler的处理。

    1.Handler 处理并输出控制台

        private Handler handler = new Handler(){
            @Override
            public void handleMessage(android.os.Message msg) {
                int arg1 = msg.arg1;
                int arg2 = msg.arg2;
                int what = msg.what;
                Object result = msg.obj;
                System.out.println("--> arg1: " + arg1);
                System.out.println("--> arg2: " + arg2);
                System.out.println("--> what: " + what);
                System.out.println("--> result: " + result);
            }
        };

    2. 子线程 MyThread 的处理

    1) 通过 Message.obtain()方式获取Message对象

        public class MyThread implements Runnable{
    
            @Override
            public void run() {
                // 使用第一种构造方法
                Message message = Message.obtain();
                message.what = 1;
                message.arg1 = 1;
                message.arg2 = 3;
                message.obj = "AHuier";
                handler.sendMessage(message);
            }        
        }
      程序执行输出如下图所示:

    [分析源码]: 这种方式博文上述中已经分析过了,主要工作是在Message对象池中获取对象。

    2) 通过 Message.obtain(Handler h)的方式获取Message对象

                /*
                 *  第二种获取Message对象的方法
                 *  public static Message obtain (Handler h)
                 *  传递一个关联到消息Handler.
                 */
                Message message = Message.obtain(handler);
                message.what = 1;
                message.arg1 = 1;
                message.arg2 = 3;
                message.obj = "AHuier";
                message.sendToTarget(); // 完成发送消息的动作

    [分析源码]:

        /**
         * Same as {@link #obtain()}, but sets the value for the <em>target</em> member on the Message returned.
         * @param h  Handler to assign to the returned Message object's <em>target</em> member.
         * @return A Message object from the global pool.
         */
        public static Message obtain(Handler h) {
            Message m = obtain();
            m.target = h;
    
            return m;
        }
      先调用obtain()的方式来获取Message对象,然后把Handler的对象给了Message,我们查看一下sendToTarget()的操作:
        ...
        /*package*/ Handler target;  
        ... 
        /**
         * Sends this Message to the Handler specified by {@link #getTarget}.
         * Throws a null pointer exception if this field has not been set.
         */
        public void sendToTarget() {
            target.sendMessage(this);
        }
    它是完成发送消息的动作,所以这种方式不需要在通过sendMessage的方式来处理了。只需要调用messge.sendToTarget();的方式就可以了。

    3) 通过 Message.obtain(Handler h)的方式获取Message对象

                /*
                 * 第三种获取Message对象的方法
                 * public static Message obtain (Handler h, int what)
                 * 关联一个Handler和传递一个what的属性值
                 */
                Message message = Message.obtain(handler, 1);
                message.arg1 = 1;
                message.arg2 = 3;
                message.obj = "AHuier";
                message.sendToTarget();
    [分析源码]:
        /**
         * Same as {@link #obtain()}, but sets the values for both <em>target</em> and
         * <em>what</em> members on the Message.
         * @param h  Value to assign to the <em>target</em> member.
         * @param what  Value to assign to the <em>what</em> member.
         * @return A Message object from the global pool.
         */
        public static Message obtain(Handler h, int what) {
            Message m = obtain();
            m.target = h;
            m.what = what;
    
            return m;
        }
      从源码我们可以看出这种方式更为简便,它也是内部将handle和what都赋值给Message对象,从而简化我们的代码。

    4) 通过 Message.obtain(Handler h, int what, int arg1, int arg2, Object obj)的方式获取Message对象

                /*
                 * public static Message obtain (Handler h, int what, int arg1, int arg2, Object obj)
                 * 关联Handler和传递Message的几种常用属性值
                 */
                Message message = Message.obtain(handler, 1, 1, 3, "AHuier");
                message.sendToTarget();
    [分析源码]:
        /**
         * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>, 
         * <em>arg1</em>, <em>arg2</em>, and <em>obj</em> members.
         * 
         * @param h  The <em>target</em> value to set.
         * @param what  The <em>what</em> value to set.
         * @param arg1  The <em>arg1</em> value to set.
         * @param arg2  The <em>arg2</em> value to set.
         * @param obj  The <em>obj</em> value to set.
         * @return  A Message object from the global pool.
         */
        public static Message obtain(Handler h, int what, 
                int arg1, int arg2, Object obj) {
            Message m = obtain();
            m.target = h;
            m.what = what;
            m.arg1 = arg1;
            m.arg2 = arg2;
            m.obj = obj;
    
            return m;
        }
    同理,从源码中我们可以看出它也是在obtain()方法内部将传递过来的参数赋值给Message对象了。

    5) 通过上述几个例子我们可以知道Message中的obtain()的几种重载方法在底层的实现都是大同小异的,他们都是底层都是首先调用obtain()方法来从消息池中获得一个消息的对象的。然后在通过参数传递来封装指定的Handler和需要携带的数据。如果使用这些重载的方法建议完成数据封装之后调用sendToTarget()方法。这就是几种obtain()重载方法的不同。

    6) 这里我们需要特别注意Message中的这个重载方法:Message obtain (Message orig) 它是将原有的消息体作为一个新的消息参数来发送的,我们看一下它的源代码。

        /**
         * Same as {@link #obtain()}, but copies the values of an existing
         * message (including its target) into the new one.
         * @param orig Original message to copy.
         * @return A Message object from the global pool.
         */
        public static Message obtain(Message orig) {
            Message m = obtain();
            m.what = orig.what;
            m.arg1 = orig.arg1;
            m.arg2 = orig.arg2;
            m.obj = orig.obj;
            m.replyTo = orig.replyTo;
            if (orig.data != null) {
                m.data = new Bundle(orig.data);
            }
            m.target = orig.target;
            m.callback = orig.callback;
    
            return m;
        }
    通过源码知道,同样它首先先从Message对象池中获取Message对象,然后将原有Message中的各种属性值赋予新的信息中的各种属性值,最后返回新的消息对象,再发送出去。

    3. 使用Bundle方式来传递复杂的数据类型

    1) 在前面的Message的Demo中,我们采用的都是传递Message自带的属性来传递一些轻量级的int类型和Object类型数据,那么如果是复杂一点的数据类型,Message也是可以传递的,传递的方式是就是采用Bundle的方式。

    2) 查看Message中的api文档,我们就是采用setData(Bundle data)方法来绑定一个Bundle类型对象,而你可以往Bundle里面填充各种类型。

    3) 程序Demo如下

    i. 往Bundle中填入数据,同时发送消息

                /*
                 * public static Message obtain (Handler h, int what, int arg1, int arg2, Object obj)
                 * 关联Handler和传递Message的几种常用属性值
                 */
                Message message = Message.obtain(handler, 1, 1, 3, "AHuier");
                Bundle data = new Bundle();
                data.putStringArray("str", new String[]{"AHui", "AHui1", "AHui2"});
                message.setData(data);
                message.sendToTarget();
    ii. 处理消息,同时从Bundle中取出数据,打印到控制台,输出键"str"的字符串数组长度为3
        private Handler handler = new Handler(){
            @Override
            public void handleMessage(android.os.Message msg) {
                int arg1 = msg.arg1;
                int arg2 = msg.arg2;
                int what = msg.what;
                Object result = msg.obj;
                System.out.println("--> arg1: " + arg1);
                System.out.println("--> arg2: " + arg2);
                System.out.println("--> what: " + what);
                System.out.println("--> result: " + result);
                System.out.println("----------------------");
                Bundle bundle = msg.getData();
                System.out.println("--> bundle: " + bundle.getStringArray("str").length);
            }
        };
    【总结】:这种方式也Android推荐使用的。但是我自己对这一部分的理解是:

      如果是携带的是轻量级的int类型的数据或者对象的话,我们就用Message构造方法中自带的属性来传递。如果是需要携带上述两种类型之外的数据类型或者一些比较复杂的数据类型建议使用Bundle的方式来封装好后来传递。


    源码下载:HandlerMessageTest2




    展开全文
  • 前言:在我们日常开发工作中,难免经常会在线程间进行消息传递,而这个过程最常用的实现方式就是Handler消息机制。当然,这并不我们今天的重点,今天我们要重点关注的是消息传递的中间体:Message。...
  • Failed to obtain JDBC Connection

    万次阅读 2018-12-11 13:46:52
    环境: spring cloud + myBatis + MySql5 报错信息如下: Caused by: org.apache.ibatis.exceptions.PersistenceException: ### Error querying database. Cause: org.springframework.jdbc....
  • public void onMounted(String mountPoint) { LogUtils.i(TAG,"onMounted,mountPoint="+mountPoint);... Message.obtain(mHandler,MSG_DO_MOUNTED,mountPoint).sendToTarget(); }源码分析: Return a new Message i
  • Handler.obtainMessage()

    万次阅读 多人点赞 2012-08-28 10:10:41
    转自:... 话说在工作中第一次接触android 的Handler 的时候,不知道怎么去关注性能。 记得当时这么写的: ...Message msg = new Message() ...msg.arg2
  • 环境: MacBook Pro 15 jdk8 IntelliJ IDEA 问题: Error querying database.... org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested except...
  • Causedby:org.springframework.jdbc.CannotGetJdbcConnectionException:FailedtoobtainJDBCConnection;nestedexceptionisjava.sql.SQLException:Failedtovalidateanewlyestablishedconnection. ...
  • 本地是mysql,服务器上面是sql server2008,部署项目时报错怎么处理?
  • 寻找主要信息:failed to obtain node locks 简单理解为:绑定节点失败!!! 百度后,好多人同样遇到了这个问题,导致的原因可能是因为之前运行的es还没有正常关闭。 第一步:通过命令:ps aux | grep ...
  • 最近项目中需要配置多数据源,在执行查询方法时遇到一个错误Failed to obtain JDBC Connection: dbType not support,记录下解决过程。 正文 问题再现 Cause: org.springframework.jdbc....
  • Could not obtain connection metadata

    万次阅读 2010-01-23 01:44:00
    用hibernate连接数据库出现错误009-09-27 17:38:15,093 [main] WARN [org.hibernate.cfg.SettingsFactory] - Could not obtain connection metadata java.sql.SQLException: 不支持的特性
  • 学习慕课上的一个项目,使用的是Spring+Mybatis+c3po 学习搭建框架。 org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException: ...
  • 成功解决Please use the NLTK Downloader to obtain the resource:

    万次阅读 多人点赞 2020-05-05 09:35:18
    成功解决Please use the NLTK Downloader to obtain the resource: 目录 解决问题 解决思路 解决方法 解决问题 Please use the NLTK Downloader to obtain the resource: [31m>>> ...
  • java.io.IOException: Lock obtain timed out: Lock@F:/Tomcat 5.0/temp/lucene-424c6f3ac55284d5cd628ea4fb464f10-write.lock at org.apache.lucene.store.Lock.obtain(Lock.java:56) at org.apache.lucene.index...
  • 今天使用Java8的日期类LocalDateTime和DateTimeFormatter处理String型的日期类型yyyy.MM.dd String validDate = "2008.04.30-2018.04.30"; String end = validDate.substring(validDate.indexOf("-")+1, validDate...
  • Could not obtain the localhost address...解决方法
  • 出错的原因: 使用mysql的jdbc驱动最新版(6.0+)时,会遇到数据库和系统时区差异引起的问题。 注:CST代表的是中国上海时间(与北京时间,东八区相同)。 解决: 在 jdbc的url后加serverTimezone=CST ...
1 2 3 4 5 ... 20
收藏数 126,235
精华内容 50,494
关键字:

obtain