Android属性アニメーションObjectAnimatorソースコードの簡単な分析


前の記事のAndroid属性アニメーションValueAnimatorのソースコードを簡単に分析した上で.ObjectAnimatorの簡単な実装を見続けます.
前の文章のAndroid属性アニメーションValueAnimatorのソースコードの简単な分析非常に简単な分析Android属性アニメーションValueAnimatorのソースコードを分析して、简単な総括をして、简単に言えばValueAnimatorの中でしたことはまずValueAnimatorを通じてofInt()またはValueAnimator.ofArgb()またはValueAnimator.ofFloat()などの関数でPropertyValuesHolderオブジェクトを生成し、アニメーション全体のキーポイントを先に分割してKeyframeオブジェクトのリストに入れ、PropertyValuesHolderでこれらのKeyframeリストを関連付け、その後ValueAnimatorを呼び出す.start()関数の後、アニメーションの再生中にPropertyValuesHolderオブジェクトのcalculateValue関数を介して入力された時点から属性の値を取得し、AnimatorUpdateListenerインタフェースのonAnimationUpdate()コールバック関数を呼び出して上位アニメーションの再生中に変化に値することを伝える.だからValueAnimatorを使う時私達は自分でAnimatorUpdateListener(onAnimationUpdate)のコールバックインタフェースを実現します.
ObjectAnimatorはValueAnimatorのサブクラスで、ValueAnimatorをさらにカプセル化しています.ValueAnimatorよりも一歩多く、アニメーションの再生中にPropertyValuesHolderオブジェクトのcalculateValue関数を通じて、入力した時点から属性の値を取得した後、彼は多くの処理を手伝います.targetオブジェクトprotertyNameプロパティのsetメソッドを呼び出します.ObjectAnimatorクラスの大まかな実装手順を理解するために、次は前の記事AndroidプロパティアニメーションValueAnimatorソースコードの簡単な分析に基づいて、ObjectAnimatorソースコードの簡単な実装を見続けます.
ObjectAnimatorの簡単な実用性は、以下の通りです.
        ObjectAnimator objectAlpha = ObjectAnimator.ofFloat(this, "alpha", 1f, 0f, 1f);
        objectAlpha.setDuration(3000);
        objectAlpha.start();

ObjectAnimatorのソースコードの簡単な実現を分析するために、やはり私たちの使用過程によって3つの部分に分けて見ます.ObjectAnimator.ofFloat(this, “alpha”, 1f, 0f, 1f);ここで何をしましたか.2. objectAlpha.start();中には何が入っていますか.3.アニメーション中にPropertyValuesHolderオブジェクトのcalculateValue関数の後に何をしましたか.
第1部ObjectAnimator.ofFloat(this, “alpha”, 1f, 0f, 1f)
    public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
        ObjectAnimator anim = new ObjectAnimator(target, propertyName);
        anim.setFloatValues(values);
        return anim;
    }

3行のコードについて、まず2行目を見て、Android属性アニメーションValueAnimatorソースコードの簡単な分析の中でValueAnimatorを分析します.ofInt()の場合、プロセスは同じです.それは次の行のコードが何をしているかを見るだけです.
    private ObjectAnimator(Object target, String propertyName) {
        setTarget(target);
        setPropertyName(propertyName);
    }

targetと属性の名前(propertyName)を設定します.targetはnullではなく、targetは属性名に対応するオブジェクトです.targetに対応するプロパティ名のget関数とset関数は後で呼び出されます.
はい、第1部は終わったようですが、ValueAnimatorとの違いはtargetとpropertyNameが多くなったことです.他の過程はValueAnimatorの分析ですofInt()の場合、プロセスは同じです.
第2部objectAlpha.start();中身は何をしたんだ?
    @Override
    public void start() {
        // See if any of the current active/pending animators need to be canceled
        AnimationHandler handler = sAnimationHandler.get();
        if (handler != null) {
            int numAnims = handler.mAnimations.size();
            for (int i = numAnims - 1; i >= 0; i--) {
                if (handler.mAnimations.get(i) instanceof ObjectAnimator) {
                    ObjectAnimator anim = (ObjectAnimator) handler.mAnimations.get(i);
                    if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
                        anim.cancel();
                    }
                }
            }
            numAnims = handler.mPendingAnimations.size();
            for (int i = numAnims - 1; i >= 0; i--) {
                if (handler.mPendingAnimations.get(i) instanceof ObjectAnimator) {
                    ObjectAnimator anim = (ObjectAnimator) handler.mPendingAnimations.get(i);
                    if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
                        anim.cancel();
                    }
                }
            }
            numAnims = handler.mDelayedAnims.size();
            for (int i = numAnims - 1; i >= 0; i--) {
                if (handler.mDelayedAnims.get(i) instanceof ObjectAnimator) {
                    ObjectAnimator anim = (ObjectAnimator) handler.mDelayedAnims.get(i);
                    if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
                        anim.cancel();
                    }
                }
            }
        }
        if (DBG) {
            Log.d(LOG_TAG, "Anim target, duration: " + getTarget() + ", " + getDuration());
            for (int i = 0; i < mValues.length; ++i) {
                PropertyValuesHolder pvh = mValues[i];
                Log.d(LOG_TAG, " Values[" + i + "]: " +
                    pvh.getPropertyName() + ", " + pvh.mKeyframes.getValue(0) + ", " +
                    pvh.mKeyframes.getValue(1));
            }
        }
        super.start();
    }

記事があるstart()のプロセス分析では、4行目のhandler=sAnimationHandlerを知っています.get();得られたhandlerにはリストがたくさんあります.何のpendingアニメーションのリストですか.何のdelayアニメーションのリストですか.何のreadアニメーションのリストですか.7-14行、起動するObjectAnimatorがmAnimationsのリストに存在する場合は、このアニメーションをキャンセルします.15-23行、起動するObjectAnimatorがmPendingAnimationsのリストに存在する場合は、このアニメーションをキャンセルします.24-32行、起動するObjectAnimatorがmDelayedAnimsのリストに存在する場合は、このアニメーションをキャンセルします.34-42行、DBGはこれで構いません.43行、superのstart()関数を呼び出しました.ValueAnimatorです.start().前の文章Android属性アニメーションValueAnimatorソースコードはValueAnimatorを簡単に分析した.start()分析は同じです.
はい、第2部も終わりました.普通にアニメーションを起動して、前にこのアニメーションが存在したらキャンセルします.特に何も入っていないようです.
第3部アニメーションの過程の中でPropertyValuesHolderオブジェクトのcalculateValue関数の後でどんな事をしました.
Android属性アニメーションValueAnimatorのソースコードの簡単な分析の基礎があって、アニメーションの放送の過程の中でValueAnimator類の中のanimateValue()関数まで歩くことを知っています.ObjectAnimatorを解析するときはObjectAnimatorのanimateValue()関数を見なければなりません.何も言うことはありません.ObjectAnimatorクラスのanimateValue()関数のソースコードは次のとおりです.
    @CallSuper
    @Override
    void animateValue(float fraction) {
        final Object target = getTarget();
        if (mTarget != null && target == null) {
            // We lost the target reference, cancel and clean up.
            cancel();
            return;
        }

        super.animateValue(fraction);
        int numValues = mValues.length;
        for (int i = 0; i < numValues; ++i) {
            mValues[i].setAnimatedValue(target);
        }
    }

5-9行、私たちが前にtargetのオブジェクトを設定したとき、このオブジェクトは外で解放されてやっとこのifに入って、このアニメーションcancelを落として、これはよく理解してtargetはすべてありません.このアニメも意味がない.ここでは弱いアプリケーションを使用していますが、メモリの漏洩を避けるためです.11行、superのanimaterValue関数を呼び出し、ValueAnimatorクラスのanimaterValue関数に直接入りました.Android属性アニメーションValueAnimatorソースコードを簡単に分析した.14行、mValue[i].setAnimatedValue(target); ObjectAnimatorアニメーションのポイントがやってきました.Android属性アニメーションValueAnimatorソースコードの簡単な分析mValuesは、PropertyValuesHolderのオブジェクトまたはそのサブクラスオブジェクトであり、PropertyValuesHolderクラスのsetAnimatedValue関数に続く.
    void setAnimatedValue(Object target) {
        if (mProperty != null) {
            mProperty.set(target, getAnimatedValue());
        }
        if (mSetter != null) {
            try {
                mTmpValueArray[0] = getAnimatedValue();
                mSetter.invoke(target, mTmpValueArray);
            } catch (InvocationTargetException e) {
                Log.e("PropertyValuesHolder", e.toString());
            } catch (IllegalAccessException e) {
                Log.e("PropertyValuesHolder", e.toString());
            }
        }
    }

7行目、mTmpValueArray[0]=getAnimatedValue();得られたのはこのときのアニメーションの値です.8行目、このコードの下でやっていることは、私たちが前に設定したtargetとpropertyNameに基づいています.ターゲットオブジェクトに対応するpropertyNameのsetメソッドを削除し、対応するパラメータがアニメーション中の値になります.
ここにmSetterが出てきました.次に、これがどのように得られたのか、targetとpropertyNameに対応するsetメソッドをどのように関連付けたのかを簡単に見なければなりません.まずObjectAnimatorクラスのinitAnimation関数を見て、この関数の呼び出しタイミングAndroid属性アニメーションValueAnimatorソースコードの簡単な分析は
    @CallSuper
    @Override
    void initAnimation() {
        if (!mInitialized) {
            // mValueType may change due to setter/getter setup; do this before calling super.init(),
            // which uses mValueType to set up the default type evaluator.
            final Object target = getTarget();
            if (target != null) {
                final int numValues = mValues.length;
                for (int i = 0; i < numValues; ++i) {
                    mValues[i].setupSetterAndGetter(target);
                }
            }
            super.initAnimation();
        }
    }

11行に直接ジャンプし、PropertyValuesHolderクラスのsetupSetterAndGetterメソッドを呼び出します.
    void setupSetterAndGetter(Object target) {
        mKeyframes.invalidateCache();
        if (mProperty != null) {
            // check to make sure that mProperty is on the class of target
            try {
                Object testValue = null;
                List<Keyframe> keyframes = mKeyframes.getKeyframes();
                int keyframeCount = keyframes == null ? 0 : keyframes.size();
                for (int i = 0; i < keyframeCount; i++) {
                    Keyframe kf = keyframes.get(i);
                    if (!kf.hasValue() || kf.valueWasSetOnStart()) {
                        if (testValue == null) {
                            testValue = convertBack(mProperty.get(target));
                        }
                        kf.setValue(testValue);
                        kf.setValueWasSetOnStart(true);
                    }
                }
                return;
            } catch (ClassCastException e) {
                Log.w("PropertyValuesHolder","No such property (" + mProperty.getName() +
                        ") on target object " + target + ". Trying reflection instead");
                mProperty = null;
            }
        }
        // We can't just say 'else' here because the catch statement sets mProperty to null.
        if (mProperty == null) {
            Class targetClass = target.getClass();
            if (mSetter == null) {
                setupSetter(targetClass);
            }
            List<Keyframe> keyframes = mKeyframes.getKeyframes();
            int keyframeCount = keyframes == null ? 0 : keyframes.size();
            for (int i = 0; i < keyframeCount; i++) {
                Keyframe kf = keyframes.get(i);
                if (!kf.hasValue() || kf.valueWasSetOnStart()) {
                    if (mGetter == null) {
                        setupGetter(targetClass);
                        if (mGetter == null) {
                            // Already logged the error - just return to avoid NPE
                            return;
                        }
                    }
                    try {
                        Object value = convertBack(mGetter.invoke(target));
                        kf.setValue(value);
                        kf.setValueWasSetOnStart(true);
                    } catch (InvocationTargetException e) {
                        Log.e("PropertyValuesHolder", e.toString());
                    } catch (IllegalAccessException e) {
                        Log.e("PropertyValuesHolder", e.toString());
                    }
                }
            }
        }
    }

直接29-31行にジャンプして、ここにmSetterが現れたことに注意してください.最初は空いているはずなのにsetupSetter(targetClass);方法.パラメータはtargetのclassです.
    void setupSetter(Class targetClass) {
        Class<?> propertyType = mConverter == null ? mValueType : mConverter.getTargetType();
        mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", propertyType);
    }

3行目はsetupSetterOrGetter関数を呼び出してmSetterオブジェクトを得て、パラメータの中にset文字のキーワードがあるのを見ました.
    private Method setupSetterOrGetter(Class targetClass, HashMap<Class, HashMap<String, Method>> propertyMapMap, String prefix, Class valueType) { Method setterOrGetter = null; synchronized(propertyMapMap) { // Have to lock property map prior to reading it, to guard against // another thread putting something in there after we've checked it // but before we've added an entry to it HashMap<String, Method> propertyMap = propertyMapMap.get(targetClass); boolean wasInMap = false; if (propertyMap != null) { wasInMap = propertyMap.containsKey(mPropertyName); if (wasInMap) { setterOrGetter = propertyMap.get(mPropertyName); } } if (!wasInMap) { setterOrGetter = getPropertyFunction(targetClass, prefix, valueType); if (propertyMap == null) { propertyMap = new HashMap<String, Method>(); propertyMapMap.put(targetClass, propertyMap); } propertyMap.put(mPropertyName, setterOrGetter);
            }
        }
        return setterOrGetter;
    }

直接9行にジャンプし、getPropertyFunctionメソッド
    private Method getPropertyFunction(Class targetClass, String prefix, Class valueType) {
        // TODO: faster implementation...
        Method returnVal = null;
        String methodName = getMethodName(prefix, mPropertyName);
        Class args[] = null;
        if (valueType == null) {
            try {
                returnVal = targetClass.getMethod(methodName, args);
            } catch (NoSuchMethodException e) {
                // Swallow the error, log it later
            }
        } else {
            args = new Class[1];
            Class typeVariants[];
            if (valueType.equals(Float.class)) {
                typeVariants = FLOAT_VARIANTS;
            } else if (valueType.equals(Integer.class)) {
                typeVariants = INTEGER_VARIANTS;
            } else if (valueType.equals(Double.class)) {
                typeVariants = DOUBLE_VARIANTS;
            } else {
                typeVariants = new Class[1];
                typeVariants[0] = valueType;
            }
            for (Class typeVariant : typeVariants) {
                args[0] = typeVariant;
                try {
                    returnVal = targetClass.getMethod(methodName, args);
                    if (mConverter == null) {
                        // change the value type to suit
                        mValueType = typeVariant;
                    }
                    return returnVal;
                } catch (NoSuchMethodException e) {
                    // Swallow the error and keep trying other variants
                }
            }
            // If we got here, then no appropriate function was found
        }

        if (returnVal == null) {
            Log.w("PropertyValuesHolder", "Method " +
                    getMethodName(prefix, mPropertyName) + "() with type " + valueType +
                    " not found on target class " + targetClass);
        }

        return returnVal;
    }

mPropertyNameがあるのを見て、実は彼は私たちのObjectAnimatorです.ofFloat(this,「alpha」,1 f,0 f,1 f)のときに渡されるalpha.4行目、returnVal=targetClass.getMethod(methodName, args); 推定されるのはsetAlphaの方法である.これでmSetterオブジェクトがどこで入手されたのかがわかり、具体的には中に入って見ません.
第3部の分析をまとめると、アニメーションの過程でアニメーションの変化の値を得た後、相応のsetXXXを呼び出す方法でこの値を設定します.ObjectAnimatorアニメーションを使用する場合は、必ず対応するset getメソッドを実現します.
流水帳は記入済みで、次はアニメイトセットで大まかな実現を見るつもりです.