Android和多线程中的动画



在尝试向ImageViews添加动画时,我似乎没有正确处理多线程,这给了我不正确的结果。

这是我调用动画>>的部分

startAnimation(gameController.getSecondImage()); // 1
...
startAnimation(gameController.getFirstImage()); // 2
...
startAnimation(gameController.getSecondImage()); // 3
...

这里的问题是,当我没有为startAnimation()函数创建单独的线程时,所有3个调用都同时发生,一切都变得一团糟。但现在它仍然没有完美地工作;第三个电话被打乱了。

public void startAnimation(final ImageView image1) {
    final ImageView image2 = cardViewMap.get(cardSwapMap.get(image1.getId()));
    Runnable animate = new Runnable() {
        @Override
        public void run() {
            animationController.animate(image1, image2);
        }
    };
    Thread animationThread = new Thread(animate);
    animationThread.start();
    try {                                         //
        animationThread.join();                   //
    } catch (InterruptedException e) {            // Added Later
        Log.d("ERROR", e.toString());             //
    }                                             //
}

我试着用join()做实验,但没有成功,现在它给出了更激进的结果。我认为使用join()将确保在开始新的调用之前执行以前对startAnimation()的调用。

EDIT:我已经跟踪了这个问题,问题是当主Looper运行时,我的startAnimation()函数被调用了。因此,它是在对函数进行了所有三次调用之后执行的。我需要确保startAnimation()在我进行调用时运行,并且在对同一函数的下一次调用发生之前执行。有什么办法确保这一点吗?

试着运行这段代码,它将帮助你理解解决方案,一旦你运行它,你就会更容易理解,

将布局名称设置为animation_st_activity.xml代码位于下方

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ImageView
    android:id="@+id/imageView3"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentTop="true"
    android:layout_centerHorizontal="true"
    android:src="@drawable/ic_launcher"
    android:visibility="invisible" />
<ImageView
    android:id="@+id/imageView2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignLeft="@+id/imageView3"
    android:layout_alignParentTop="true"
    android:src="@drawable/ic_launcher"
    android:visibility="invisible" />
<ImageView
    android:id="@+id/imageView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignLeft="@+id/imageView3"
    android:layout_alignParentTop="true"
    android:src="@drawable/ic_launcher"
    android:visibility="invisible" />
<Button
    android:id="@+id/button1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignLeft="@+id/imageView3"
    android:layout_alignParentBottom="true"
    android:text="click me" />
</RelativeLayout> 

现在,在make一个名为AnimationTest.java的活动中,代码如下所述。

package com.some.servewrtest;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.AnimationSet;
import android.view.animation.TranslateAnimation;
import android.widget.Button;
import android.widget.ImageView;
public class AnimationTest extends Activity implements OnClickListener {
private ImageView[] imageViews = new ImageView[3];
private Button button;

@Override
protected void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    setContentView(R.layout.animation_test_activity);
    initializeUI();
}
private void initializeUI() {
    // TODO Auto-generated method stub
    imageViews[0] = (ImageView) findViewById(R.id.imageView1);
    imageViews[1] = (ImageView) findViewById(R.id.imageView2);
    imageViews[2] = (ImageView) findViewById(R.id.imageView3);
    button = (Button)findViewById(R.id.button1);
    button.setOnClickListener(this);
}
@Override
public void onClick(View v) {
    // TODO Auto-generated method stub
    AnimationSet set = new AnimationSet(true);
    TranslateAnimation[] animations = new TranslateAnimation[3];
    int duration = 300;
    animations[0] = createCoins(0, duration*1, 0, 0, 0, 270); 
    animations[1] = createCoins(1, duration*2, 0, -100, 0, 270); 
    animations[2] = createCoins(2, duration*3, 0, 100, 0, 270);
    set.addAnimation(animations[0]);
    set.addAnimation(animations[1]);
    set.addAnimation(animations[2]);
    set.start();
}
private TranslateAnimation createCoins(int i, int duration, int fromXDelta, int toXDelta, int fromYDelta, int toYDelta) {
    // TODO Auto-generated method stub
    TranslateAnimation animation = new TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta);
    animation.setDuration(duration+1900);
    animation.setFillAfter(false);
    imageViews[i].setVisibility(ImageView.VISIBLE);
    imageViews[i].setAnimation(animation);
    imageViews[i].setVisibility(ImageView.INVISIBLE);
    return animation;
}
}

这个代码正在运行,你也可以测试它,这样你就可以自定义你想要使用它的方式

现在我们有一个工作的例子,我们将看看我们是如何做到这一点的,

首先,如果您尝试使用AnimationSet一遍又一遍地为同一图像设置动画,或者对同一图像制作不同的TranslateAnimation引用类型,但由于单个图像尝试同时位于两个不同的位置而无法工作。所以发生的情况是,只有第一个动画被看到,其他的被android忽略了,这是重复方法在android中不起作用的结果之一。

为了解决这个问题,我们可以做的是有尽可能多的视图,我们需要在每个视图上显示不同的动画,这次是一个单独的视图。它的工作原理是每个动画都与单个视图相关,并且它们可以同时工作。

我无法告诉你不要使用"多线程",但请记住,你正试图在UI线程上执行此操作,因此,如果你的应用程序中有许多动画,那么这些线程会让你的应用陷入困境,这是很有可能的。

如果你想在一个特定的动画结束时听一个事件,比如说动画,然后做这个

animation..setAnimationListener(new AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
                    // TODO Auto-generated method stub
                    Log.d(TAG, "Animation has started");
                }
                @Override
                public void onAnimationRepeat(Animation animation) {
                    // TODO Auto-generated method stub
                    Log.d(TAG, "Animation is repeat");
                }
                @Override
                public void onAnimationEnd(Animation animation) {
                    // TODO Auto-generated method stub
                    Log.d(TAG, "Animation is over");
                }
            });

通过这样做,您可以在上一个动画结束时开始一个新的动画:)

我尝试使用Android工具,但失败了。我回去用多线程修复了它。

尽管我更改了很多其他代码,但这是关于我的问题的重要代码之一——

package thakur.rahul.colourmemory.controller;
import thakur.rahul.colourmemory.view.Animation.DisplayNextView;
import thakur.rahul.colourmemory.view.Animation.Flip3dAnimation;
import android.app.Activity;
import android.view.animation.AccelerateInterpolator;
import android.widget.ImageView;
public class AnimationController implements Runnable {
    private Activity activity;
    private ImageView image1;
    private ImageView image2;
    private boolean isFirstImage = true;
    private volatile static int numThread = 1;
    private volatile static int threadAllowedToRun = 1;
    private int myThreadID;
    private volatile static Object myLock = new Object();
    private volatile static boolean hasNotSlept = true;
    public volatile static boolean fixForMatch = false;
    public AnimationController(Activity activity, ImageView image1, ImageView image2) {
        this.activity = activity;
        this.image1 = image1;
        this.image2 = image2;
        this.myThreadID = numThread++;
    }
    @Override
    public void run() {
        synchronized (myLock) {
            while (myThreadID != threadAllowedToRun)
                try {
                    myLock.wait();
                } catch (InterruptedException e) {
                } catch (Exception e) {
                }
            animate();
            if (myThreadID % 2 == 0)
                if (hasNotSlept || fixForMatch)
                    try {
                        Thread.sleep(1000);
                        hasNotSlept = !hasNotSlept;
                    } catch (InterruptedException e) {
                    }
                else
                    hasNotSlept = !hasNotSlept;
            myLock.notifyAll();
            threadAllowedToRun++;
        }
    }
    public void animate() {
        if (isFirstImage) {
            applyRotation(0, 90);
            isFirstImage = !isFirstImage;
        } else {
            applyRotation(0, -90);
            isFirstImage = !isFirstImage;
        }
    }
    private void applyRotation(float start, float end) {
        final float centerX = image1.getWidth() / 2.0f;
        final float centerY = image1.getHeight() / 2.0f;
        final Flip3dAnimation rotation = new Flip3dAnimation(start, end, centerX, centerY);
        rotation.setDuration(300);
        rotation.setFillAfter(true);
        rotation.setInterpolator(new AccelerateInterpolator());
        rotation.setAnimationListener(new DisplayNextView(isFirstImage, image1, image2));
        if (isFirstImage)
            activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    image1.startAnimation(rotation);
                }
            });
        else
            activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    image2.startAnimation(rotation);
                }
            });
    }
}

这是从主控制器调用的-

public void startAnimation(ImageView image1) {
    ImageView image2 = cardViewMap.get(cardSwapMap.get(image1.getId()));
    animationController = new AnimationController(activity, image1, image2);
    animationThread = new Thread(animationController);
    animationThread.start();
}

基本上,每次我需要运行动画时,我都会制作并标记线程,以便按顺序运行它。

如果您有更好的解决方案,请添加您的答案

相关内容

  • 没有找到相关文章

最新更新