Robotium学习笔记四

在这篇记录中我将完成solo类中其他未记录的方法的学习笔记,主要是Click,和Type/Enter,那么我最先开始的是Click这个类型的方法,其实这个操作的原理并不难理解,主要是拿到控件,再通过控件上的坐标点发送点击事件,下面是代码

public void clickOnText(String text) {
		clicker.clickOnText(text, false, 1, true, 0);
	}

调用Clicker类中的 clickOnText()

public void clickOnText(String regex, boolean longClick, int match, boolean scroll, int time) {
		TextView textToClick = waiter.waitForText(regex, match, Timeout.getSmallTimeout(), scroll, true, false);

		if (textToClick != null) {
			clickOnScreen(textToClick, longClick, time);
		}

		else {

			if(match > 1){
				Assert.fail(match + " matches of text string: '" + regex +  "' are not found!");
			}

			else{
				ArrayList<TextView> allTextViews = RobotiumUtils.removeInvisibleViews(viewFetcher.getCurrentViews(TextView.class, true));
				allTextViews.addAll((Collection<? extends TextView>) webUtils.getTextViewsFromWebView());

				for (TextView textView : allTextViews) {
					Log.d(LOG_TAG, "'" + regex + "' not found. Have found: '" + textView.getText() + "'");
				}
				allTextViews = null;
				Assert.fail("Text string: '" + regex + "' is not found!");
			}
		}
	}

这个方法中首先还是获取参数中传过来的控件这个方法没得可说,和前面的Search是一样的,拿到控件后就是点击了,调用 clickOnScreen()

public void clickOnScreen(View view, boolean longClick, int time) {
		if(view == null)
			Assert.fail("View is null and can therefore not be clicked!");

		float[] xyToClick = getClickCoordinates(view);
		float x = xyToClick[0];
		float y = xyToClick[1];

		if(x == 0 || y == 0){
			sleeper.sleepMini();
			try {
				view = viewFetcher.getIdenticalView(view);
			} catch (Exception ignored){}

			if(view != null){
				xyToClick = getClickCoordinates(view);
				x = xyToClick[0];
				y = xyToClick[1];
			}
		}

		if (longClick)
			clickLongOnScreen(x, y, time, view);
		else
			clickOnScreen(x, y, view);
	}	

这个方法主要是将View控件转化为坐标点,然后传给clickOnScreen()的重载形式,其中getClickCoordinates(view);这个方法就是要得到view的中心点的坐标,再加上view在屏幕上的坐标,得到了一个view中心点的坐标,(这里开始我不太明白但是也是在看了前辈的博文后才有所理解),算了不能犯懒我还是详细记录一下吧, view.getLocationOnScreen()这个方法是得到view控件左边和上边 距离屏幕左边和屏幕上边的距离从而得到坐标,再加上view内部中心点的的坐标,得到view中心点在屏幕上的绝对坐标

private float[] getClickCoordinates(View view){
		sleeper.sleep(MINI_WAIT);
		int[] xyLocation = new int[2];
		float[] xyToClick = new float[2];

		view.getLocationOnScreen(xyLocation);

		final int viewWidth = view.getWidth();
		final int viewHeight = view.getHeight();
		final float x = xyLocation[0] + (viewWidth / 2.0f);
		float y = xyLocation[1] + (viewHeight / 2.0f);

		xyToClick[0] = x;
		xyToClick[1] = y;

		return xyToClick;
	}


得到坐标后发送个体clickOnScreen()重载方法这里有一个 LongClick的值来判断 是点击还是长按

public void clickOnScreen(float x, float y, View view) {
		boolean successfull = false;
		int retry = 0;
		SecurityException ex = null;

		while(!successfull && retry < 10) {
			long downTime = SystemClock.uptimeMillis();
			long eventTime = SystemClock.uptimeMillis();
			MotionEvent event = MotionEvent.obtain(downTime, eventTime,
					MotionEvent.ACTION_DOWN, x, y, 0);
			MotionEvent event2 = MotionEvent.obtain(downTime, eventTime,
					MotionEvent.ACTION_UP, x, y, 0);
			try{
				inst.sendPointerSync(event);
				inst.sendPointerSync(event2);
				successfull = true;
			}catch(SecurityException e){
				ex = e;
				dialogUtils.hideSoftKeyboard(null, false, true);
				sleeper.sleep(MINI_WAIT);
				retry++;
				View identicalView = viewFetcher.getIdenticalView(view);
				if(identicalView != null){
					float[] xyToClick = getClickCoordinates(identicalView);
					x = xyToClick[0]; 
					y = xyToClick[1];
				}
			}
		}
		if(!successfull) {
			Assert.fail("Click at ("+x+", "+y+") can not be completed! ("+(ex != null ? ex.getClass().getName()+": "+ex.getMessage() : "null")+")");
		}
	}

到这里就一目了然了,看到了使用Instrumentation发送 MotionEvent事件完成点击,其实长按和点击是差不多的就是Key_dwon 然后sleep.


下面来看看type 先看代码

public void typeText(final EditText editText, final String text){
		if(editText != null){
			inst.runOnMainSync(new Runnable()
			{
				public void run()
				{
					editText.setInputType(InputType.TYPE_NULL);
				}
			});
			clicker.clickOnScreen(editText, false, 0);
			dialogUtils.hideSoftKeyboard(editText, true, true);

			boolean successfull = false;
			int retry = 0;

			while(!successfull && retry < 10) {

				try{
					inst.sendStringSync(text);
					successfull = true;
				}catch(SecurityException e){
					dialogUtils.hideSoftKeyboard(editText, true, true);
					retry++;
				}
			}
			if(!successfull) {
				Assert.fail("Text can not be typed!");
			}
		}
	}
}
这里其实没有什么太多难度,此方法首先设置输入类型deitText..setInputType(0),然后把焦点数值在EditText上,隐藏键盘,这些都是准备工作,最好开始输入,又事强大的Instrumentation来发送事件

,这里有一点很重要typeText 和EnterText在方法调用时其实是类似的,但是有一些区别具体请看源码

typeText调用inst.sendStringSync(text);

public void sendStringSync(String text) {
        if (text == null) {
            return;
        }
        KeyCharacterMap keyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);

        KeyEvent[] events = keyCharacterMap.getEvents(text.toCharArray());

        if (events != null) {
            for (int i = 0; i < events.length; i++) {
                // We have to change the time of an event before injecting it because
                // all KeyEvents returned by KeyCharacterMap.getEvents() have the same
                // time stamp and the system rejects too old events. Hence, it is
                // possible for an event to become stale before it is injected if it
                // takes too long to inject the preceding ones.
                sendKeySync(KeyEvent.changeTimeRepeat(events[i], SystemClock.uptimeMillis(), 0));
            }
        }
    }

可以注意到 再输入时将text转为了 char数组 一个一个的输入,让我们类对比EnterText方法 ,这个方法直接调用EditText的setText的方法editText.setText(text);

public final void setText(CharSequence text) {
        setText(text, mBufferType);
    }

这个方法就是一下把文本全部写上去没有发送KeyEvent事件,这一点是需要注意的

到此处Solo类的绝大多数类型都已经统计完毕,这是我对Robotium原理的一些简单理解,还有很多不对的和不清晰的地方 比如为什么要用 OnMainThread和OnUiThread等希望大家指出






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值