iOS and Server Error Fix Plus Potential Major Speed Increase #11
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Background
A while back, I noticed that my tile server periodically would accumulate "CLOSE_WAIT" states, resulting in a gradual slowing and eventual need for a reboot. Upon researching this topic, the overarching theme was that the client was not closing connections properly, leaving the server in a confused state:
The issue was rare enough I made a monitoring script on my server that would auto-reboot if CLOSE_WAIT count got too high.
I then turned to development on iOS as Android was mostly done.
iOS Restart Issue
My iOS app would run great on first install. But then if I killed it and restarted, when it came up, it would have many missing tiles and just slow in general. Common debugger errors (hundreds) included:
Sometimes I even got missing asset errors. This suggested file descriptor exhaustion.
Strangely, these errors only occurred on a physical iPhone. iOS simulators worked great, so did all my Android devices (aside from periodic CLOSE_WAIT issues seen on my server). The fix was to restart the app about 4 times, which must have cleared out "something" from memory. App would then work great, until next time. Rinse & repeat.
Initial Debugging
I decided to play around with local pub dev copy of tile_provider.dart and image_provider.dart, focusing on the closing of the connections. tile_provider.dart already had this:
but perhaps not all connections were being closed properly. I added a print statement, and noticed upon normal map usage, hundreds of prints, suggesting frequent creation and attempted closing of dio clients.
I had previously stumbled upon a Dart thread with similar errors, and they suggested using cupertino_http, and/or native_dio_adapter which includes that along with cronet for Android. Clearly dio was not playing nice with iPhones, so I gave it a shot.
I also hypothesized that maybe only a single dio client was actually needed, instead of creating and destroying constantly. That way, previously used resources could be reused.
Result
Success! Not only was I able to restart my iPhone app as frequently as I wanted with zero errors, but the tiles are FLYING IN.
At least for my app, it's night and day. Sometimes I can't even tell it's tiled, more like a seamless map. And when I zoom out quickly, instead of checker-board loading, they all load nearly simultaneously.
Who May Benefit (Most) & Testing
While more testing is needed, clearly anyone with the same errors I was experiencing on iPhones should test these changes.
After two days of usage, I have seen no ill effects. On the contrary.
It should be noted that in my application, I use MANY TIleLayer() at once (12+). Probably a somewhat rare amount, but it should work all the same.
Very few lines of code were needed as you can see. I import native_dio_adapter, created a singleton of dio, and removed the _dioClient.close(). In addition, I create a CancellableNetworkTileProvider instance once in initState and use _tileProvider in all of my tile layers:
It seems clear to me that at least for iOS, sometimes dio instances were not all getting closed properly. But this must have also been true for Android, just to a lesser extent, given my experience with CLOSE_WAIT on my tile server. Installing the native adapters fixed the file descriptors running out error on iPhone, and I'm guessing I will no longer get the server errors.
Errors aside, I am guessing that the more TileLayer() you have in your app, the more of a speed increase you will see.
I am eager to hear if this works for you!
PS: if this works well for everyone, you might also consider the same for NetworkTileProvider, which I do not currently use.