Please consider leaving a donation if you appreciate this information. Lightning network now available
I’ve been working through an Android dev course on Udemy and as a result, I just published my first app to the Google Play store. I wanted to take a few moments to chronicle the learning experience and the challenges that I came across in building this app.
Here’s the finished product. In a nutshell, it’s a wrapper for the Atlas Obscura website. It shows all of the places on a map with a contextual popup window when tapping any given map marker and tapping on that info window will take you to the page for that particular place on the Atlas Obscura website.
Here are some of the problems that I encountered and how I solved them.
Sourcing Data
AO doesn’t provide any kind of an API so simply making API calls was a non-starter. However, a google search turned up an “unofficial” REST API for the website. That API lacks the kind of structure that I would require for what I was trying to do, but it did provide data that was reliably and consistently formatted and I could work with and manipulate to suit my needs. I ended up building a JavaScript app with node.js to make API calls on a timer (to avoid being rate-limited by the API) and then parsing the results of those requests and inserting them into a database. During that process, I discovered several issues with the API so had to fix those which led to me needing to learn how to deploy an app to heroku (which I really can’t even explain what that is) and I needed to apply fixes (so I had to figure out a bit of Python as well) and deploy the fixes to my own instance of the API.
How to Deal With Markers
With nearly 13,000 rows in a database, I now had to figure out the most optimal way to display them on the map. I suppose there are many different approaches to this but given my goal of showing all the spots, I went with a clustering solution. Google provides a really slick library for that and it’s well documented and turned out to be relatively easy to implement. So that was settled, or so I thought. Turns out that the library doesn’t really work too well with 13,000 markers and I’ll get to that later.
Presenting Contextual Information
By default, when creating a map marker, you can set a title and a “snippet” which is a bit of extra information. The title and snippet are displayed when the marker is tapped, but there are limits to this approach as you can’t really provide much in the way of formatting that information. Enter custom info windows. Getting through that took several visits to Stack Overflow and eventually I found an example that I understood and was able to get that working in a way that I understood.
Extracting and Representing Data
Up to this point, I had just been creating “dummy” markers with a loop and setting the information on them with a corresponding number to where they were in the loop. I hadn’t actually begun the course content that dealt with reading/writing data to a database. I had to back up and go back to the course and complete that part of the course. I found myself a bit disappointed and ended up back on Stack Overflow to figure out what I needed to figure out. Also, android apps use SQLite while I am accustomed to MySQL. I was a bit intimidated but all in all, the transition was easy even though I don’t really understand some of the nuances vs. MySQL.
Android has some great utilities for creating/writing/reading databases but so far as I know there’s nothing included to use a pre-populated database which is what my app would be using. I was stuck with either having to build something for my app to call and request data or figure out how to work with pre-existing data within the app itself. I ended up using the Android SQLiteAssetHelper which works quite well and is thus far the only external tool that I implemented but haven’t needed to open an issue on GH for. With that sorted and now real live data to work with on to the next challenge.
Performance
Remember way back there when I mentioned that the included clustering library didn’t end up working? Well, here we are. With those nearly 13,000 rows of data, clustering wasn’t working nearly as smoothly as I would hope and in fact in some cases, it was downright awful. Keeping in mind that I am on higher end hardware than the average android user, this was quite concerning. I was able to find an alternative clustering library which fixed the performance problems. If you’re interested in faster marker clustering, that library can be found here. It does have its own quirk for which I have opened an issue, but it’s really more an annoyance than anything, I can live with it.
Starting Over
Well, not completely from scratch, but pretty damn close. The clustering library that I ended up using to fix the performance problems completely wrecked my info window implementation. I had to get a bit creative to get that working again but the short story is that aside from the code I had written to access the data from the database, everything else had to be re-written.
Deployment
The bulk of projects like this that I dive in to usually end up as nothing more than having their aggregate results displayed to me in the form of a “low disk space” warning and I honestly didn’t believe this one would be much different. If I could build something that suited my needs that was good enough for me but I had a bit of encouragement so I decided to go for it.
One of the main reasons that I rarely release any of my work is that a release usually requires artwork of some kind and I a) suck at visual arts and b) simply can’t be bothered. Luckily, there are some tools for generating artwork for the Google Play store. I found this: https://www.norio.be/android-feature-graphic-generator/ and this: https://romannurik.github.io/AndroidAssetStudio/icons-launcher.html which generated artwork that was good enough for me.
The other thing about deploying this particular app was a failure to understand how app signing works on the Google Play store, and specifically when you choose to use the Google Play App Signing and you are also using a Google Maps API Key and have it restricted by signature. This caused the live version of the app to not be able to load the map at all. How embarrassing. Eventually, I found the solution to this and got that sorted.
Details
In my development environment, I had been developing for whatever the current version of android is. I failed to take in to account that not everyone has a brand new phone. I also failed to understand that android updates don’t work the same way that iOS updates do in that it’s up to the device manufacturer to roll out updates for their phones and oftentimes devices will remain on the same android version that they shipped with. This is a bit of a vexation to me, but the result is that I ended up with a relatively huge number of reports that people couldn’t install the app. This was solvable but did require a bit of extra work to figure out how to conditionally call functions based on the android version. I’ll definitely keep this one in mind if I ever decide to pursue future projects.
Conclusion
I really enjoyed building this and I am happy with the end result. It does everything that I wanted it to do and I have already generated a pretty big to-do list for future updates. I am also continually impressed with the Android Developer Studio as an IDE. If you can kind of guess the name of a function that you want to access, you can usually find it just by typing a few letters of how you think it might be called. It provides some great contextual help.
Please consider leaving a donation if you appreciate this information. Lightning network now available
Leave a Reply
You must be registered and logged in to post a comment.