Android数字价格变化的动画效果的简单实现

原理:使用ValueAnimator属性动画类实现,它通过值的改变手动设置对象的属性值来实现动画效果。直接贴代码:

public static void doNumberAnim(TextView tvPrice, float startNumber, float endNumber) {
    ValueAnimator animator = ValueAnimator.ofFloat(startNumber, endNumber);
    animator.setDuration(800);
    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            tvPrice.setText(animation.getAnimatedValue().toString());
        }
    });
    animator.start();
}

对于官网解释如下:

This class provides a simple timing engine for running animations which calculate animated values and set them on target objects.

There is a single timing pulse that all animations use. It runs in a custom handler to ensure that property changes happen on the UI thread.

By default, ValueAnimator uses non-linear time interpolation, via the AccelerateDecelerateInterpolator class, which accelerates into and decelerates out of an animation. This behavior can be changed by calling setInterpolator.

Animators can be created from either code or resource files. Here is an example of a ValueAnimator resource file:

ValueAnimator also supports the use of a combination of PropertyValuesHolder and Keyframe resource tags to create a multi-step animation. Note that you can specify explicit fractional values (from 0 to 1) for each keyframe to determine when, in the overall duration, the animation should arrive at that value. Alternatively, you can leave the fractions off and the keyframes will be equally distributed within the total duration:


此类提供了一个简单的计时引擎,用于运行动画,这些动画计算动画值并将其设置在目标对象上。

所有动画都使用单个定时脉冲。它在自定义处理程序中运行,以确保属性更改发生在 UI 线程上。

默认情况下,ValueAnimator 通过类使用非线性时间插值,该插值加速到动画中,从动画中减速。可以通过调用 来更改此行为。AccelerateDecelerateInterpolatorsetInterpolator

可以从代码或资源文件创建动画器。下面是 ValueAnimator 资源文件的示例:

ValueAnimator 还支持使用 and 资源标记的组合来创建多步骤动画。请注意,您可以为每个关键帧指定显式小数值(从 0 到 1),以确定动画在整个持续时间内何时应达到该值。或者,您可以关闭分数,关键帧将在总持续时间内均匀分布:PropertyValuesHolderKeyframe

总结

常数

static final int
INFINITE = -1

此值与属性一起使用以无限期地重复动画。setRepeatCount

static final int
RESTART = 1

当动画到达末尾并且为 INFINITE 或正值时,动画将从开头重新启动。repeatCount

static final int
REVERSE = 2

当动画到达末尾并且为无限值或正值时,动画在每次迭代时都会反转方向。repeatCount

公共构造函数

创建一个新的 ValueAnimator 对象。

公共方法

static boolean

返回系统范围的动画器当前是否已启用。

void
cancel()

取消动画。

@NonNull ValueAnimator
clone()
void
end()

结束动画。

float

返回当前动画分数,这是动画上最近帧更新中使用的经过/插值分数。

@NonNull Object

当只有一个属性被动画化时,由此计算的最新值。ValueAnimator

@Nullable Object
getAnimatedValue(@NonNull String propertyName)

由此计算的最新值为 。ValueAnimatorpropertyName

long

获取动画在时间中的当前位置,该位置等于当前时间减去动画开始的时间。

long

获取动画的长度。

static long

动画的每一帧之间的时间量(以毫秒为单位)。

@Nullable Interpolator

返回此值动画器使用的计时插值器。

@NonNull String

返回此动画器的名称以进行调试。

int

定义动画应重复的次数。

int

定义此动画到达末尾时应执行的操作。

long

调用延迟启动动画的时间量(以毫秒为单位)。start

long

获取动画的总持续时间,包括动画序列、开始延迟和重复。

@NonNull PropertyValuesHolder[]

返回此值动画器在其间进行动画处理的值。

boolean

返回此动画器当前是否正在运行(已启动并已超过任何初始启动延迟周期且尚未结束)。

boolean

返回此动画器是否已启动和尚未结束。

static @NonNull ValueAnimator
ofArgb(@NonNull int[] values)

构造并返回一个在颜色值之间进行动画处理的 ValueAnimator。

static @NonNull ValueAnimator
ofFloat(@NonNull float[] values)

构造并返回一个在浮点值之间进行动画处理的 ValueAnimator。

static @NonNull ValueAnimator
ofInt(@NonNull int[] values)

构造并返回一个在 int 值之间进行动画处理的 ValueAnimator。

static @NonNull ValueAnimator
ofObject(@NonNull TypeEvaluator evaluator, @NonNull Object[] values)

构造并返回一个在对象值之间进行动画处理的 ValueAnimator。

static @NonNull ValueAnimator
ofPropertyValuesHolder(@NonNull PropertyValuesHolder[] values)

构造并返回一个 ValueAnimator,该动画器在 PropertyValuesHolder 对象中指定的值之间进行动画处理。

void
pause()

暂停正在运行的动画。

void
resume()

恢复暂停的动画,使动画师在暂停时从中断的位置继续。

void

反向播放 ValueAnimator。

void
setCurrentFraction(float fraction)

将动画的位置设置为指定的分数。

void
setCurrentPlayTime(long playTime)

将动画的位置设置为指定的时间点。

@NonNull ValueAnimator
setDuration(long duration)

设置动画的长度。

void

计算此动画的动画值时要使用的类型赋值器。

void
setFloatValues(@NonNull float[] values)

设置将在浮点值之间进行动画处理。

static void
setFrameDelay(long frameDelay)

动画的每一帧之间的时间量(以毫秒为单位)。

void
setIntValues(@NonNull int[] values)

设置将在两者之间进行动画处理的 int 值。

void

用于计算此动画的经过分数的插值器。

void
setNameForTrace(@NonNull String animationName)

设置要在系统跟踪中显示的动画的名称。

void
setObjectValues(@NonNull Object[] values)

设置要对此动画进行动画处理的值。

void
setRepeatCount(int value)

设置动画应重复的次数。

void

定义此动画到达末尾时应执行的操作。

void
setStartDelay(long startDelay)

调用延迟启动动画的时间量(以毫秒为单位)。start

void
setValues(@NonNull PropertyValuesHolder[] values)

设置每个属性之间的值。

void
start()

启动此动画。

@NonNull String

继承的常量

来自androidx.core.animation.Animator

继承的方法

来自androidx.core.animation.Animator

常数

无限INFINITE

public static final int INFINITE = -1

此值与属性一起使用以无限期地重复动画。setRepeatCount

重新启动RESTART

public static final int RESTART = 1

当动画到达末尾并且为 INFINITE 或正值时,动画将从开头重新启动。repeatCount

反向REVERSE

public static final int REVERSE = 2

当动画到达末尾并且为无限值或正值时,动画在每次迭代时都会反转方向。repeatCount

公共构造函数

ValueAnimator

public ValueAnimator()

创建一个新的 ValueAnimator 对象。此默认构造函数主要用于内部;采用参数的工厂方法通常更有用。

公共方法

areAnimatorsEnabled

public static boolean areAnimatorsEnabled()

返回系统范围的动画器当前是否已启用。默认情况下,所有动画器都处于启用状态。如果用户将开发人员选项设置为将动画器持续时间比例设置为 0,或者启用电池保存模式(禁用所有动画),则这可能会更改。

开发人员通常不需要调用此方法,但如果应用希望在禁用动画器时显示不同的体验,则可以将此返回值用作要提供的体验的决策程序。

返回
boolean

布尔值 当前是否启用动画器。默认值为 。true

取消

public void cancel()

取消动画。与 不同,会导致动画停止在其轨道上,向其侦听器发送 ,然后发送消息。endcancel()onAnimationCancelonAnimationEnd

必须在运行动画的线程上调用此方法。

克隆

public @NonNull ValueAnimator clone()

结束

public void end()

结束动画。这会导致动画分配要进行动画处理的属性的结束值,然后在其侦听器上调用该方法。onAnimationEnd

必须在运行动画的线程上调用此方法。

getAnimatedFraction

public float getAnimatedFraction()

返回当前动画分数,这是动画上最近帧更新中使用的经过/插值分数。

返回
float

动画的经过/插值部分。

getAnimatedValue

public @NonNull Object getAnimatedValue()

当只有一个属性被动画化时,由此计算的最新值。此值仅在动画运行时是合理的。此只读属性的主要用途是在计算值后立即从调用 期间检索值,该值在每个动画帧期间调用。ValueAnimatorValueAnimatoronAnimationUpdate

返回
@NonNull Object

animatedValue 最近由此值为要进行动画处理的单个属性计算的值。如果有多个属性正在进行动画处理(由构造函数中的多个 PropertyValuesHolder 对象指定),则此函数返回其中第一个对象的动画值。ValueAnimator

getAnimatedValue

public @Nullable Object getAnimatedValue(@NonNull String propertyName)

由此计算的最新值为 。此只读属性的主要用途是在计算值后立即从调用 期间检索值,该值在每个动画帧期间调用。ValueAnimatorpropertyNameValueAnimatoronAnimationUpdate

返回
@Nullable Object

animatedValue 最近由 .ValueAnimator

getCurrentPlayTime

public long getCurrentPlayTime()

获取动画在时间中的当前位置,该位置等于当前时间减去动画开始的时间。尚未启动的动画将返回零值,除非动画已通过 或 设置了播放时间,在这种情况下,它将返回设置的时间。setCurrentPlayTimesetCurrentFraction

返回
long

动画时间中的当前位置。

getDuration

获取动画的长度。默认持续时间为 300 毫秒。

返回
long

动画的长度(以毫秒为单位)。

getFrameDelay

public static long getFrameDelay()

动画的每一帧之间的时间量(以毫秒为单位)。这是动画将尝试遵守的请求时间,但帧之间的实际延迟可能会有所不同,具体取决于系统负载和功能。这是一个静态函数,因为相同的延迟将应用于所有动画,因为它们都是从单个计时循环运行的。当动画系统使用外部计时源(如显示刷新率 (vsync))来控制动画时,可以忽略帧延迟。请注意,应从调用的同一线程调用此方法,以便检查该动画的帧延迟。如果调用线程没有 Looper,则会引发运行时异常。start

返回
long

帧之间的请求时间(以毫秒为单位)

getInterpolator

public @Nullable Interpolator getInterpolator()

返回此值动画器使用的计时插值器。

返回
@Nullable Interpolator

此值动画器的计时插值器。

getNameForTrace

public @NonNull String getNameForTrace()

返回此动画器的名称以进行调试。

getRepeatCount

<span style="color:var(--devsite-code-color)">public int <a data-cke-saved-href="https://developer.android.google.cn/reference/androidx/core/animation/ValueAnimator#getRepeatCount()" href="https://developer.android.google.cn/reference/androidx/core/animation/ValueAnimator#getRepeatCount()">getRepeatCount</a>()</span>

定义动画应重复的次数。默认值为 0。

返回
int

动画应重复的次数,或INFINITE

getRepeatMode

@ValueAnimator.RepeatMode
public int getRepeatMode()

定义此动画到达末尾时应执行的操作。

返回
int

REVERSERESTART

getStartDelay

public long getStartDelay()

调用延迟启动动画的时间量(以毫秒为单位)。start

返回
long

延迟运行动画的毫秒数

getTotalDuration

public long getTotalDuration()

获取动画的总持续时间,包括动画序列、开始延迟和重复。

当动画无限重复时,或者当任何子动画师重复时(通过 } 到 ),总持续时间将为 。否则,总持续时间是开始延迟和动画运行时间的总和(即一次迭代的持续时间乘以迭代次数)。setRepeatCountINFINITEDURATION_INFINITE

返回
long

动画完成所需的总时间(从调用的时间开始)。 如果动画或任何子动画无限重复,将返回。startDURATION_INFINITE

getValues

public @NonNull PropertyValuesHolder[] getValues()

返回此值动画器在其间进行动画处理的值。这些值存储在 PropertyValuesHolder 对象中,即使 ValueAnimator 是使用简单的值对象列表创建的。

返回
@NonNull PropertyValuesHolder[]

PropertyValuesHolder[] 一个 PropertyValuesHolder 对象的数组,这些对象保存定义动画的每个属性的值。

isRunning

public boolean isRunning()

返回此动画器当前是否正在运行(已启动并已超过任何初始启动延迟周期且尚未结束)。

返回
boolean

动画器是否正在运行。

isStarted

public boolean isStarted()

返回此动画器是否已启动和尚未结束。对于可重用的动画师(除了 生成的单次动画师之外,大多数动画师都是),此状态是 的超集,因为非零的动画师将在延迟阶段返回 true,而只有在延迟阶段完成后才会返回 true。不可重用的动画器在启动后将始终返回 true,因为它们无法返回到非启动状态。createCircularReveal()isRunningstartDelayisStartedisRunning

返回
boolean

动画器是否已启动和尚未结束。

ofArgb

public static @NonNull ValueAnimator ofArgb(@NonNull int[] values)

构造并返回一个在颜色值之间进行动画处理的 ValueAnimator。单个值意味着该值是要动画到的值。但是,这在 ValueAnimator 对象中通常没有用处,因为对象无法确定动画的起始值(与 ObjectAnimator 不同,ObjectAnimator 可以从要设置动画的目标对象和属性派生该值)。因此,通常应有两个或多个值。

参数
@NonNull int[] values

动画将随时间推移在其之间设置动画效果的一组值。

返回
@NonNull ValueAnimator

一个 ValueAnimator 对象,该对象设置为在给定值之间进行动画处理。

浮点数

public static @NonNull ValueAnimator ofFloat(@NonNull float[] values)

构造并返回一个在浮点值之间进行动画处理的 ValueAnimator。单个值意味着该值是要动画到的值。但是,这在 ValueAnimator 对象中通常没有用处,因为对象无法确定动画的起始值(与 ObjectAnimator 不同,ObjectAnimator 可以从要设置动画的目标对象和属性派生该值)。因此,通常应有两个或多个值。

参数
@NonNull float[] values

动画将随时间推移在其之间设置动画效果的一组值。

返回
@NonNull ValueAnimator

一个 ValueAnimator 对象,该对象设置为在给定值之间进行动画处理。

ofInt

public static @NonNull ValueAnimator ofInt(@NonNull int[] values)

构造并返回一个在 int 值之间进行动画处理的 ValueAnimator。单个值意味着该值是要动画到的值。但是,这在 ValueAnimator 对象中通常没有用处,因为对象无法确定动画的起始值(与 ObjectAnimator 不同,ObjectAnimator 可以从要设置动画的目标对象和属性派生该值)。因此,通常应有两个或多个值。

参数
@NonNull int[] values

动画将随时间推移在其之间设置动画效果的一组值。

返回
@NonNull ValueAnimator

一个 ValueAnimator 对象,该对象设置为在给定值之间进行动画处理。

对象

public static @NonNull ValueAnimator ofObject(@NonNull TypeEvaluator evaluator, @NonNull Object[] values)

构造并返回一个在对象值之间进行动画处理的 ValueAnimator。单个值意味着该值是要动画到的值。但是,这在 ValueAnimator 对象中通常没有用处,因为对象无法确定动画的起始值(与 ObjectAnimator 不同,ObjectAnimator 可以从要设置动画的目标对象和属性派生该值)。因此,通常应有两个或多个值。

注意:Object 值存储为对原始对象的引用,这意味着调用此方法后对这些对象的更改将影响动画器上的值。如果在调用此方法后对象将在外部发生突变,则调用方应改为传递这些对象的副本。

由于 ValueAnimator 不知道如何在任意对象之间进行动画处理,因此此工厂方法还采用 TypeEvaluator 对象,ValueAnimator 将使用该对象来执行该插值。

参数
@NonNull TypeEvaluator evaluator

将在每个动画帧上调用的类型计算器,以在对象值之间提供必要的插值以派生动画值。

@NonNull Object[] values

动画将随时间推移在其之间设置动画效果的一组值。

返回
@NonNull ValueAnimator

一个 ValueAnimator 对象,该对象设置为在给定值之间进行动画处理。

OfPropertyValuesHolder

public static @NonNull ValueAnimator ofPropertyValuesHolder(@NonNull PropertyValuesHolder[] values)

构造并返回一个 ValueAnimator,该动画器在 PropertyValuesHolder 对象中指定的值之间进行动画处理。

参数
@NonNull PropertyValuesHolder[] values

一组 PropertyValuesHolder 对象,其值将随时间推移进行动画处理。

返回
@NonNull ValueAnimator

一个 ValueAnimator 对象,该对象设置为在给定值之间进行动画处理。

暂停

public void pause()

暂停正在运行的动画。此方法只应在启动动画的同一线程上调用。如果动画尚未或已结束,则忽略调用。暂停的动画可以通过调用 来恢复。 startedresume

恢复

public void resume()

恢复暂停的动画,使动画师在暂停时从中断的位置继续。此方法只应在启动动画的同一线程上调用。对当前未暂停的动画器进行 resume() 的调用将被忽略。

反向

public void setCurrentFraction(float fraction)

反向播放 ValueAnimator。如果动画已在运行,它将自行停止并从调用 reverse 时达到的点向后播放。如果动画当前未运行,则它将从末尾开始并向后播放。此行为仅针对当前动画设置;动画的未来播放将使用向前播放的默认行为。

设置电流分数

public void setCurrentFraction(float fraction)

将动画的位置设置为指定的分数。此分数应介于 0 和动画的总分数之间,包括任何重复。也就是说,分数 0 会将动画定位在重复一次的反转动画器的开头,值 1 定位在末尾,值 2 定位在末尾。如果动画尚未启动,则在设置为此分数后,它将不会向前前进;它只需将分数设置为此值,并根据该分数执行任何适当的操作。如果动画已经在运行,则 setCurrentFraction() 会将当前分数设置为此值,并从该点继续播放。 由于更改分数,不会调用事件;这些事件仅在动画运行时处理。androidx.core.animation.Animator.AnimatorListener

参数
float fraction

动画前进或倒带到的分数。动画师的最大分数范围之外的值将被钳制到正确的范围。

设置当前播放时间

public void setCurrentPlayTime(long playTime)

将动画的位置设置为指定的时间点。此时间应介于 0 和动画的总持续时间(包括任何重复)之间。如果动画尚未启动,则设置为此时后将不再前进;它只会将时间设置为此值,并根据该时间执行任何适当的操作。如果动画已在运行,则 setCurrentPlayTime() 会将当前播放时间设置为此值,并从该点继续播放。

参数
long playTime

动画前进或倒带的时间(以毫秒为单位)。

设置持续时间

public @NonNull ValueAnimator setDuration(long duration)

设置动画的长度。默认持续时间为 300 毫秒。

参数
long duration

动画的长度(以毫秒为单位)。此值不能为负数。

返回
@NonNull ValueAnimator

ValueAnimator 使用 setDuration() 调用的对象。通过此返回值,可以更轻松地将构造语句组合在一起,然后设置持续时间,如 中所示。ValueAnimator.ofInt(0, 10).setDuration(500).start()

setEvaluator

public void setEvaluator(@NonNull TypeEvaluator value)

计算此动画的动画值时要使用的类型赋值器。系统将根据构造函数中的类型和自动分配浮点数或整数赋值器。但是,如果这些值不是这些基元类型之一,或者需要不同的计算(例如表示颜色的 int 值所必需的),则需要分配自定义计算器。例如,在对颜色值运行动画时,应使用 来获取正确的 RGB 颜色插值。startValueendValueArgbEvaluator

如果此值动画器之间只有一组值进行动画处理,则此赋值器将用于该集。如果有几组值正在进行动画处理,例如在 ValueAnimator 上设置了 PropertyValuesHolder 对象,则赋值器仅分配给第一个 PropertyValuesHolder 对象。

参数
@NonNull TypeEvaluator value

此动画要使用的赋值器

设置浮点值

public void setFloatValues(@NonNull float[] values)

设置将在浮点值之间进行动画处理。单个值意味着该值是要动画到的值。但是,这在 ValueAnimator 对象中通常没有用处,因为对象无法确定动画的起始值(与 ObjectAnimator 不同,ObjectAnimator 可以从要设置动画的目标对象和属性派生该值)。因此,通常应有两个或多个值。

如果已经通过多个 PropertyValuesHolder 对象为此 ValueAnimator 定义了多组值,则此方法将为其中第一个对象设置值。

参数
@NonNull float[] values

动画将随时间推移在其之间设置动画效果的一组值。

设置帧延迟

public static void setFrameDelay(long frameDelay)

动画的每一帧之间的时间量(以毫秒为单位)。这是动画将尝试遵守的请求时间,但帧之间的实际延迟可能会有所不同,具体取决于系统负载和功能。这是一个静态函数,因为相同的延迟将应用于所有动画,因为它们都是从单个计时循环运行的。当动画系统使用外部计时源(如显示刷新率 (vsync))来控制动画时,可以忽略帧延迟。请注意,应从调用的同一线程调用此方法,以使新的帧延迟对该动画生效。如果调用线程没有 Looper,则会引发运行时异常。start

参数
long frameDelay

帧之间的请求时间(以毫秒为单位)

设置整数值

public void setIntValues(@NonNull int[] values)

设置将在两者之间进行动画处理的 int 值。单个值意味着该值是要动画到的值。但是,这在 ValueAnimator 对象中通常没有用处,因为对象无法确定动画的起始值(与 ObjectAnimator 不同,ObjectAnimator 可以从要设置动画的目标对象和属性派生该值)。因此,通常应有两个或多个值。

如果已经通过多个 PropertyValuesHolder 对象为此 ValueAnimator 定义了多组值,则此方法将为其中第一个对象设置值。

参数
@NonNull int[] values

动画将随时间推移在其之间设置动画效果的一组值。

设置插值器

public void setInterpolator(@Nullable Interpolator value)

用于计算此动画的经过分数的插值器。插值器确定动画是以线性运动还是非线性运动(如加速和减速)运行。默认值为AccelerateDecelerateInterpolator

参数
@Nullable Interpolator value

此动画要使用的插值器。值 将导致线性插值。null

设置名称跟踪

public void setNameForTrace(@NonNull String animationName)

设置要在系统跟踪中显示的动画的名称。这使特定动画在系统跟踪中可识别。

参数
@NonNull String animationName

使实例在系统跟踪中可识别的动画的名称

设置对象值

public void setObjectValues(@NonNull Object[] values)

设置要对此动画进行动画处理的值。单个值意味着该值是要动画到的值。但是,这在 ValueAnimator 对象中通常没有用处,因为对象无法确定动画的起始值(与 ObjectAnimator 不同,ObjectAnimator 可以从要设置动画的目标对象和属性派生该值)。因此,通常应有两个或多个值。

注意:Object 值存储为对原始对象的引用,这意味着调用此方法后对这些对象的更改将影响动画器上的值。如果在调用此方法后对象将在外部发生突变,则调用方应改为传递这些对象的副本。

如果已经通过多个 PropertyValuesHolder 对象为此 ValueAnimator 定义了多组值,则此方法将为其中第一个对象设置值。

在 ValueAnimator 上应该设置一个 TypeEvaluator,它知道如何在这些值对象之间进行插值。ValueAnimator 只知道如何在其他 setValues() 方法中指定的基元类型之间进行插值。

参数
@NonNull Object[] values

要在其间进行动画处理的值集。

setRepeatCount

public void setRepeatCount(int value)

设置动画应重复的次数。如果重复计数为 0,则永远不会重复动画。如果重复计数大于 0 或 ,则将考虑重复模式。默认情况下,重复计数为 0。INFINITE

参数
int value

动画应重复的次数

设置重复模式

public void setRepeatMode(@ValueAnimator.RepeatMode int value)

定义此动画到达末尾时应执行的操作。仅当重复计数大于 0 或 时,才应用此设置。默认值为 。INFINITERESTART

参数
@ValueAnimator.RepeatMode int value

RESTARTREVERSE

设置启动延迟

public void setStartDelay(long startDelay)

调用延迟启动动画的时间量(以毫秒为单位)。请注意,启动延迟应始终为非负数。任何负启动延迟都将在 N 及以上时被钳制为 0。start

参数
long startDelay

延迟量(以毫秒为单位)

设置值

public void setValues(@NonNull PropertyValuesHolder[] values)

设置每个属性之间的值。此函数由采用值列表的 ValueAnimator 的构造函数在内部调用。但是,可以在没有值的情况下构造 ValueAnimator,并且可以调用此方法来手动设置值。

参数
@NonNull PropertyValuesHolder[] values

每个属性之间的值集。

开始

public void start()

启动此动画。如果动画具有非零 startDelay,则动画将在该延迟过后开始运行。非延迟动画将立即设置其初始值,然后调用此动画器的任何侦听器。onAnimationStart

通过调用此方法启动的动画将在调用此方法的线程上运行。此线程上应该有一个 Looper(如果不是这种情况,将引发运行时异常)。此外,如果动画将对视图层次结构中对象的属性进行动画处理,则调用线程应该是该视图层次结构的 UI 线程。

到字符串

public @NonNull String toString()

猜你喜欢

转载自blog.csdn.net/u010231454/article/details/132191265