Scrolling using UiScrollable stops in the middle of the screen

I am trying to scroll down to the bottom of the screen to a UI block using UiSelector class but it’s not working as expected. Basically, when I run the code it does not scroll all the way to the bottom rather it the first pulls (sort pull to refresh) and then starts scrolling but stops in the middle of the screen and then it goes back and forth and at some point it fails with an exception NoSuchElementException(attached a screen recording).
Below is the code I used:

myDriver.findElement(MobileBy.AndroidUIAutomator("new UiScrollable("
				+ "new UiSelector().description(\"scrollview_train_tab\")).scrollIntoView("                      
				+ "new UiSelector().textMatches(\"Games\"));"));

Here, myDriver is an instance of AndroidDriver.
Please note that the app does not have resourceId so I am using content-desc to identify UI objects.

I have tried with the followings methods in UiSelector class: text(), textContains(),description(), textMatches() but no luck. All of these are resulting in the same behaviour.

Please check this screen recording

Appium Client/Version: Java/7.3.0

Appium Server: 1.18.0-1 (Desktop version)

Executed on Android Emulator with Android 8

OS: Windows 10

Can anybody help? Thanks in advance.

@Aleksei hoping you can help me out.

try to increase number of swipes first (setMaxSearchSwipes). also visit guide which should help in many cases -> http://appium.io/docs/en/writing-running-appium/tutorial/swipe-tutorial/

Thank you for the replay. Really appreciate this.
I already tried a solution with setMaxSearchSwipes but no luck. Besides, I also tried all the solution from http://appium.io/docs/en/writing-running-appium/tutorial/swipe-tutorial/

Code snippet used:
driver.findElement(MobileBy.AndroidUIAutomator( "new UiScrollable(new UiSelector().description(\"content-desc\")).setMaxSearchSwipes(10)" + ".scrollIntoView(new UiSelector().text(\"text_to_match\"))"));

Could there be an issue with the layout? Below is the inspected layout of the screen.

pls attach result of:
System.out.println(driver.getPageSource())
on this screen as file

Here is the page source:
pageSource.log (19.5 KB)

try:

// 1
driver.findElement(MobileBy.AndroidUIAutomator(
                    "new UiScrollable(new UiSelector().scrollable(true).instance(0))" +
                            ".scrollIntoView(new UiSelector()" +
                            ".textMatches(\"" + elementText + "\").instance(0))"));

// 2
driver.findElement(MobileBy.AndroidUIAutomator(
                    "new UiScrollable(new UiSelector().scrollable(true).description(\"content-desc\"))" +
                            ".scrollIntoView(new UiSelector()" +
                            ".textMatches(\"" + elementText + "\").instance(0))"));

// 3
driver.findElement(MobileBy.AndroidUIAutomator(
                    "new UiScrollable(new UiSelector().scrollable(true).instance(0))" +
                            ".setSwipeDeadZonePercentage(50).scrollIntoView(new UiSelector()" +
                            ".textMatches(\"" + elementText + "\").instance(0))"));
// 4 final solution when nothing helps -> switch to:
// scrollForward (moves exactly one view)
try {
    driver.findElement(MobileBy.AndroidUIAutomator(
            "new UiScrollable(new UiSelector().scrollable(true)).scrollForward()"));
} catch (InvalidSelectorException e) {
    // ignore
}
// and quickly check text needed appeared
// repeat scrollForward + text check in loop with some limit e.g. 10 tries.

Thank you. I really appreciate your help. The first 3 didn’t help. 4th solution didn’t work as well. However, I made a little adjustment then it worked.
Here is working code snippet:
Scroll down:
driver.findElement(MobileBy.AndroidUIAutomator("new UiScrollable(new UiSelector().description(\""+parentScrollViewId+"\")).scrollForward()"));

Scroll up:
driver.findElement(MobileBy.AndroidUIAutomator("new UiScrollable(new UiSelector().description(\""+parentScrollViewId+"\")).scrollBackward()"));

Your adjustment is correct. I just copied code like basic idea. Good. Try same adjustment with 1 2 and 3

@Aleksei I tried but none of them work.
So tried the below code to scroll until the element is displayed but it throws error after scrolling once. The script works on emulator (OS -7) but fails on real android device with OS version 7 but work on real device with android 10.

		boolean elementFound = false;
	while(elementFound==false) {
		try {
			if(mobEl.isDisplayed()==true) {
				break;
			}
		}catch(Exception e) {
			elementFound=false;
		}
		waitForEvent(2);
		driver.findElement(MobileBy.AndroidUIAutomator("new UiScrollable(new UiSelector().description(\"scrollview_learn_tab\")).scrollForward()"));
	}
Here is the error log

09:39:02:159 - [HTTP] --> POST /wd/hub/session/2f8f63ae-25d6-4a00-946e-20c7fc19600a/element
2020-08-27 09:39:02:159 - [HTTP] {“using”:"-android uiautomator",“value”:“new UiScrollable(new UiSelector().description(“scrollview_learn_tab”)).scrollForward()”}
2020-08-27 09:39:02:160 - [debug] [W3C (2f8f63ae)] Calling AppiumDriver.findElement() with args: ["-android uiautomator",“new UiScrollable(new UiSelector().description(“scrollview_learn_tab”)).scrollForward()”,“2f8f63ae-25d6-4a00-946e-20c7fc19600a”]
2020-08-27 09:39:02:160 - [debug] [BaseDriver] Valid locator strategies for this request: xpath, id, class name, accessibility id, -android uiautomator
2020-08-27 09:39:02:160 - [debug] [BaseDriver] Waiting up to 5000 ms for condition
2020-08-27 09:39:02:161 - [debug] [WD Proxy] Matched ‘/element’ to command name ‘findElement’
2020-08-27 09:39:02:162 - [debug] [WD Proxy] Proxying [POST /element] to [POST http://127.0.0.1:8200/wd/hub/session/8f1b5e7b-396a-4567-94c0-6d3a99b85ed1/element] with body: {“strategy”:"-android uiautomator",“selector”:“new UiScrollable(new UiSelector().description(“scrollview_learn_tab”)).scrollForward()”,“context”:"",“multiple”:false}
2020-08-27 09:39:03:445 - [WD Proxy] Got an unexpected response with status 400: {“sessionId”:“8f1b5e7b-396a-4567-94c0-6d3a99b85ed1”,“value”:{“error”:“invalid selector”,“message”:“Could not parse expression new UiScrollable(new UiSelector().description(\"scrollview_learn_tab\")).scrollForward(): Last method called on a UiScrollable object must return a UiObject object”,“stacktrace”:"io.appium.uiautomator2.common.exceptions.UiSelectorSyntaxException: Could not parse expression new UiScrollable(new UiSelector().description(\"scrollview_learn_tab\")).scrollForward(): Last method called on a UiScrollable object must return a UiObject object\n\tat io.appium.uiautomator2.utils.UiScrollableParser.parse(UiScrollableParser.java:71)\n\tat io.appium.uiautomator2.utils.UiAutomatorParser.consumeStatement(UiAutomatorParser.java:92)\n\tat io.appium.uiautomator2.utils.UiAutomatorParser.parse(UiAutomatorParser.java:48)\n\tat io.appium.uiautomator2.utils.ElementLocationHelpers.toSelectors(ElementLocationHelpers.java:98)\n\tat io.appium.uiautomator2.utils.ElementLocationHelpers.toSelector(ElementLoca…
2020-08-27 09:39:03:446 - [debug] [W3C] Matched W3C error code ‘invalid selector’ to InvalidSelectorError
2020-08-27 09:39:03:492 - [debug] [W3C (2f8f63ae)] Encountered internal error running command: io.appium.uiautomator2.common.exceptions.UiSelectorSyntaxException: Could not parse expression new UiScrollable(new UiSelector().description("scrollview_learn_tab")).scrollForward(): Last method called on a UiScrollable object must return a UiObject object
2020-08-27 09:39:03:492 - [debug] [W3C (2f8f63ae)] at io.appium.uiautomator2.utils.UiScrollableParser.parse(UiScrollableParser.java:71)
2020-08-27 09:39:03:493 - [debug] [W3C (2f8f63ae)] at io.appium.uiautomator2.utils.UiAutomatorParser.consumeStatement(UiAutomatorParser.java:92)
2020-08-27 09:39:03:493 - [debug] [W3C (2f8f63ae)] at io.appium.uiautomator2.utils.UiAutomatorParser.parse(UiAutomatorParser.java:48)
2020-08-27 09:39:03:493 - [debug] [W3C (2f8f63ae)] at io.appium.uiautomator2.utils.ElementLocationHelpers.toSelectors(ElementLocationHelpers.java:98)
2020-08-27 09:39:03:493 - [debug] [W3C (2f8f63ae)] at io.appium.uiautomator2.utils.ElementLocationHelpers.toSelector(ElementLocationHelpers.java:92)
2020-08-27 09:39:03:493 - [debug] [W3C (2f8f63ae)] at io.appium.uiautomator2.handler.FindElement.findElement(FindElement.java:106)
2020-08-27 09:39:03:493 - [debug] [W3C (2f8f63ae)] at io.appium.uiautomator2.handler.FindElement.safeHandle(FindElement.java:72)
2020-08-27 09:39:03:493 - [debug] [W3C (2f8f63ae)] at io.appium.uiautomator2.handler.request.SafeRequestHandler.handle(SafeRequestHandler.java:38)
2020-08-27 09:39:03:493 - [debug] [W3C (2f8f63ae)] at io.appium.uiautomator2.server.AppiumServlet.handleRequest(AppiumServlet.java:252)
2020-08-27 09:39:03:493 - [debug] [W3C (2f8f63ae)] at io.appium.uiautomator2.server.AppiumServlet.handleHttpRequest(AppiumServlet.java:242)
2020-08-27 09:39:03:494 - [debug] [W3C (2f8f63ae)] at io.appium.uiautomator2.http.ServerHandler.channelRead(ServerHandler.java:51)
2020-08-27 09:39:03:494 - [debug] [W3C (2f8f63ae)] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)
2020-08-27 09:39:03:494 - [debug] [W3C (2f8f63ae)] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)
2020-08-27 09:39:03:494 - [debug] [W3C (2f8f63ae)] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345)
2020-08-27 09:39:03:494 - [debug] [W3C (2f8f63ae)] at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
2020-08-27 09:39:03:494 - [debug] [W3C (2f8f63ae)] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)
2020-08-27 09:39:03:494 - [debug] [W3C (2f8f63ae)] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)
2020-08-27 09:39:03:494 - [debug] [W3C (2f8f63ae)] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345)
2020-08-27 09:39:03:494 - [debug] [W3C (2f8f63ae)] at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:435)
2020-08-27 09:39:03:495 - [debug] [W3C (2f8f63ae)] at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:293)
2020-08-27 09:39:03:495 - [debug] [W3C (2f8f63ae)] at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:267)
2020-08-27 09:39:03:495 - [debug] [W3C (2f8f63ae)] at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:250)
2020-08-27 09:39:03:495 - [debug] [W3C (2f8f63ae)] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)
2020-08-27 09:39:03:495 - [debug] [W3C (2f8f63ae)] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)
2020-08-27 09:39:03:495 - [debug] [W3C (2f8f63ae)] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345)
2020-08-27 09:39:03:495 - [debug] [W3C (2f8f63ae)] at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1294)
2020-08-27 09:39:03:495 - [debug] [W3C (2f8f63ae)] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)
2020-08-27 09:39:03:495 - [debug] [W3C (2f8f63ae)] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)
2020-08-27 09:39:03:495 - [debug] [W3C (2f8f63ae)] at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:911)
2020-08-27 09:39:03:496 - [debug] [W3C (2f8f63ae)] at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:131)
2020-08-27 09:39:03:496 - [debug] [W3C (2f8f63ae)] at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:611)
2020-08-27 09:39:03:496 - [debug] [W3C (2f8f63ae)] at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:552)
2020-08-27 09:39:03:496 - [debug] [W3C (2f8f63ae)] at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:466)
2020-08-27 09:39:03:496 - [debug] [W3C (2f8f63ae)] at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:438)
2020-08-27 09:39:03:496 - [debug] [W3C (2f8f63ae)] at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:140)
2020-08-27 09:39:03:496 - [debug] [W3C (2f8f63ae)] at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144)
2020-08-27 09:39:03:496 - [debug] [W3C (2f8f63ae)] at java.lang.Thread.run(Thread.java:761)
2020-08-27 09:39:03:496 - [debug] [W3C (2f8f63ae)]

Any idea what could be the reason?

You should ignore scrollForward errors like in example i wrote with try-catch.

Plus after scroll you should search for element again! But you checking that some old found element displaying.

1 Like

Thank you so much. That was so silly about them.
Here is the full working solution:

	public void scrollUntilElementFound(AppiumDriver<?> driver, MobileElement elementScrollTo,String parentScrollViewId) {//Scrolls until element is found
	boolean elementFound = false;
	while(elementFound==false) {
		try {
			if(elementScrollTo.isDisplayed()==true) {
				break;
			}
		}catch(Exception e) {
			elementFound=false;
		}
		try {
			driver.findElement(MobileBy.AndroidUIAutomator("new UiScrollable(new UiSelector().description(\""+parentScrollViewId+"\")).scrollForward()"));
		}catch(Exception e) {
			//Ignore error 	
		}
	}
}

@Aleksei
I am using the above script to scroll down but it is super slow like it takes 10+ seconds between two scrolls. Do you have any suggestions to improve this?

I found that If I only use the scrolling code snippet for example, the below line then the scrolling is fast enough (1.5 seconds between two scrolls). So I assume it’s the text search part that is causing the delay.

driver.findElement(MobileBy.AndroidUIAutomator("new UiScrollable(new UiSelector().description(\""+parentScrollViewId+"\")).scrollForward()"));

Log each action. What cause it.
“elementScrollTo.isDisplayed()” or scroll itself. As workaround use simple scroll example from tutorial.