AI technology is advancing faster than any technology in history and there is reason to be excited, especially when it comes to programming. Things are advancing so quickly that my experience of trying to build an Android App using Gemini are already obsolete! In a way this serves as a historical post about the state of Gemini and Android apps with Kotlin as of the early summer of 2025 before the Narwhal release! Stay tuned for an update that includes the Narwhal upgrades.
My goal in the Spring and early summer of 2025 was to see if it was possible yet, to develop an Android app only using Gemini. The plan was to play the role of a computer literate power user who is not a programmer and see if Gemini could build me an Android App entirely from scratch. In effect, I was going to "Vibe Code" the app and finally achieve the dream of code free application development. At the time, the phrase Vibe Coding was just gaining traction, but regardless of timing the real-world pros and cons of a Vibe Coding approach will persist for a while and the experience is still relevant.
One very important rule I imposed was that I was only allowed to use Gemini as a resource and I wasn't allowed to modify the code by myself at all. At the time, I could only copy code back and forth between Gemini and Android Studio. Android Studio has since released the "Narwhal Feature Drop" (officially on July 31st 2025) and the very first item on the list of improvements is "Gemini in Android Studio - Agent Mode" which in theory solves some of the problems I experienced. More importantly, it speaks to just how fast AI and Vibe Coding is evolving.
The first step in my AI assisted adventure was to ask Gemini "How do I build an Android app from scratch?" As a power user, it wasn't difficult to dutifully follow the steps Gemini outlined for me to set up Android Studio and the SDK. Just like that, I was now in the world of the latest Kotlin development and ready to go.
Now for the fun part. I needed an idea for an app to build. Since my son is in junior golf, I decided to build a simple golf scorecard app. In addition to keeping score, it would also suggest clubs based on his distances and let him track additional data he uses to improve his game.
With that, I had everything I needed (in theory), Android Studio an idea for an app and Gemini. As I started asking Gemini questions it figured out that it was assisting me in developing an application and switched from the standard chat based UI into an interactive code review UI which was an early version to what has been renamed now to "Agent Mode." The chat was on the left side and the code was on the right. It was very nice. As I came back to the application over the course of several days however, I never figured out exactly how to force it to switch to that mode. Sometimes it never did which was frustrating.
The first thing I noticed as I started using code Gemini gave me, is that it would on occasion have errors including small typos like missing braces. I had to restrain the coder in me from just quickly fixing these errors. Instead, I copied the code back into Gemini and gave it the error message. Gemini would then fix the error, add the missing braces or punctuation and I would paste the revised code back into the IDE. Overall, it was a terribly inefficient way to operate. The good news is that when told it made a mistake, Gemini was almost always able to fix it on the first try. Only on a few occasions did it take more than one attempt to fix the small syntax errors.
While syntax errors were fine, when it came to providing the layout for the screens, things got a little bit maddening. With each small layout change, Gemini would regenerate all of the code. Since it wasn't integrated into the IDE at the time, it had no capacity to break the code into modules or understand the relationships between modules. Instead, I was pasting in all of the code, telling Gemini how I wanted to change it and then Gemini was processing the code and regenerating the entire code base back to me.
Gemini would often "forget" features of the layout it had previously fixed as well. I'd have to go back and ask for the same changes again and again and again. For example, I would have it remove some whitespace and then a few changes later the whitespace was back and I'd have to have it remove the whitespace again presumably because the whitespace is "standard."
Another rule I used in this little experiment was to never call anything by the correct technical name. I just spoke plain "power user" English. Once Gemini responded to my request with the correct technical name for something, then I could use that name. For example, I had a "slider tool" to easily select the distance from the golf ball to the flag, so the app could suggest a club to use. I told Gemini to "change the color on the left side of the slider" and Gemini responded that it had "changed the Active part of the slider." Now that Gemini told me that was called the Active part of the slider, I could refer to it using the correct term going forward. It was interesting and impressive that Gemini was able to correctly handle my English description of layout components.
Gemini was so good at recognizing the layout components, I could have "normal" conversations to ask it about something in the screen "we" were developing without needing elaborate prompting. For example, here is a summary of one conversation I had with the Gemini. The Gemini responses are highly "summarized" for the sake of brevity in this article, but it gives you an idea of the process.
Me: "Why is there a white border."
Gemini: "Because of a border modifier."
Me: "OK, remove that."
Gemini: <new code>
Me: "The border is still there."
Gemini: "It’s because of padding in the main column."
Me: "OK remove that too."
Gemini: <new code>
The fact that Gemini would rewrite the ENTIRE code base for each change based on me telling it to "remove that" was both a blessing and a curse. As programmers know, there are times when you have a big change to an app and you get that sinking feeling in your stomach because you think "oh no, that's going to be a lot of refactoring." With Gemini, it wasn't a problem at all. If I decided to make a "big" change that I would have absolutely hated as a programmer, Gemini just happily churned away and refactored everything. I absolutely LOVED that experience. Of course, the downside is that when I told it to make a small change like "Center that number" it also regenerated hundreds of lines of code and took the same amount of time. Thankfully with the integration of Gemini into the IDE, there is hope that we will retain the ability to easily do massive refactoring, but also make smaller changes without rewriting everything since Gemini will have the context of the project within the IDE.
By far my biggest frustration in the whole process was that Gemini routinely used deprecated features or implemented libraries incorrectly. I'm not sure why it did this, but each time it did, I fed the errors back to Gemini. It would eventually recognize the problem, apologize and deliver an alternative implementation. On several occasions it forgot about the deprecated features it had just fixed and then re-implement the same deprecated feature. For example, this error: MainActivity.kt:99:20 'var statusBarColor: Int' is deprecated. Deprecated in Java. resulted in Gemini returning the following response along with a new set of code: "Oh you’re right let’s update it to use the recommended handling for Compose." However, that update created a situation with an Unresolved reference 'BEHAVIOR_SHOW_TRANSIENT' which Gemini then fixed... by reimplementing the same deprecated feature we had just fixed. I tried a few times to just feed it the same errors, but it was essentially stuck in a perpetual loop. The solution was for me to prompt Gemini to fix the BEHAVIOR_SHOW_TRANSIENT error using non-deprecated features.
Likewise, when Gemini implemented certain features incorrectly, I could give it the errors and it was often able to figure out what had gone wrong and provide a great explanation. For example, Gemini had implemented listSaver to meet one of my requirements but it created an error. When fed the error Gemini replied: Okay, I've updated the code to address the "Destructuring of type 'kotlin.Any' requires operator function 'component1()'" error. This error occurs because listSaver returns a single Any type, and we're trying to destructure it as if it were a pair or a list. I'll correct the way we handle the saved data within the listSaver. Another great feature is if you provide Gemini with multiple errors at the same time, it does a good job of resolving all of the errors provided.
With all that said, the farther I went along the path of developing the app, the less I believed a "power user" would succeed. For example, adding gson capabilities caused a lot of grief. I had to explain what was happening to get the updated libs.version.toml and build.gradle.kts, but Gemini did manage to do it after I kind of broke my rule and gave it a little "programmer hint" so we could move on.
Finally, I got to "the wall." There was a limit to what Gemini could do in this power user, non-programmer approach. Since it was generating all the code as one giant block, once the code increased beyond a certain number of lines, it took Gemini too long to read it and figure out a response. Gemini would time out and tell me "something went wrong." At the time, the paid version of Gemini might have helped solved this, but processing timeouts are a limitation within all versions. With the latest version of Android Studio which contains Gemini integrated into the IDE, there are still timeouts but since code can be broken apart and Gemini has the full context of the application, there are ways to work around this. I will pick up this little project again using the latest feature drop with Gemini directly integrated into the Android Studio IDE and report back shortly with a follow up article.
For this version, while it's true I had hit a technical wall, I had also done what I set out to do. I wanted to see the state of the technology regarding Vibe Coding and share it with you, our valued reader. The reality at least currently, is that we still need "coders" who are using AI as an assistant rather than relying entirely on AI to build the code from what we tell it. We still need "software engineers" working within the IDE who have technical expertise. Gemini and other AI tools can help with each module and certainly do a good job at resolving errors and doing "grunt work" but as of now, Gemini isn't quite far enough along to build entire apps relying only on user prompting.
It's clear that the role of a "computer programmer" is changing and the future of AI is very promising. AI is making programming faster by eliminating the need to convert detailed logical steps into code and quickly solving errors. It's eliminating the friction between business requirements and technical glitches that get in the way. It's safe to say that the summer of 2025 is the last summer that it still took solid programming skills to build a usable Android application. By next year, it will be a much more conversational experience. If we're really lucky, 2026 may be the first year where the title "Software Engineer" feels like it actually fits because the "programmer" doesn't have to focus so much effort on churning out code.
These Stories on Development
121 Washington Ave N, 4th Floor
Minneapolis, MN 55401
L2, 1 Post Office Square
Wellington 6011
119 Willoughby Road
Crows Nest NSW 2065
No Comments Yet
Let us know what you think