Mobile App Project 2 Milestone 4

For the second project of my Mobile App Development class this semester, I decided to create an Android version of MyBoulder (I created the iOS version for my first project). MyBoulder is an app that provides users with ideas of how to explore the area of Boulder, Colorado, from outdoor activities, urban highlights, or entertainment events. Users can select what types of activities they like, whether they are willing to do paid activities, and what season it currently is.

Screenshot_20191207-102454Screenshot_20191207-102513

After selecting their preferences, MyBoulder will generate an idea for the user including a title, description, image and address. If the user doesn’t like the idea that has been generated for them, they can either change their preferences or re-launch the generator with the same settings and a new idea will be generated.

Screenshot_20191207-102501Screenshot_20191207-102505

Overall, developing the Android version of MyBoulder was actually much more difficult and time-consuming than I anticipated, but I learned a lot about Android Studio and the differences between iOS and Android along the way. Read more about my experience and post-development reflections below!

What went well?

  • A huge perk of having already developed the iOS version of MyBoulder was that I already had all of the content for the app (my list of 35 ideas, all with descriptions, cropped images, and addresses). Additionally, I didn’t have to do as much creative design work for this version in terms of color palettes, fonts, etc., because I really liked my design for the iOS version and just had to reproduce that design in Android Studio.
  • Related to the above note: I knew when I was starting to copy over my ideas from XCode to Android Studio that I was about to do a ton of copying and pasting. However, I realized I could copy all of my Swift code into a text editor and use Find and Replace to essentially convert the code into Java, step-by-step! For instance, I changed the instances of let *ideaName* = Idea( in my Swift code to private Idea *ideaName* = new Idea( with the power of Find and Replace. I still had to manually change some things, but this saved me a ton of time converting my code!
  • Like with the first iteration of MyBoulder, investing a good amount of time into developing my pseudocode in the last phase of this project helped me develop the app much more quickly. Having the main logic worked out already allowed me to focus on correcting syntax and coding efficiently.
  • Once I was done coding most of MyBoulder’s functionality, I was able to test the Android version against the iOS version to make sure the idea generation algorithm was working correctly. I used Log.i() statements to output all the ideas that were generated for a certain set of user selections, and then compared the idea lists generated by the Android and iOS versions to make sure they were the same.
  • When it came time to develop a constraint layout for adapting to different devices and orientations, it wasn’t too hard to figure out how to use a scroll view for when the content was bigger than the screen. An added benefit of this was that the scroll view worked for landscape too, so I didn’t have to create a separate landscape layout (like I have done for past Android labs). Additionally, since all of my user inputs (switches and radio buttons) hold their state between orientation changes, I didn’t have to worry about saving and sending data for orientation transitions.
  • Since Android has a built-in back button, I ended up just using that for the “back to first screen” functionality instead of putting a back button in the app bar.

What didn’t go so well?

I quickly figured out that many things in Android are much more complicated (or maybe just less intuitive for me) than they are in iOS. Below, I explain some of the problems I faced.

First of all, figuring out how to send an instance of a custom class (I used an Idea class) between screens was difficult. I tried using different tutorials to convert my Idea class into a “Parcelable” class that could be sent between screens, but it was pretty complicated. I almost got it working, but ran into another error with the Parcelable .writeBoolean function, which didn’t work with my required minimum API level. Finally, I resorted to just extracting the strings (for idea title, description, address, and imageName) in the first activity and sending the strings themselves to the second activity (instead of sending the whole class instance and extracting strings in the second activity). This turned out to be a good, much less complicated solution and worked just fine.

In Android, it is also a bit harder to set image resources dynamically. In the iOS version of MyBoulder, I only needed one line of code to set each Idea’s image on the second screen of my app:

ideaPic.image = UIImage(named: generatedIdea.imageName)

In Android, things aren’t quite as simple because you need to find the image resource with an ID (something like R.drawable.*name*). Unfortunately, you can’t just concatenate your image name on to the end of this ID and find images that way, so one option is to just program a bunch of different if statements:

if(rImg.equals("buff")){
    restImage.setImageResource(R.drawable.buff);
} else if(rImg.equals("pub")){
    restImage.setImageResource(R.drawable.pub);
} else if(rImg.equals("rincon")){
    restImage.setImageResource(R.drawable.rincon);
} else if(rImg.equals("sc")){
    restImage.setImageResource(R.drawable.sc);
}

Obviously, for 35 different Idea/image pairs, this isn’t very efficient. I figured out another way, which uses this code:

ImageView ideaImage = findViewById(R.id.imageView);
int imageResource = getResources().getIdentifier(imageName, null, getPackageName());
Drawable img = getResources().getDrawable(imageResource);
ideaImage.setImageDrawable(img);

To get this to work, I just had to reconfigure all of the strings for imageName in my Idea instances. Instead of just being a keyword like “avery”, I changed them to the resource name, which was in the format of: “@drawable/avery”.

Additionally, I discovered that dealing with arrays is much more complicated in Java, because arrays have a fixed size and for anything more dynamic, you need to use an arrayList instead. There was a learning curve for this, but I eventually figured out the right syntax to get everything working. Similarly, random number generation is different and a little more complicated in Android.

When it comes to styling things, Android gives you a lot more finite control over some elements, but it can be really hard to find which code controls which component, whereas iOS kind of just does everything for you. For a long time, I tried to figure out how to make the background-track color of my switches blue when they were off (like in this prototype), but I made my peace with them being gray in the end.

Last, I ran into a bunch of weird errors where what I was seeing in the Design tab of my layout xml files wasn’t matching up with what was actually being rendered on the Emulator. I tried lots of things to fix this, like restarting Android Studio, cleaning the project, invalidating the cache, reinstalling the app, and others. Eventually, I just recreated my TextViews in the layout and the emulator worked – must have been a weird glitch. I also couldn’t get custom fonts to work for a long time, despite being sure that I was following the Android documentation correctly. When I installed my app on a real device, the fonts worked just fine, so I think it was just an issue with my emulator.

What would you do differently next time?

During this process, I wasted a lot of time trying to figure out the cause of glitches in Android Studio. I definitely learned some techniques to fight these glitches,  including:

  • Un-installing and re-installing the app on my emulator, or just running the app off of a physical device. This helped me avoid problems with my emulator not rendering correctly.
  • Cleaning the project – solves a lot of weird Android Studio issues! This is a good “first thing to try” whenever I run into bugs in the future.
  • For problems that really seem to want to stick around, I think restarting Android Studio itself, or invalidating the cache and restarting, can help sometimes.

Following some of these troubleshooting tactics the first time (instead of trying a bunch of other, unsuccessful things first) would have saved me a few hours of development during this project. Apart from those problems, most of the difficulty from creating the Android version of MyBoulder came from learning new procedures and syntaxes in Java.

Leave a comment