gpt4 book ai didi

java - Android:如何让后续例程等待ObjectAnimator?

转载 作者:行者123 更新时间:2023-12-01 09:44:39 24 4
gpt4 key购买 nike

有关此问题的更详细版本,请参阅 How to make MediaPlayer wait for ObjectAnimator (and generally control Android UI sequence)?谢谢。 - 代码读取

我正在尝试构建一个按以下顺序启动的 Android 应用程序:

  1. 在(TextView)中缩放其主视图;
  2. View 完全放大后,发出声音;
  3. 声音发出后,执行主程序。

我首先尝试在程序中的声音代码( ObjectAnimator )之前简单地输入缩放代码( MediaPlayer )。但代码并不按出现顺序运行。 MediaPlayer 与 ObjectAnimator 并行播放,无论代码顺序如何。 为什么会发生这种情况以及如何预防?

为了解决这个问题,我应用了各种计时和锁定方法来让 MediaPlayer 等待 ObjectAnimator。我在这里和其他地方搜索了很多解决方案。到目前为止我发现的唯一的有:

  1. Handler().postDelayed 运行 MediaPlayer,并且
  2. AnimatorListenerAdapter() 在动画完成时启动 MediaPlayer。

这两种方法都有效,但是(1)并不精确,因为我必须对等待时间进行硬编码(并手动管理该值),并且(2)并不通用,主应用程序代码仍然在之前启动媒体播放器完成。许多答案建议使用 AsyncTask控制 Android UI 序列,但 AsyncTask 只适用于两个任务,并在后台线程中等待其中一个任务,这对于两个以上阶段的序列确实不合适。

Android - wait for animation to finish before continuing?也在这个问题上。接受的答案是 AnimatorListenerAdaptor(),但是 OP 询问,现在可以使用,但是如果我希望在动画完成后运行更多行代码,我是否必须基本上将我的整个代码放在onAnimationEnd 方法? 我同意 - 这似乎不合理。

通过进一步的测试,我的问题似乎可以简化为:如何让后续例程等待 ObjectAnimator?

下面的代码说明了后一个问题。 boolean waitLock 设置为 true。然后启动 ObjectAnimator。然后 while() 循环等待 onAnimationEnd() 将 waitLock 设置为 false。 ObjectAnimator 永远不会完成,waitLock 永远不会设置为 false,并且 while() 无限循环。为什么?

但是,如果 waitLock 最初设置为 false,则 ObjectAnimator 会完成并且应用程序会正常退出。为什么 ObjectAnimator 在这种情况下完成,而在另一种情况下却没有?

public class MainActivity extends Activity {
private boolean waitLock;
View mainView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mainView = findViewById(R.id.mainView);
waitLock = true;
ObjectAnimator scalexAnim = ObjectAnimator.ofFloat(mainView, "scaleX", 0f, 1f);
scalexAnim.setDuration(1500);
scalexAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animator) {
Log.w("sA", "onAnimationStart reached");
super.onAnimationStart(animator);
}
@Override
public void onAnimationEnd(Animator animation) {
Log.w("sA", "onAnimationEnd reached");
waitLock = false;
super.onAnimationEnd(animation);
}
});

Log.w("zI", "starting.."); zoomIn.start(); Log.w("zI", "started");

while (waitLock == true) {
SystemClock.sleep(1000);
Log.w("while(waitLock)", "sleep 1000ms");
}
Log.w("onCreate", "exit");
}

以下是当 waitLock 设置为 true 时相应的 logcat 输出:

07-02 13:34:14.850    9233-9233/com.code_read.sequentialcontroltest W/sA﹕ starting..
07-02 13:34:14.860 9233-9233/com.code_read.sequentialcontroltest W/sA﹕ onAnimationStart reached
07-02 13:34:14.860 9233-9233/com.code_read.sequentialcontroltest W/sA﹕ started
07-02 13:34:15.861 9233-9233/com.code_read.sequentialcontroltest W/while(waitLock)﹕ sleep 1000ms
07-02 13:34:16.862 9233-9233/com.code_read.sequentialcontroltest W/while(waitLock)﹕ sleep 1000ms
07-02 13:34:17.863 9233-9233/com.code_read.sequentialcontroltest W/while(waitLock)﹕ sleep 1000ms
07-02 13:34:18.864 9233-9233/com.code_read.sequentialcontroltest W/while(waitLock)﹕ sleep 1000ms

最佳答案

由于没有人回答这个问题,我将发布到目前为止我所发现的内容。然而,我认为这个问题仍然悬而未决。我当然不知道有关 Android 或 Java 的全部知识,我希望有更好的答案。

我的发现是:

  1. 一般来说,Android平台和原生库不是对同步编程友好。我发现了很多询问如何进行各种操作的问题(请参阅下面的链接)以受控顺序发生,并且没有非常令人满意的一般性这样做的方法;

  2. AsyncTask仅限于一对事件,并且不能在应用程序中重用;

  3. LooperHandler看起来很有希望一段时间,但显然 Looper 不会等待事件完成后再将其他事件出队;

  4. 看起来视觉例程比音频例程更容易同步,可能是因为 Android 的视觉库调用比音频更成熟。我发现许多评论表明同步 Android 音频例程存在问题,例如 MediaPlayerAudioTrack 。通常,在时机很重要的情况下,推荐的解决方案是使用编译的 C 代码和专用库;

  5. 锁定机制适合单独线程使用。我尝试使用它们作为控制单个线程内序列的方法,但总是因死锁而失败;

  6. 相反,只有 UI 线程中的代码才能改变屏幕或生成声音。这导致了一个悖论,我找到的唯一解决方案是要么严格控制UI线程的Looper队列,要么在音频和视觉函数调用之间编码交错;

  7. 我将代码放置在 Android“生命周期”的哪个位置没有什么区别。例如,将稍后执行的代码从 onCreate() 移至 onResume() 没有什么区别。

鉴于上述情况,下面是我对原始问题的编码解决方案:对 View 进行动画处理,然后发出声音,然后运行程序的其余部分。它依赖于回调,这会导致奇怪的反转: 源文件中较早的代码运行时间较晚。从易读性和可管理性的角度来看,我发现这令人不安。我也不喜欢这种普遍复杂的结构,但到目前为止,它的编码方式正如我所知道的那样简单。

(我怀疑这些同步问题被单核 CPU 掩盖了。现在大多数 Android 硬件都是多核的,操作系统可能需要迎头 catch 。我希望看到类似 @Synchronous 的东西 类将指定代码部分按其出现的顺序串行运行。或者可能是指定代码部分仅在特定核心上运行的方法。

许多相关问题中的一些链接:

<小时/>

我的编码解决方案。请注意执行顺序是如何颠倒的。首先运行rotateZoomin(),然后是MediaPlayer(),然后是playTracks():

MediaPlayer.OnCompletionListener smComplete = new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
startupMediaPlayer.stop();
startupMediaPlayer.reset();
startupMediaPlayer.release();
playTracks(); // This is third to execute (the rest of my application)
}
};

startupMediaPlayer = MediaPlayer.create(this, R.raw.doorbell2mp3);
startupMediaPlayer.setOnCompletionListener(smComplete);

ObjectAnimator rotateAnim = ObjectAnimator.ofFloat(mainView, "rotation", 1080f, 0f);
ObjectAnimator scalexAnim = ObjectAnimator.ofFloat(mainView, "scaleX", 0f, 1f);
ObjectAnimator scaleyAnim = ObjectAnimator.ofFloat(mainView, "scaleY", 0f, 1f);
AnimatorSet rotateZoomIn = new AnimatorSet();
rotateZoomIn.play(rotateAnim).with(scalexAnim);
rotateZoomIn.play(rotateAnim).with(scaleyAnim);
rotateZoomIn.setDuration(1500);
rotateZoomIn.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
startupMediaPlayer.start(); // This is second to execute
}
});
rotateZoomIn.start(); // This is first to execute

关于java - Android:如何让后续例程等待ObjectAnimator?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38164479/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com