我正在尝试制作一个项目,如果计步器在过去3秒钟内检测到任何脚步,就会播放一个简单的动画。但是,这导致动画只能在Looper线程上运行。我尝试过制作方法来在“ WalkActivity”类中运行动画,因为动画在那里可以正常运行,但是发现它们仅在“ onCreate”下运行,否则抛出Looper错误。我还尝试使用Handlers和AsyncTask进行变体,但是它们会引起其他问题(冻结View中的所有gif)。
import android.animation.ObjectAnimator;
import pl.droidsonroids.gif.GifImageView;
public class WalkScreenAnimThread extends Thread {
private int numSteps;
private GifImageView closeCharacterView;
private GifImageView farCharacterView;
ObjectAnimator closeOffScreen;
ObjectAnimator closeOnScreen;
ObjectAnimator farStepLeft;
ObjectAnimator farStepRight;
int prevSteps;
int currSteps;
int remainingTime = 3000;
int stage = 0;
int stepsCaught = 0; // keeps track of steps taken within a certain timeframe
int direction = 1;
public WalkScreenAnimThread(GifImageView y, GifImageView z, ObjectAnimator a, ObjectAnimator b, ObjectAnimator c, ObjectAnimator d)
{
closeCharacterView = y;
farCharacterView = z;
closeOffScreen = a;
closeOnScreen = b;
farStepLeft = c;
farStepRight = d;
}
public void setSteps(int steps)
{
numSteps = steps;
}
public void run()
{
prevSteps = numSteps;
currSteps = numSteps;
try
{
while(true) {
currSteps = prevSteps+1; // currently this is set to constantly increase since android emulator doesn't include a pedometer, normally this would be "currSteps = numSteps;"
if (prevSteps != currSteps)
stepsCaught += 1;
if (stage == 0) {
if (stepsCaught > 2) { // require a few steps to start so the animation isn't triggered by one accidental step
stage = 1;
direction = 1;
stepsCaught = 0;
closeOffScreen.start(); //foreground sprite moves off screen
Thread.sleep(4000);
}
else if (remainingTime <= 0)
stepsCaught = 0;
} else if (remainingTime % 1500 == 0) { // every second and a half, update the animation
if (remainingTime <= 0 && stepsCaught == 0) { // if three seconds have passed without any steps, take steps back to start
direction = -1;
farCharacterView.setRotationY(180);
} else if (stepsCaught > 0)
direction = 1;
if (direction > 0) { // do character fowards cycle https://cdn.discordapp.com/attachments/448275746147008534/499788306381406209/unknown.png
if (stage != 10) {
stage++;
if (stage >= 1 && stage <= 5) // background character has not reached the leftmost limit of the background, step left
farCharacterView.setRotationY(0);
farStepLeft.start();
else // background character has reached the leftmost limit of the background, step right
farCharacterView.setRotationY(180);
farStepRight.start();
} else { // background character has completed a full loop, rather than going off screen, turn character around
stage = 3;
}
} else // do character return to start cycle https://cdn.discordapp.com/attachments/448275746147008534/499788804807458817/unknown.png
{
if (stage >= 6 && stage <= 9) {
stage++;
farStepRight.start();
} else if (stage == 1) { // background character is off screen, return foreground character to screen
stage = 0;
closeOnScreen.start();
Thread.sleep(4000);
} else if (stage == 2)
stage = 10;
else if (stage == 10) {
stage = 1;
farStepRight.start();
} else if (stage >= 3) {
stage += 13 - stage * 2;
farStepRight.start();
}
}
}
if (remainingTime <= 0) // if 3 seconds have passed, set a new timer for 3 seconds
remainingTime = 3000;
prevSteps = currSteps;
Thread.sleep(100);
remainingTime -= 100;
}
}
catch (Exception e)
{
System.out.println(e);
}
}
}
此线程在此活动中运行:
import android.animation.ObjectAnimator;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
import android.os.Handler;
import pl.droidsonroids.gif.GifImageView;
public class WalkActivity extends AppCompatActivity implements SensorEventListener, StepListener {
private TextView textView;
private StepDetector simpleStepDetector;
private SensorManager sensorManager;
private Sensor accel;
private int numSteps;
private TextView stepCountView;
private WalkScreenAnimThread anim;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_walk);
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
accel = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
simpleStepDetector = new StepDetector();
simpleStepDetector.registerListener(this);
numSteps = 0;
stepCountView = findViewById(R.id.stepCountView);
stepCountView.setText("Steps taken: " + numSteps);
sensorManager.registerListener(WalkActivity.this, accel, SensorManager.SENSOR_DELAY_FASTEST);
GifImageView closeCharacterView = findViewById(R.id.closeCharacterView);
GifImageView farCharacterView = findViewById(R.id.farCharacterView);
ObjectAnimator a = ObjectAnimator.ofFloat(closeCharacterView, "translationX", 600f);
a.setDuration(3500);
ObjectAnimator b = ObjectAnimator.ofFloat(closeCharacterView, "translationX", -600f);
b.setDuration(3500);
ObjectAnimator c = ObjectAnimator.ofFloat(farCharacterView, "translationX", -124f);
c.setDuration(5);
ObjectAnimator d = ObjectAnimator.ofFloat(farCharacterView, "translationX", 124f);
d.setDuration(5);
anim = new WalkScreenAnimThread(closeCharacterView, farCharacterView, a, b, c, d);
anim.start();
// I have also tried variations of:
//
// new Handler().postDelayed(new Runnable() {
// @Override
// public void run() {
// runOnUiThread(anim);
// }
// }, 100);
//
// but it just freezes the gif after the delay and nothing else happens.
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
simpleStepDetector.updateAccel(
event.timestamp, event.values[0], event.values[1], event.values[2]);
}
}
@Override
public void step(long timeNs) {
numSteps++;
stepCountView.setText("Steps taken: " + numSteps);
anim.setSteps(numSteps);
}
}
我该怎么做才能使这项工作成功?
编辑: 这是错误日志(在不使用Handler时发生。请注意,在使用Handler时不会发生任何错误,但在屏幕上显示所有gif图像时,不会出现动画):
Capturing and displaying logcat messages from application. This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page.
D/skia: ---- fAsset->read(4096) returned 0
D/skia: --- SkAndroidCodec::NewFromStream returned null
D/MediaPlayer: setSubtitleAnchor in MediaPlayer
D/EGL_emulation: eglMakeCurrent: 0x9bab3880: ver 2 0 (tinfo 0x9bab58d0)
D/EGL_emulation: eglMakeCurrent: 0x9bab3880: ver 2 0 (tinfo 0x9bab58d0)
I/System.out: android.util.AndroidRuntimeException: Animators may only be run on Looper threads
D/EGL_emulation: eglMakeCurrent: 0x9bab3880: ver 2 0 (tinfo 0x9bab58d0)
D/EGL_emulation: eglMakeCurrent: 0x9bab3880: ver 2 0 (tinfo 0x9bab58d0)
D/EGL_emulation: eglMakeCurrent: 0x9bab3880: ver 2 0 (tinfo 0x9bab58d0)
D/OpenGLRenderer: endAllActiveAnimators on 0xa0274d80 (RippleDrawable) with handle 0x8eda0c00
D/EGL_emulation: eglMakeCurrent: 0x9bab3880: ver 2 0 (tinfo 0x9bab58d0)