Android中的享元模式

作者: Anderson大码渣 | 来源:发表于2017-01-21 16:34 被阅读509次
    设计模式.png

    前言

    又来梳理知识点啦!

    在有的时候我们要多次使用某个类中的公有实例方法,我们通常的做法是,先new一个该类的实例,然后再调用该类的这个方法,调用完毕后这个类也就变成垃圾。这种调用方式如果出现的频率很高,会在对象生成和内存占用上浪费很多的资源,一个对象的创建和销毁是很占资源的。

    于是,伟大的程序员们想到一个好办法,尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。经典的享元模式中,是使用一个map来存储对象,相当于是一个对象工厂,客户端每次都从享元对象工厂中获取对象。

    定义

    使用共享对象可有效的支持大量的细粒度对象

    使用场景

    1. 系统中存在大量的相似对象
    2. 对象没有特定的身份,状态都较接近
    3. 需要缓冲池的场景

    使用方法

    享元模式是一种思想,一种避免多次重复创建对象的编程思想。

    我们主要是要创建一个享元工厂,来生产我们的享元类。这样的享元工厂有N种写法,我们常见的是使用map来构造享元工厂,来看一个享元工厂的demo

    import java.util.HashMap;
    
    public class ShapeFactory {
       private static final HashMap<String, Shape> circleMap = new HashMap();
    
       //使用传统的map来管理对象
       public static Shape getObj(String color) {
          Circle circle = (Circle)circleMap.get(color);
    
          if(circle == null) {
             circle = new Circle(color);
             circleMap.put(color, circle);
             System.out.println("Creating circle of color : " + color);
          }
          return circle;
       }
    }
    

    Android中的享元模式应用

    应用的话,若我说,我们编写的ViewHolder都可以归类为享元工厂的存储器。几乎到处是应用,不过最明显的是Handler中Message的应用。

    例如我们发送个0给handler自己。

    handler.obtainMessage(0).sendToTarget();

    我们进去看Handler的源码,obtainMessage如下

        public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
        {
            return Message.obtain(this, what, arg1, arg2, obj);
        }
    
    

    我们发现,其中调用了Message.obtain,我们再去看Message的实现

        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;
        }
        
        //获取一个空message
        public static Message obtain() {
            synchronized (sPoolSync) {
                //从对象Message中获取message
                if (sPool != null) {   //private static Message sPool;
                    Message m = sPool;
                    sPool = m.next;
                    //清空message属性
                    m.next = null;
                    m.flags = 0; // clear in-use flag 
                    sPoolSize--;
                    return m;
                }
            }
            return new Message();
        }
    

    我们可以看到,sPool指向的是一个链表,其实这个链表是存储我们用过的Message的,当我们obtain一个Message的时候,会去取链表中的第一个,并把sPool指向下一个,同时把取到的置空。

        /*Message的回收方法*/
        public void recycle() {
            if (isInUse()) {
                if (gCheckRecycle) {
                    throw new IllegalStateException("This message cannot be recycled because it "
                            + "is still in use.");
                }
                return;
            }
            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;
    
        /*将用过的Message放入链表中*/
            synchronized (sPoolSync) {
                if (sPoolSize < MAX_POOL_SIZE) {
                    next = sPool;
                    sPool = this;
                    sPoolSize++;
                }
            }
        }
    
    

    我们可以知道Message的享元模式不是使用的传统的map方式,而是自己构建一个链表,灵活使用我们的享元模式思想才是重点。


    谢谢大家阅读,如有帮助,来个喜欢或者关注吧!


    本文作者:Anderson/Jerey_Jobs

    博客地址 : 夏敏的博客/Anderson大码渣/Jerey_Jobs

    简书地址 : Anderson大码渣

    CSDN地址 : Jerey_Jobs的专栏

    github地址 : Jerey_Jobs

    相关文章

      网友评论

        本文标题:Android中的享元模式

        本文链接:https://www.haomeiwen.com/subject/gyqnbttx.html