Xamarin is a complex beast, and sometimes it gets ugly if you don't use it right way...
On my current job one of the projects is a mobile (android) app which connects via bluetooth to vehicle CAN-bus, gathers some info, sends that info to backend, backend performs some statistics calculations and displays results to end user.
I must admit that we should not have used Xamarin at all, as we faced so many problems with it.
I wish we could rewind back several months of work, and use plain Java and Android API.
As we finished coding all the features required, and tested the app with CAN-bus software simulator, we shipped the app to the customer. This is where testing has started using real hardware.
The problem that we observed was Xamarin's garbage collector...
We used separate thread for exchanging data between the app and BT adaptor.
Every time Mono runtime ran a garbage collector - bluetooth connection would get lost.
The app knew how to reconnect to BT adaptor gracefully, but everytime connection was lost and established again - a toast would pop-up displaying corresponding message, and that would happen too often and annoy an app user.
So why would GC shutdown a bluetooth connection in the app?
And why did not we observe such behavior using simulator?
We did not observe it with simulator, because real hardware was sending a lot more data packets at higher speed.
So with simulator we only tested the correctness of data protocol, but not the high bandwith.
Basically with simulator we did not have GC running so often, and did not observe an issue.
Returning back to the first question - why would GC do such bad things for us?
We tried all three types of Xamarin GC currently available: tarjan, new and old. Nothing helped...
Then we just started to review code over and over again, trying to understand what went wrong.
The problem was that connection was created in one thread, and all data exchange was performed in the other thread.
Once we moved connection creation and data exchange logic to same thread - the problem disappeared.
I should mention that it was not due that we lost reference to connection object somehow and it would automatically get disposed, or other known issues of managed runtime.
App would simply throw an exception having java.io.IOException under the hood saying that read() method returned -1.
I'm not sure if it is a limitation of Android platform, or some specifics of Xamarin runtime on top of Android.
But if you guys face same issue with Xam, I hope this post will save you several days.
On my current job one of the projects is a mobile (android) app which connects via bluetooth to vehicle CAN-bus, gathers some info, sends that info to backend, backend performs some statistics calculations and displays results to end user.
I must admit that we should not have used Xamarin at all, as we faced so many problems with it.
I wish we could rewind back several months of work, and use plain Java and Android API.
As we finished coding all the features required, and tested the app with CAN-bus software simulator, we shipped the app to the customer. This is where testing has started using real hardware.
The problem that we observed was Xamarin's garbage collector...
We used separate thread for exchanging data between the app and BT adaptor.
Every time Mono runtime ran a garbage collector - bluetooth connection would get lost.
The app knew how to reconnect to BT adaptor gracefully, but everytime connection was lost and established again - a toast would pop-up displaying corresponding message, and that would happen too often and annoy an app user.
So why would GC shutdown a bluetooth connection in the app?
And why did not we observe such behavior using simulator?
We did not observe it with simulator, because real hardware was sending a lot more data packets at higher speed.
So with simulator we only tested the correctness of data protocol, but not the high bandwith.
Basically with simulator we did not have GC running so often, and did not observe an issue.
Returning back to the first question - why would GC do such bad things for us?
We tried all three types of Xamarin GC currently available: tarjan, new and old. Nothing helped...
Then we just started to review code over and over again, trying to understand what went wrong.
The problem was that connection was created in one thread, and all data exchange was performed in the other thread.
Once we moved connection creation and data exchange logic to same thread - the problem disappeared.
I should mention that it was not due that we lost reference to connection object somehow and it would automatically get disposed, or other known issues of managed runtime.
App would simply throw an exception having java.io.IOException under the hood saying that read() method returned -1.
I'm not sure if it is a limitation of Android platform, or some specifics of Xamarin runtime on top of Android.
But if you guys face same issue with Xam, I hope this post will save you several days.