当自定义 ImageView 调用 startAnimation(Animation) 时,为什么在 JUnit 测试期间 getActivity() 会阻塞? [英] Why does getActivity() block during JUnit test when custom ImageView calls startAnimation(Animation)?

查看:23
本文介绍了当自定义 ImageView 调用 startAnimation(Animation) 时,为什么在 JUnit 测试期间 getActivity() 会阻塞?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我编写了一个 Android 应用程序,它使用 startAnimation(Animation) 显示一个自定义的 ImageView,它会定期旋转.该应用程序运行良好,但如果我创建一个 ActivityInstrumentationTestCase2 类型的 JUnit 测试并且该测试调用 getActivity(),则该调用对 getActivity()永远不会返回,直到应用程序进入后台(例如,按下设备的主页按钮).

I wrote an Android app that displays a custom ImageView that rotates itself periodically, using startAnimation(Animation). The app works fine, but if I create a JUnit test of type ActivityInstrumentationTestCase2 and the test calls getActivity(), that call to getActivity() never returns until the app goes to the background (for example, the device's home button is pressed).

经过很多时间和挫折,我发现如果我在自定义 ImageView<中注释掉对 startAnimation(Animation) 的调用,getActivity() 会立即返回/代码> 类.但这会违背我的自定义 ImageView 的目的,因为我确实需要为它设置动画.

After much time and frustration, I found that getActivity() returns immediately if I comment out the call to startAnimation(Animation) in my custom ImageView class. But that would defeat the purpose of my custom ImageView, because I do need to animate it.

谁能告诉我为什么在我的 JUnit 测试期间 getActivity() 会阻塞,但只有在使用 startAnimation 时才阻塞?提前感谢任何可以提出解决方法或告诉我我做错了什么的人.

Can anyone tell me why getActivity() blocks during my JUnit test but only when startAnimation is used? Thanks in advance to anyone who can suggest a workaround or tell me what I'm doing wrong.

注意:该解决方案至少需要使用 Android API 级别 10.

Note: the solution needs to work with Android API level 10 minimum.

这是运行它所需的所有源代码(将任何 PNG 图像放入 res/drawable 并将其命名为 the_image.png):

Here is all the source code you need to run it (put any PNG image in res/drawable and call it the_image.png):

activity_main.xml:

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>

MainActivity.java:

MainActivity.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):

RotatingImageView.java (custom 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:

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);
    }

}

推荐答案

不知道你们是否解决了这个问题.但这是我的解决方案,只需覆盖方法 getActivity():

not sure if you guys solve this. But this is my solution, just override method getActivity():

@Override
    public MyActivity getActivity() {
        if (mActivity == null) {
            Intent intent = new Intent(getInstrumentation().getTargetContext(), MyActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            // register activity that need to be monitored.
            monitor = getInstrumentation().addMonitor(MyActivity.class.getName(), null, false);
            getInstrumentation().getTargetContext().startActivity(intent);
            mActivity = (MyActivity) getInstrumentation().waitForMonitor(monitor);
            setActivity(mActivity);
        }
        return mActivity;
    }

这篇关于当自定义 ImageView 调用 startAnimation(Animation) 时,为什么在 JUnit 测试期间 getActivity() 会阻塞?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆