Android PooledLambda记录

Android PooledLambda记录,第1张

Android PooledLambda记录

首先需要弄清楚Pool,这个接口的定义位于frameworks/base/core/java/android/util/Pools.java

是一个工具类,内容如下:

public static interface Pool {

    
    @UnsupportedAppUsage
    public T acquire();

    
    @UnsupportedAppUsage
    public boolean release(T instance);
}

可以看到只有两个方法,这是一个池子管理的内容方式非常单一就两种,一种是请求,一种是发布。在这个文件中有一个简单的实现,如下:

public static class SimplePool implements Pool {
    @UnsupportedAppUsage
    private final Object[] mPool;

    private int mPoolSize;

    
    @UnsupportedAppUsage
    public SimplePool(int maxPoolSize) {
        if (maxPoolSize <= 0) {
            throw new IllegalArgumentException("The max pool size must be > 0");
        }
        mPool = new Object[maxPoolSize];
    }

    @Override
    @SuppressWarnings("unchecked")
    @UnsupportedAppUsage
    public T acquire() {
        if (mPoolSize > 0) {
            final int lastPooledIndex = mPoolSize - 1;
            T instance = (T) mPool[lastPooledIndex];
            mPool[lastPooledIndex] = null;
            mPoolSize--;
            return instance;
        }
        return null;
    }

    @Override
    @UnsupportedAppUsage
    public boolean release(T instance) {
        if (isInPool(instance)) {
            throw new IllegalStateException("Already in the pool!");
        }
        if (mPoolSize < mPool.length) {
            mPool[mPoolSize] = instance;
            mPoolSize++;
            return true;
        }
        return false;
    }

    private boolean isInPool(T instance) {
        for (int i = 0; i < mPoolSize; i++) {
            if (mPool[i] == instance) {
                return true;
            }
        }
        return false;
    }
}

可以得出,这个类就是用来管理一个对象栈,当aquire的时候就把最后一个实例取出来并且删除,release的时候就检索一下是否存在,存在就不入栈,不存在就放在最后一个,检索这一步就是与栈的唯一区别,然后有一个同步类定义如下:

public static class SynchronizedPool extends SimplePool {
    private final Object mLock;

    
    public SynchronizedPool(int maxPoolSize, Object lock) {
        super(maxPoolSize);
        mLock = lock;
    }

    
    @UnsupportedAppUsage
    public SynchronizedPool(int maxPoolSize) {
        this(maxPoolSize, new Object());
    }

    @Override
    @UnsupportedAppUsage
    public T acquire() {
        synchronized (mLock) {
            return super.acquire();
        }
    }

    @Override
    @UnsupportedAppUsage
    public boolean release(T element) {
        synchronized (mLock) {
            return super.release(element);
        }
    }
}

只是原有的基础上加锁,防止多线程访问下资源的竞争。

接下来我们先看一个使用实例,如下:

mHandler.sendMessage(PooledLambda.obtainMessage(
        AppOpsService::notifyOpChanged,
        this, repCbs, code, uid, packageName));

这里可以看到我们这里直接使用了PooledLambda的obtainMessage函数,这个函数的定义如下:

static  Message obtainMessage(
QuintConsumer function,
        A arg1, B arg2, C arg3, D arg4, E arg5) {
    synchronized (Message.sPoolSync) {
        PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
                function, 5, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, null, null, null,
                null);
        return Message.obtain().setCallback(callback.recycleonUse());
    }
}

可以看到这是一个静态函数,可以在接口外部直接被调用,这个接口里面就是使用了我们经典的lambda定义方式。这个泛型的定义巧妙的將我们的函数以及需要传出的参数类型巧妙的连接起来,第一个传入的lambda接口跟后面的参数类型紧紧相关,我们调用这个函数的时候直接將需要传入的参数一并传入,省的后续再次重新传参。这里需要提到的是lambda里面的中间接口是一种隐藏式的存在我们在调用的过程中可以直接匿名忽略掉,本次的调用实例就是如此,直接使用了::符号直接链接到目标函数notifyOpChanged。

这里传入QuintConsumer接口,这个接口的定义如下:

public interface QuintConsumer {
    void accept(A a, B b, C c, D d, E e);
}

可以看到这个接口只有一个方法,这个方法就是我们要去用lamba来实现的功能。这里需要注意的是我们的accept函数是需要5个参数的,但是我们在调用赋值的

notifyOpChanged函数只有四个参数如下:
private void notifyOpChanged(ArraySet callbacks, int code,
        int uid, String packageName) {
    for (int i = 0; i < callbacks.size(); i++) {
        final ModeCallback callback = callbacks.valueAt(i);
        notifyOpChanged(callback, code, uid, packageName);
    }
}

为什么这样被允许,可以看到我们obtainMessage这个函数定义的时候后面是紧跟着5个参数的,我们只需要在调用的时候將第2个参数传入为this这样默认我们4个参数的函数就允许被加载进去,第2个参数相当于是一个指针,指向我们这个函数定义的类。

根据泛型的定义我们可以推测到五个参数分别为this类的类型然后是ModeCallBack,int,int,String的类型。默认我们把this已经作为一个参数传递给QuintConsumer接口。

然后去看acquire函数的定义这个函数位于frameworks/base/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java可以看到这是一个实现类,他就是实现我们PooledLambda里面的一些具体功能。这个类继承自OmniFunction,而QmniFunction是一个抽象类,里面包含了Pooled的所有功能实现,这些实现又全部通过指派给了抽象函数involk,这样具体的实现就交给了子类。可以认为这里就是一个列表,列出了所有要实现的函数。

abstract class OmniFunction implements
        PooledFunction, BiFunction, TriFunction,
        QuadFunction, QuintFunction,
        HexFunction, HeptFunction,
        OctFunction, NonaFunction,
        PooledConsumer, BiConsumer, TriConsumer, QuadConsumer,
        QuintConsumer, HexConsumer,
        HeptConsumer, OctConsumer,
        NonaConsumer, PooledPredicate, BiPredicate,
        PooledSupplier, PooledRunnable, ThrowingRunnable, ThrowingSupplier,
        PooledSupplier.OfInt, PooledSupplier.OfLong, PooledSupplier.OfDouble 

abstract R invoke(A a, B b, C c, D d, E e, F f, G g, H h, I i);

@Override
public R apply(A o, B o2) {
    return invoke(o, o2, null, null, null, null, null, null, null);
}

令人眼花缭乱,这样一个工具类包含的功能确实齐全,但是真站内存啊阿。

我们的子类PooledLambdaImpl相当忙活去实现这invoke函数。

我们继续查看PooledLambdaImpl的acquire这个静态函数如下:

static  E acquire(Pool pool, Object func,
        int fNumArgs, int numPlaceholders, int fReturnType, Object a, Object b, Object c,
        Object d, Object e, Object f, Object g, Object h, Object i) {
    PooledLambdaImpl r = acquire(pool);
    if (DEBUG) {
        Log.i(LOG_TAG,
                "acquire(this = @" + hashCodeHex(r)
                        + ", func = " + func
                        + ", fNumArgs = " + fNumArgs
                        + ", numPlaceholders = " + numPlaceholders
                        + ", fReturnType = " + LambdaType.ReturnType.toString(fReturnType)
                        + ", a = " + a
                        + ", b = " + b
                        + ", c = " + c
                        + ", d = " + d
                        + ", e = " + e
                        + ", f = " + f
                        + ", g = " + g
                        + ", h = " + h
                        + ", i = " + i
                        + ")");
    }
    r.mFunc = Preconditions.checkNotNull(func);
    r.setFlags(MASK_FUNC_TYPE, LambdaType.encode(fNumArgs, fReturnType));
    r.setFlags(MASK_EXPOSED_AS, LambdaType.encode(numPlaceholders, fReturnType));
    if (ArrayUtils.size(r.mArgs) < fNumArgs) r.mArgs = new Object[fNumArgs];
    setIfInBounds(r.mArgs, 0, a);
    setIfInBounds(r.mArgs, 1, b);
    setIfInBounds(r.mArgs, 2, c);
    setIfInBounds(r.mArgs, 3, d);
    setIfInBounds(r.mArgs, 4, e);
    setIfInBounds(r.mArgs, 5, f);
    setIfInBounds(r.mArgs, 6, g);
    setIfInBounds(r.mArgs, 7, h);
    setIfInBounds(r.mArgs, 8, i);
    return (E) r;
}

通过这里我们可以看到最终返回的是一个r,这个r的类型为PooledLambdaImpl类型,因为这个类型继承了OmniFunction并且OmniFunction实现了那么多接口,所以这个类型所涵盖的范围就很广了,我们此次acquire的PooledRunnable类型只是其中的一种,这里QmniFunction的很巧妙的使用了设计模式中的依赖倒置原则。表面上看它实现了那么多接口其实他通过抽象函数involke的方式把具体的实现传递给了子类,这样子类可以根据业务有更多更具体的实现。

这里需要注意的是最后我们使用了强制类型转换是因为有时候我们是父类转换成子类。

我们在acquire的时候第一个参数是sMessageCallbacksPool,这个成员变量的定义以及初始化是在PooledLambdaImpl中来实现的,这里也是跟我们文章开头关联的地方需要用到Pool了,定义如下:

static final Pool sMessageCallbacksPool = new Pool(Message.sPoolSync);
static class Pool extends Pools.SynchronizedPool {

    public Pool(Object lock) {
        super(MAX_POOL_SIZE, lock);
    }
}

可以看到这里的Pool继承自SynchronizedPool,所以这里也是对对象的池管理。并且初始化了大小。

acquire(pool);

的实现如下:

static PooledLambdaImpl acquire(Pool pool) {
    PooledLambdaImpl r = pool.acquire();
    if (r == null) r = new PooledLambdaImpl();
    r.mFlags &= ~FLAG_RECYCLED;
    r.setFlags(FLAG_ACQUIRED_FROM_MESSAGE_CALLBACKS_POOL,
            pool == sMessageCallbacksPool ? 1 : 0);
    return r;
}

可以看到我们在这里new了一个PooledLambdaImpl实例,并且设置了标志位。通过setIfBounds来管理mArgs数组

private static void setIfInBounds(Object[] array, int i, Object a) {
    if (i < ArrayUtils.size(array)) array[i] = a;
}
 Object[] mArgs = null;

来管理调用者args参数。从0-8已经涵盖了最长参数的函数。

本次我们acquire的是一个PooledRunnable类型,同样这个类型被OmniFunction实现,实现方法如下:

@Override
public abstract OmniFunction recycleonUse();

哦,这里直接是一个抽象函数那么就要看看我们子类PooledLambdaImpl的实现了。

如下:

@Override
public OmniFunction recycleonUse() {
    if (DEBUG) Log.i(LOG_TAG, this + ".recycleonUse()");
    mFlags |= FLAG_RECYCLE_ON_USE;
    return this;
}

直接返回this那么就是我们这整个类咯。我们现在比较关心的是run函数,那么这个函数的直接实现也是在QmniFunction,然后如下:

@Override
public void run() {
    invoke(null, null, null, null, null, null, null, null, null);
}

所以去看PooledLambdaImpl的invoke函数:

@Override
R invoke(Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7,
        Object a8, Object a9) {
    checkNotRecycled();
    if (DEBUG) {
        Log.i(LOG_TAG, this + ".invoke("
                + commaSeparateFirstN(
                        new Object[] { a1, a2, a3, a4, a5, a6, a7, a8, a9 },
                        LambdaType.decodeArgCount(getFlags(MASK_EXPOSED_AS)))
                + ")");
    }
    final boolean notUsed = fillInArg(a1) && fillInArg(a2) && fillInArg(a3) && fillInArg(a4)
            && fillInArg(a5) && fillInArg(a6) && fillInArg(a7) && fillInArg(a8)
            && fillInArg(a9);
    int argCount = LambdaType.decodeArgCount(getFlags(MASK_FUNC_TYPE));
    if (argCount != LambdaType.MASK_ARG_COUNT) {
        for (int i = 0; i < argCount; i++) {
            if (mArgs[i] == ArgumentPlaceholder.INSTANCE) {
                throw new IllegalStateException("Missing argument #" + i + " among "
                        + Arrays.toString(mArgs));
            }
        }
    }
    try {
        return doInvoke();
    } finally {
        if (isRecycleonUse()) doRecycle();
        if (!isRecycled()) {
            int argsSize = ArrayUtils.size(mArgs);
            for (int i = 0; i < argsSize; i++) {
                popArg(i);
            }
        }
    }
}

这里可以看到直接调用了doInvoke函数,

private R doInvoke() {
    final int funcType = getFlags(MASK_FUNC_TYPE);
    final int argCount = LambdaType.decodeArgCount(funcType);
    final int returnType = LambdaType.decodeReturnType(funcType);

    switch (argCount) {
        case LambdaType.MASK_ARG_COUNT: {
            switch (returnType) {
                case LambdaType.ReturnType.INT: return (R) (Integer) getAsInt();
                case LambdaType.ReturnType.LONG: return (R) (Long) getAsLong();
                case LambdaType.ReturnType.DOUBLE: return (R) (Double) getAsDouble();
                default: return (R) mFunc;
            }
        }
        case 0: {
            switch (returnType) {
                case LambdaType.ReturnType.VOID: {
                    ((Runnable) mFunc).run();
                    return null;
                }
                case LambdaType.ReturnType.BOOLEAN:
                case LambdaType.ReturnType.OBJECT: {
                    return (R) ((Supplier) mFunc).get();
                }
            }
        } break;

这里的run应该是0参数所以我们把后续的省略了,只看0参数的情况,直接就调用了run函数。

所以回到obtainMessage函数中的

 PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
                    function, 5, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, null, null, null,
                    null);
            return Message.obtain().setCallback(callback.recycleonUse());

这里我们通过auquire函数得到了一个PooledRunnable实例,又通过他的recycleOnUse函数得到了

PooledLambdaImpl的实例。所以当我们sendMessage的时候这个callback会run起来。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5683109.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存