Я написал приложение для Android, которое отображает пользовательский ImageView
, который периодически вращается, используя startAnimation(Animation)
. Приложение работает нормально, но если я создаю тест JUnit типа ActivityInstrumentationTestCase2
и тест вызывает getActivity()
, этот вызов getActivity()
никогда не возвращается до тех пор, пока приложение не перейдет в фоновый режим (например, нажата кнопка «Домой» устройства).
Спустя много времени и разочарований я обнаружил, что getActivity()
возвращается немедленно, если я закомментирую вызов startAnimation(Animation)
в своем пользовательском классе ImageView
. Но это противоречит цели моего пользовательского ImageView
, потому что мне нужно его анимировать.
Может ли кто-нибудь сказать мне, почему getActivity()
блокируется во время моего теста JUnit, но только при использовании startAnimation
? Заранее спасибо всем, кто может предложить обходной путь или сказать мне, что я делаю неправильно.
Примечание. Решение должно работать с Android API уровня не ниже 10.
Вот весь исходный код, необходимый для его запуска (поместите любое изображение PNG в res/drawable и назовите его the_image.png):
Activity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<com.example.rotatingimageviewapp.RotatingImageView
android:id="@+id/rotatingImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/the_image" />
</RelativeLayout>
Основная активность.java:
package com.example.rotatingimageviewapp;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends Activity {
private RotatingImageView rotatingImageView = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rotatingImageView = (RotatingImageView) findViewById(
R.id.rotatingImageView);
rotatingImageView.startRotation();
}
@Override
protected void onPause() {
super.onPause();
rotatingImageView.stopRotation();
}
@Override
protected void onResume() {
super.onResume();
rotatingImageView.startRotation();
}
}
RotatingImageView.java (пользовательский ImageView):
package com.example.rotatingimageviewapp;
import java.util.Timer;
import java.util.TimerTask;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
public class RotatingImageView extends ImageView {
private static final long ANIMATION_PERIOD_MS = 1000 / 24;
//The Handler that does the rotation animation
private final Handler handler = new Handler() {
private float currentAngle = 0f;
private final Object animLock = new Object();
private RotateAnimation anim = null;
@Override
public void handleMessage(Message msg) {
float nextAngle = 360 - msg.getData().getFloat("rotation");
synchronized (animLock) {
anim = new RotateAnimation(
currentAngle,
nextAngle,
Animation.RELATIVE_TO_SELF,
.5f,
Animation.RELATIVE_TO_SELF,
.5f);
anim.setDuration(ANIMATION_PERIOD_MS);
/**
* Commenting out the following line allows getActivity() to
* return immediately!
*/
startAnimation(anim);
}
currentAngle = nextAngle;
}
};
private float rotation = 0f;
private final Timer timer = new Timer(true);
private TimerTask timerTask = null;
public RotatingImageView(Context context) {
super(context);
}
public RotatingImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public RotatingImageView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
public void startRotation() {
stopRotation();
/**
* Set up the task that calculates the rotation value
* and tells the Handler to do the rotation
*/
timerTask = new TimerTask() {
@Override
public void run() {
//Calculate next rotation value
rotation += 15f;
while (rotation >= 360f) {
rotation -= 360f;
}
//Tell the Handler to do the rotation
Bundle bundle = new Bundle();
bundle.putFloat("rotation", rotation);
Message msg = new Message();
msg.setData(bundle);
handler.sendMessage(msg);
}
};
timer.schedule(timerTask, 0, ANIMATION_PERIOD_MS);
}
public void stopRotation() {
if (null != timerTask) {
timerTask.cancel();
}
}
}
MainActivityTest.java:
package com.example.rotatingimageviewapp.test;
import android.app.Activity;
import android.test.ActivityInstrumentationTestCase2;
import com.example.rotatingimageviewapp.MainActivity;
public class MainActivityTest extends
ActivityInstrumentationTestCase2<MainActivity> {
public MainActivityTest() {
super(MainActivity.class);
}
protected void setUp() throws Exception {
super.setUp();
}
protected void tearDown() throws Exception {
super.tearDown();
}
public void test001() {
assertEquals(1 + 2, 3 + 0);
}
public void test002() {
//Test hangs on the following line until app goes to background
Activity activity = getActivity();
assertNotNull(activity);
}
public void test003() {
assertEquals(1 + 2, 3 + 0);
}
}