Skip to content
This repository has been archived by the owner on May 19, 2023. It is now read-only.

Rotating the device resets everything (Android) #28

Open
kentcb opened this issue Nov 16, 2015 · 16 comments
Open

Rotating the device resets everything (Android) #28

kentcb opened this issue Nov 16, 2015 · 16 comments
Labels

Comments

@kentcb
Copy link
Contributor

kentcb commented Nov 16, 2015

The layout is such that test names are not discernible on small devices. The text just gets cut off somewhere within the namespace name, or class name if you're lucky. Also, rotating the device in an attempt to find out test names seems to reset everything.

Perhaps trim the start of the text?

@clairernovotny
Copy link
Member

What platform are you seeing the resetting on? Android? There's nothing inherent in the code where a rotate should clear things, but Android is recreates activities and things could be lost

@kentcb
Copy link
Contributor Author

kentcb commented Nov 16, 2015

Yeah, it's Android.

@clairernovotny clairernovotny changed the title Can't see test names Rotating the device resets everything (Android) Nov 24, 2015
@clairernovotny
Copy link
Member

Renaming this as #28 tracks the text size issue itself.

@Bowman74
Copy link
Contributor

@onovotny Likely what is happening here is a rotation event in Android causes the main activity to reload and is resetting the present state. The likely solution is to save current state on the main activity unload and reconstitute it when the activity reloads.

@clairernovotny
Copy link
Member

Almost certainly....pr? :)

@Bowman74
Copy link
Contributor

Bowman74 commented Feb 26, 2017 via email

@ToddThomson
Copy link

@onovotny As you likely know, an Android rotation or screen orientation change restarts the currently running Activity. OnDestroy() is followed by OnCreate(). As @Bowman74 mentions above, you must save state to properly handle the Activity restart.

I can issue a PR for this, but I need to determine first how you are handling the background thread that is running the tests. With Android this is accomplished with a Service. I will investigate and get back to you soon...

@clairernovotny
Copy link
Member

clairernovotny commented Jun 6, 2018

I'd love a PR to fix this...I've just put up with it all this time. The thing you'd want is to keep the xUnit classes alive between the views and then reattach them to the new view instances. The threading model of the execution doesn't matter as much long as the xUnit class instances are maintained.

@ToddThomson
Copy link

@onovotny Yes, I'm just looking into that. When an Activity is destroyed so are all it's resources. It is likely that the thread(s) that is running the test(s) will need to be run in a Service. Let me take a look and I'll get back to you soon...

@ToddThomson
Copy link

ToddThomson commented Jun 7, 2018

@onovotny Sorry for the delay. It took me a bit to get debugging working in VS with your library, but I eventually figured it out. I also do not use Xamarin Forms as I find it too much to learn yet another framework. Xamarin.Android and Xamarin.iOS are more of just using c# with the Android and iOS APIs. Each to their own however.

With Android, even though you are using Forms, the entry point to the app is an Activity ( base class for FormsAppCompatActvity - which you should be using to run on a greater API levels set ). This means that android activity lifecycle events occur for various user interactions including device orientation changes. Using Forms does not insulate you from activity life cycle events. When the activity is destroyed so are all it's threads and xunit class instances. The only way to keep background operations running when an activity is torn down is to use a Service.

In general, It is quite likely that running tests may take quite a long time. During this time the user may decide to do anything - switch to, or start, another app, etc. All could cause grief! So, although screen orientations are causing you grief, there are many other user or system interactions that will also cause you grief.

On Android platforms, the way around all these issues is to utilize a background service. You run your test(s) in a service context and utilize a message passing mechanism. This makes your app a bit more complicated. Since your XUnit.Devices package is cross platform you will need to do this for each platform.

I can ( and already have ) made is so that your Android implementation does not allow for tear down of its main activity on screen orientation changes. However, as mentioned above, this will cover only 1 case of user interaction.

This may be outside of the scope of work that want to make. Please give me your thoughts.

@clairernovotny
Copy link
Member

I'm not sure I follow 100% -- there's nothing that an activity can do to control/kill the threads we create in our instance...?

If we use a static FormsRunner instance, wouldn't that solve it?

@ToddThomson
Copy link

When an Activity is about to be killed it receives the onDestroy() life cycle event. The Activity should then perform housekeeping ( Cancel background threads to avoid avoid memory leaks, etc. ).

A static FormsRunner instance would still live in an Activity context.

Android provides Services to help with background threading scenarios. It's just the way it is. It's not too much more effort to put your DeviceRunner code into a background service.

If using a service is outside the scope of work that you want to make then just clean up your threads when the activity is destroyed and fix screen orientation as portrait.

@ToddThomson
Copy link

@onovotny

If we use a static FormsRunner instance, wouldn't that solve it?

I believe you are thinking along the lines of how Xamarin.Android.NUnitLite works. NUnitLite utilizes a static AndroidRunner.Runner instance. This instance will persist until the JVM unloads the outer class or the DVM is killed (essentially). This is perhaps a "Good Enough" solution, but, in general, it is not robust.

If a test app, derived from your RunnerActivity, goes into a paused or stopped state, Android can kill it at any time. Even if the test app is not killed what happens when the test app resumes/restarts? Was a there a test running on a worker thread? Has it completed? Is it still running?

If you don't want your app to save state given life cycle events (how it works now) then I would at minimum make your DeviceRunner static and then have your UI react to its current state (Tests Running, Finished with Results, Not Run, etc ).

The robust approach would be to utilize an Android service to perform the tests and have your UI listen for updates from the service.

This is your package so I just need to know what you're interested in doing ( not much - just deal with the screen orientation change; moderate effort - keep testing state in static DeviceRunner and have the UI react to it's current state; moderate effort - utilize a service component to handle testing with the UI reacting to the state of the service ).

@ToddThomson
Copy link

@onovotny I'm going to go ahead with using the Xamarin Forms Backgrounding technique to handle long running test tasks.

@ToddThomson
Copy link

ToddThomson commented Jun 9, 2018

@onovotny Why doesn't UWP get a package reference to Xamarin.Forms in csproj?

<PackageReference Condition="'$(IsXamForms)' == 'true'" Include="Xamarin.Forms" Version="3.0.0.482510" />

@clairernovotny
Copy link
Member

Because UWP has its own UWP XAML Implementation due to Xam Forms not working well with .NET Native at the time. (it may be better now).

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

4 participants