¿Por qué se bloquea getActivity () durante la prueba JUnit cuando las llamadas de ImageView personalizadas comienzanAnimation (Animation)?
Escribí una aplicación de Android que muestra un ImageView
personalizado que se rota periódicamente, utilizando startAnimation(Animation)
. La aplicación funciona correctamente, pero si creo una prueba JUnit de tipo ActivityInstrumentationTestCase2
y las llamadas de prueba getActivity()
, esa llamada a getActivity()
nunca vuelve hasta que la aplicación se va al fondo (por ejemplo, se presiona el botón de inicio del dispositivo).
Después de mucho tiempo y frustración, descubrí que getActivity()
devuelve inmediatamente si comento la llamada a startAnimation(Animation)
en mi clase de ImageView
personalizada. Pero eso derrotaría el propósito de mi imagen personalizada, porque necesito animarla.
- ¿Cuál es la manera más eficiente de cargar mi archivo JPG almacenado en ImageView?
- añadir dinámicamente el diseño al método getview del adaptador en android
- Cambiar la fuente de ImageView
- Obtener coordenadas reales de xy de los usuarios
- Anclaje de ImageView a Collapsing Toolbar
¿Puede alguien decirme por qué bloques getActivity()
durante mi prueba de JUnit pero sólo cuando startAnimation
se utiliza? Gracias de antemano a cualquier persona que puede sugerir una solución o decirme lo que estoy haciendo mal.
Nota: la solución debe funcionar con la API de Android mínimo 10.
Aquí está todo el código fuente que necesita para ejecutarlo (ponga cualquier imagen PNG en res / drawable y llámela 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>
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 (personalizado 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); } }
- App: srcCompat - Vector drawable se muestra en la vista previa del diseño, pero no se muestra en la aplicación
- ¿Es posible obtener coordenadas en tiempo real de un ImageView mientras está en la animación de Translate?
- Establecer visibilidad de la barra de progreso en la finalización de la carga de la imagen utilizando la biblioteca Glide
- Android se desvanece y se desvanece con ImageView
- El efecto Ripple no va por encima de ImageView
- GetActivity (). StartActivityForResult () no funciona en fragmentos
- Rotación de ImageView desde el archivo xml de diseño
- Extraño comportamiento de las imágenes en RecyclerView
No estoy seguro de si ustedes resuelven esto. Pero esta es mi solución, sólo el método override 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; }
Puedo decirle por qué esto está sucediendo y tienen una pequeña solución, creo que debería ser capaz de hacer algo con su punto de vista, pero esto debería funcionar por ahora.
El problema es que, cuando llamas a getActivity (), pasa por una serie de métodos hasta que toca lo siguiente en InstrumentationTestCase.java
public final <T extends Activity> T launchActivityWithIntent( String pkg, Class<T> activityCls, Intent intent) { intent.setClassName(pkg, activityCls.getName()); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); T activity = (T) getInstrumentation().startActivitySync(intent); getInstrumentation().waitForIdleSync(); return activity; }
El problema es la pesky línea que tiene lo siguiente:
getInstrumentation().waitForIdleSync();
Debido a su animación nunca hay un inactivo en el hilo principal y por lo que nunca vuelve de este método! ¿Cómo se puede arreglar esto? Así es bastante fácil que tendrá que anular este método por lo que ya no tiene esa línea pulg Usted puede tener que agregar en algún código para poner una espera para asegurarse de que la actividad se inicia, aunque de lo contrario este método volverá demasiado rápido! Sugiero esperar una vista específica para esta actividad.
ACTUALIZACIÓN: gracias a @nebula por la respuesta anterior: https://stackoverflow.com/a/24506584/720773
Aprendí sobre una solución sencilla para este problema: utilice un enfoque diferente para rotar la imagen, que no implica Animation
:
Android: gira la imagen en la vista de la imagen por un ángulo
Eso realmente no responde a mi pregunta, pero funciona en torno al problema. Si alguien sabe cómo obtener ActivityInstrumentationTestCase2.getActivity()
para devolver la Activity
mientras utiliza la clase Animation
en un ImageView
personalizado, publica un SSCCE como respuesta y lo aceptaré en lugar de éste si funciona.
He aprendido sobre cada solución para este problema, y esta es mi solución, funciona bien, thx todo el mundo;)
public class TestApk extends ActivityInstrumentationTestCase2 { private static final String LAUNCHER_ACTIVITY_FULL_CLASSNAME = "com.notepad.MainActivity"; private static Class launcherActivityClass; static { try { launcherActivityClass = Class .forName(LAUNCHER_ACTIVITY_FULL_CLASSNAME); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } public TestApk () throws ClassNotFoundException { super(launcherActivityClass); } private Solo solo; @Override protected void setUp() throws Exception { solo = new Solo(getInstrumentation()); Intent intent = new Intent(getInstrumentation().getTargetContext(), launcherActivityClass); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); getInstrumentation().getTargetContext().startActivity(intent); } public void test_ookla_speedtest() { Boolean expect = solo.waitForText("Login", 0, 60*1000); assertTrue("xxxxxxxxxxxxxxxxxxx", expect); } @Override public void tearDown() throws Exception { solo.finishOpenedActivities(); super.tearDown(); } }
- La aplicación Ionic / Cordova no recibe notificación push en el fondo
- Cómo cambiar el tamaño de Bitmaps de la manera óptima en Android?