【问题标题】:ActivityInstrumentationTestCase2 issues - test hangs because of invalidate() call in the code I'm writing a test forActivityInstrumentationTestCase2 问题 - 由于我正在为其编写测试的代码中的 invalidate() 调用,测试挂起
【发布时间】:2011-11-02 08:51:36
【问题描述】:

我正在对我编写的一些代码进行测试 提炼成下面粘贴的示例项目。 我遇到的问题是测试挂起测试运行器并且 我的测试用例中没有一个测试运行。

我已将问题归结为对 invalidate() 的调用 getChildStaticTransformation(View child, Transformation t) 我是 覆盖做一些缩放效果。

如果我注释掉对 invalidate() 的调用,那么测试就会运行。这 我之所以调用 invalidate() 是为了确保视图得到 应用缩放效果后重绘。

如果我不调用 invalidate() 那么视图看起来不正确,直到 用户操作会强制重新绘制屏幕。

两个问题:

  1. 为什么 invalidate() 会阻止测试运行?
  2. 我是否应该以不同的方式缩放视图? 需要调用 invalidate() 吗?

以下是 Eclipse Android 控制台的输出,显示了在哪里 测试挂起:

[2011-08-19 13:51:27 - HelloGalleryTest]
------------------------------
[2011-08-19 13:51:27 - HelloGalleryTest] Android Launch!
[2011-08-19 13:51:27 - HelloGalleryTest] adb is running normally.
[2011-08-19 13:51:27 - HelloGalleryTest] Performing
android.test.InstrumentationTestRunner JUnit launch
[2011-08-19 13:51:27 - HelloGalleryTest] Automatic Target Mode: using
device '428024642BF9457'
[2011-08-19 13:51:27 - HelloGalleryTest] Uploading
HelloGalleryTest.apk onto device '428024642BF9457'
[2011-08-19 13:51:27 - HelloGalleryTest] Installing
HelloGalleryTest.apk...
[2011-08-19 13:51:29 - HelloGalleryTest] Success!
[2011-08-19 13:51:29 - HelloGalleryTest] Project dependency found,
installing: HelloGallery
[2011-08-19 13:51:29 - HelloGallery] Uploading HelloGallery.apk onto
device '428024642BF9457'
[2011-08-19 13:51:29 - HelloGallery] Installing HelloGallery.apk...
[2011-08-19 13:51:31 - HelloGallery] Success!
[2011-08-19 13:51:31 - HelloGalleryTest] Launching instrumentation
android.test.InstrumentationTestRunner on device 428024642BF9457
[2011-08-19 13:51:31 - HelloGalleryTest] Collecting test information
[2011-08-19 13:51:32 - HelloGalleryTest] Sending test information to
Eclipse
[2011-08-19 13:51:32 - HelloGalleryTest] Running tests...

以下是我编写的示例项目代码和测试用例 表现出我上面描述的问题。 HelloGallery.getChildStaticTransformation(查看孩子,转换 t) 是调用 invalidate() 的方法。

下面包含的其他文件是为了完整性,以防您想要 尝试构建项目并观察我所描述的行为。

START::HELLO_GALLERY_PROJECT-FILES

HelloGallery.java

package com.hello;

import android.content.Context;
import android.graphics.Camera;
import android.graphics.Matrix;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Transformation;
import android.widget.Gallery;

public class HelloGallery extends Gallery {

       private Camera mCamera = new Camera();

       /**
        * The position (index) of the centered view in the gallery.
        */
       public int mCenterViewPositionIndex;

       public HelloGallery(Context context, AttributeSet attrs) {
               super(context, attrs);
               this.setStaticTransformationsEnabled(true);
       }

       /**
        * {@inheritDoc}
        *
        * @see #setStaticTransformationsEnabled(boolean)
        */
       protected boolean getChildStaticTransformation(View child,
Transformation t) {
               t.clear();

               mCamera.save();
               final Matrix imageMatrix = t.getMatrix();
               int position = getPositionForView(child);
               t.setTransformationType(Transformation.TYPE_MATRIX);

               if (child == getSelectedView()) {
                       mCenterViewPositionIndex = position;

                       t.setAlpha(1f);
                       mCamera.translate(-20, 20, -200);
               }
               else if(((mCenterViewPositionIndex - 1) == position )) {
                       t.setAlpha(0.5f);
                       // no need to zoom this view.
               }
               else if((mCenterViewPositionIndex + 1) == position ) {
                       t.setAlpha(0.5f);
                       // no need to zoom this view.
               }

               else if(((mCenterViewPositionIndex - 2) == position )) {
                       t.setAlpha(0.35f);
                       mCamera.translate(0, 0, 250);
               }
               else if((mCenterViewPositionIndex + 2) == position ) {
                       t.setAlpha(0.35f);
                       mCamera.translate(0, 0, 250);
               }

               else if(((mCenterViewPositionIndex - 3) == position )) {
                       t.setAlpha(0.1f);
                       mCamera.translate(0, 0, 350);
               }
               else if((mCenterViewPositionIndex + 3) == position ) {
                       t.setAlpha(0.2f);
                       mCamera.translate(0, 0, 350);
               }else {
                       t.setAlpha(0.1f);
                       mCamera.translate(0, 0, 450);
               }

               mCamera.getMatrix(imageMatrix);
               mCamera.restore();
//              invalidate();  //  <----  commenting out this line allows the Test
to run.   Uncommenting this line will not allow the Test to run.

               return true;
       }
}

HelloGalleryActivity.java

package com.hello;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Gallery;

public class HelloGalleryActivity extends Activity implements OnItemClickListener {
    private Gallery mGallery;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mGallery=(Gallery)findViewById(R.id.gallery);

        //String array holding the values
        String [] text=new String[]{"Hello","Hi","Alloha","Bonjour","Hallo","¡Hola"};

        //Circular Array adapter to display our values in the gallery control
        HomeGalleryAdapter adapter = new HomeGalleryAdapter(this, R.layout.gallery_item_layout, text);
        mGallery.setAdapter(adapter);
        mGallery.setSelection(adapter.MIDDLE);
        mGallery.setOnItemClickListener(this);
        mGallery.setOnTouchListener(new OnTouchListener() {

            public boolean onTouch(View arg0, MotionEvent arg1) {
                Log.d("HelloGalleryActivity", " --> onTouch");
                return false;
            }
        });        
    }

    @Override
    public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
        Log.d("HelloGalleryActivity", " --> onItemClick");  
    }
}

HelloGalleryAdapter.java

package com.hello;

import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

public class HomeGalleryAdapter extends ArrayAdapter<String> {
       private LayoutInflater mLayoutInflater;
       private TextView mText;
       private int mLayoutId;

       public static final int HALF_MAX_VALUE = Integer.MAX_VALUE/2;
   public final int MIDDLE;
   private String[] mObjects;

       public HomeGalleryAdapter(Context context, int layoutId, String[]
lables) {
               super(context, 0, lables);

               mLayoutInflater = ((Activity) context).getLayoutInflater();
               mLayoutId = layoutId;

           mObjects = lables;
           MIDDLE = HALF_MAX_VALUE - HALF_MAX_VALUE % lables.length;
       }

       public int getCount() {
               return Integer.MAX_VALUE;
       }

       public String getItem(int position) {
               return mObjects[position % mObjects.length];
       }

       public long getItemId(int position) {
               return position % mObjects.length;
       }

       public View getView(int position, View convertView, ViewGroup group)
{
               if (convertView == null) {
                       convertView = mLayoutInflater.inflate(mLayoutId, group, false);
               }

               mText = (TextView) convertView.findViewById(R.id.gallery_item_text);

               mText.setText((String) getItem(position));
               mText.setTextColor(Color.WHITE);

               convertView.setTag(mText.getText());

               return convertView;
       }
}

res/layout/main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
       xmlns:android="http://schemas.android.com/apk/res/android"
       android:orientation="vertical"
       android:layout_width="fill_parent"
       android:layout_height="fill_parent">

       <TextView
               android:id="@+id/textview"
               android:layout_width="fill_parent"
               android:layout_height="wrap_content"
               android:text="@string/hello" />

       <com.hello.HelloGallery
               android:id="@+id/gallery"
               android:layout_gravity="center"
               android:spacing="0dp"
               android:layout_width="fill_parent"
               android:layout_height="fill_parent" />
</LinearLayout>

res/layout/gallery_item_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
       xmlns:android="http://schemas.android.com/apk/res/android"
       android:id="@+id/home_gallery_item_layout"
       android:orientation="vertical"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_gravity="center">

       <RelativeLayout
               android:id="@+id/gallery_item_background"
               android:layout_width="100dip"
               android:layout_height="100dip"
               android:orientation="horizontal"
               android:background="@drawable/gallery_item_selector">

               <ImageView
                       android:src="@drawable/icon"
                       android:id="@+id/gallery_item_icon"
                       android:layout_width="wrap_content"
                       android:layout_height="wrap_content"
                       android:layout_centerInParent="true" />

       </RelativeLayout>

       <TextView
               android:id="@+id/gallery_item_text"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:layout_gravity="center"
               android:textSize="20sp" />
</LinearLayout>

res/drawable/gallery_item_selector.xml

 <selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true"
          android:drawable="@drawable/background_selected" /> <!--
pressed -->
    <item android:drawable="@drawable/background_normal" /> <!--
default -->
 </selector>

res/drawable/background_normal.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
   android:shape="rectangle">
   <gradient
       android:startColor="#80000000"
       android:endColor="#80FFFFFF"
       android:angle="45"/>
   <padding android:left="7dp"
       android:top="7dp"
       android:right="7dp"
       android:bottom="7dp" />
   <corners android:radius="8dp" />
</shape>

res/drawable/background_selected.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
   android:shape="rectangle">
   <gradient
       android:startColor="#80000000"
       android:endColor="#807EB6FF"
       android:angle="45"/>
   <padding android:left="7dp"
       android:top="7dp"
       android:right="7dp"
       android:bottom="7dp" />
   <corners android:radius="8dp" />
</shape>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest
       xmlns:android="http://schemas.android.com/apk/res/android"
       package="com.hello"
       android:versionCode="1"
       android:versionName="1.0">
       <uses-sdk
               android:minSdkVersion="7" />

       <application
               android:icon="@drawable/icon"
               android:label="@string/app_name">
               <activity
                       android:name=".HelloGalleryActivity"
                       android:label="@string/app_name">
                       <intent-filter>
                               <action
                                       android:name="android.intent.action.MAIN" />
                               <category
                                       android:name="android.intent.category.LAUNCHER" />
                       </intent-filter>
               </activity>

       </application>
</manifest>

END::HELLO_GALLERY_PROJECT-FILES

.

START::HELLO_GALLERY_TEST_PROJECT-FILES

HelloGalleryActivityTest.java (
package com.hello.test;

import android.test.ActivityInstrumentationTestCase2;
import android.widget.Gallery;
import android.widget.SpinnerAdapter;

import com.hello.HelloGalleryActivity;

public class HelloGalleryActivityTest extends
ActivityInstrumentationTestCase2<HelloGalleryActivity> {
       private HelloGalleryActivity mActivity; // the activity under test
       private Gallery mGallery;
       private String[] mGalleryDataTestArray;
       private SpinnerAdapter mGalleryData;

       public HelloGalleryActivityTest() {
               super("com.hello", HelloGalleryActivity.class);
               mGalleryDataTestArray = new String[] { "Hello", "Hi", "Alloha",
"Bonjour", "Hallo", "¡Hola" };
       }

       @Override
       protected void setUp() throws Exception {
               super.setUp();
               setActivityInitialTouchMode(false);

               mActivity = this.getActivity();
               mGallery = (Gallery) mActivity.findViewById(com.hello.R.id.gallery);
               mGalleryData = (SpinnerAdapter) mGallery.getAdapter();
       }

       public void testPreconditions() {
               assertNotNull(mActivity);
               assertNotNull(mGallery);
               assertNotNull(mGallery.getOnItemClickListener());
               assertNotNull(mGalleryData);
       }

       public void testInitialGalleryPosition() {
               int position = mGallery.getSelectedItemPosition();
               String galleryItemLabel = (String)
mGallery.getItemAtPosition(position);

               assertEquals(mGalleryDataTestArray[0], galleryItemLabel);
       }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.hello.test"
     android:versionCode="1"
     android:versionName="1.0">
   <uses-sdk android:minSdkVersion="12" />
   <instrumentation android:targetPackage="com.hello"
android:name="android.test.InstrumentationTestRunner" />
   <application android:icon="@drawable/icon" android:label="@string/
app_name">

   <uses-library android:name="android.test.runner" />
   </application>
</manifest>

END::HELLO_GALLERY_TEST_PROJECT-FILE

【问题讨论】:

    标签: java android testing junit instrumentation


    【解决方案1】:

    尝试使用 postInvalidate() 而不是 invalidate()。

    我不能 100% 确定发生了什么,但我怀疑您的代码中有一些东西阻塞了 UI 线程。使用 postInvalidate() 将立即返回并让您的代码完成,这将解除对 UI 线程的阻塞。

    【讨论】:

    • 感谢您的建议,虽然它没有解决问题。 postInvalidate() 和 invalidate() 表现出完全相同的行为。
    【解决方案2】:

    问题解决了!

    不需要 invalidate 调用.. 它搞砸了 PERIOD!

    诀窍是向 HelloGallery.java 添加一个方法来设置中心位置并在超类上调用 setPosition。

    HelloGallery.java

    public void setSelectionToCenter(int position) {
        mCenterViewPositionIndex = position;
        setSelection(mCenterViewPositionIndex);
    }
    

    然后在 HelloGalleryActivity 中调用 setSelectionToCenter 方法而不是 setSelection。

    HelloGalleryActivity

    public void onCreate(Bundle savedInstanceState) {
        ...
        ((HelloGallery)mGallery).setSelectionToCenter(adapter.MIDDLE);
        ...
    }
    

    测试现在运行起来就像一个魅力!哇!
    感谢神秘开发者 Betsy 帮我追踪了这个问题!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-16
      • 2013-08-24
      相关资源
      最近更新 更多