Migrating Android Apps from Java to Kotlin

We see teams with tens of thousands of lines of Java getting stuck on the transition to Kotlin. Google officially announced that new Jetpack APIs—`Paging 3`, `DataStore`, `WorkManager` with coroutines, Jetpack Compose—have a Kotlin-first surface <cite>Google's Kotlin-first initiative</cite>. Technic

Development and support of all types of mobile applications:

Information and entertainment mobile applications
News apps, games, reference guides, online catalogs, weather apps, fitness and health apps, travel apps, educational apps, social networks and messengers, quizzes, blogs and podcasts, forums, aggregators
E-commerce mobile applications
Online stores, B2B apps, marketplaces, online exchanges, cashback services, exchanges, dropshipping platforms, loyalty programs, food and goods delivery, payment systems.
Business process management mobile applications
CRM systems, ERP systems, project management, sales team tools, financial management, production management, logistics and delivery management, HR management, data monitoring systems
Electronic services mobile applications
Classified ads platforms, online schools, online cinemas, electronic service platforms, cashback platforms, video hosting, thematic portals, online booking and scheduling platforms, online trading platforms

These are just some of the types of mobile applications we work with, and each of them may have its own specific features and functionality, tailored to the specific needs and goals of the client.

Showing 1 of 1All 1734 services
Migrating Android Apps from Java to Kotlin
Complex
from 2 weeks to 3 months

Our competencies:

Frequently Asked Questions

Latest works

  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    894
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    1002
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    597

We see teams with tens of thousands of lines of Java getting stuck on the transition to Kotlin. Google officially announced that new Jetpack APIs—Paging 3, DataStore, WorkManager with coroutines, Jetpack Compose—have a Kotlin-first surface Google's Kotlin-first initiative. Technically they can be called from Java, but with so many adapters and workarounds that productivity drops. In a typical project, 30% of code is getters, setters, and null-checks; during migration to Kotlin, that volume shrinks 2–3 times. But Android Studio's auto-converter gives only a syntactic translation, not an architectural one. We help you migrate without stopping development and without losing stability. Contact us for a preliminary work estimate.

Why You Can't Just Click "Convert Java File to Kotlin"

Android Studio can convert Java files to Kotlin automatically. The result technically compiles. But it's not Kotlin; it's a transliteration of Java into Kotlin syntax:

  • var everywhere instead of val — no immutability
  • !! on every null reference — NullPointerException is just renamed to KotlinNullPointerException
  • No data classes — the same POJOs with getters through field.get()
  • object and companion objects are absent — static methods float around as extensions
  • No coroutines — AsyncTask or RxJava remain
  • Lambdas look like Java 8 lambdas, but without SAM conversion for custom interfaces

Such code gives none of Kotlin's advantages, only adds confusion. The auto-converter is a tool to start, not to finish.

What a Proper Migration Looks Like

Inventory Before You Start

The first step is a full audit of the codebase: number of classes by type (Activity, Fragment, ViewModel, Repository, Model, Util), test coverage, list of actively developed modules vs. stable ones, dependencies on Kotlin-incompatible patterns (e.g., finalize(), certain patterns with static inner classes).

Based on the audit, we build a plan: which files to convert first, which to touch last, and where parallel development on Java continues during migration.

Bottom-Up Strategy

Start with classes that have no Android dependencies: data models, utilities, constants. A Java POJO with fields, getters, and setters becomes a Kotlin data class — instant benefit: equals(), hashCode(), toString(), copy() for free.

// Before: Java POJO, 60 lines with getters/setters // After: data class UserProfile( val id: Long, val name: String, val email: String, val avatarUrl: String? = null ) 

Then move to the Repository layer. The key decision here is how to handle async code. If the project used RxJava, there are two paths: keep RxJava (Kotlin works great with RxJava) or migrate to coroutines + Flow. The second path is strategically better but more expensive in the moment. For actively developed repositories, we go with coroutines; for stable modules without changes, we leave RxJava until the next major refactoring.

Migrating from LiveData to StateFlow

ViewModel layer: LiveDataStateFlow + SharedFlow. This is not mandatory; LiveData works in Kotlin too, but StateFlow behaves more predictably — no magic with LifecycleOwner, no observeForever leaks, no setValue vs postValue confusion. The replacement happens in three steps: change the field type, adapt subscriptions in fragments, update tests.

Activity and Fragment are migrated last. They have the most dependencies, the most legacy code, and errors there are the most costly.

Handling Java-Kotlin Interop

Until migration is complete, Java and Kotlin classes live side by side. Kotlin calls Java without issues. Java calls Kotlin — annotations are needed:

  • @JvmStatic for companion object methods needed from Java
  • @JvmField for fields without getters
  • @JvmOverloads for functions with default parameters
  • @Throws(IOException::class) if a Kotlin function throws checked exceptions

Ignoring these annotations is a common reason why auto-converted code doesn't compile from neighboring Java files.

Testing During Migration

Every converted class must pass existing tests unchanged — this guarantees the conversion didn't break logic. If tests were missing, this is the moment to write them, before conversion, while the logic is still clear from Java code. We use JUnit5 + MockK (for Kotlin classes) or Mockito (if Java test compatibility is needed).

CI must run tests on every PR. Migration without CI is chaos: you can't track which commit broke logic.

Example of a full file conversion

Suppose we have a Java class UserRepository with methods using Callback. After migration to Kotlin with coroutines, it becomes:

class UserRepository(private val api: UserApi) { suspend fun getUser(id: Long): Result<User> = runCatching { api.getUser(id) } } 

What Else Changes Along the Way

During migration, it makes sense to address accumulated technical debt: replace AsyncTask (deprecated since API 30) with coroutines, migrate from SharedPreferences to DataStore, update Retrofit to version with Kotlin suspend functions instead of Call<T>.

But "along the way" doesn't mean "all at once". Each such change risks regression. We compile an explicit list of "what we do within the migration"; everything else goes into the backlog for upcoming sprints.

Module Priority for Migration

Module Priority Rationale
Models and utilities High No framework dependencies, safe to convert
Repositories Medium Depends on async library, requires refactoring
ViewModel Medium LiveData → StateFlow, tests need rewriting
Activity/Fragment Low Many dependencies, errors are costly

What's Included in the Migration Work

  • Codebase audit: volume assessment, test coverage, complex spots
  • Staged conversion plan with priorities and timelines
  • Writing tests for critical modules before conversion
  • Manual architectural improvement (coroutines, data classes, null safety)
  • Training the team in Kotlin patterns and new APIs
  • Post-migration support: code review, interop refinement, performance optimization

Timelines

They depend on codebase size, test coverage, and whether parallel feature development is ongoing.

Codebase Test coverage Estimate
Up to 20,000 lines of Java Good (>60%) 2–4 weeks
20,000 – 60,000 lines Partial 4–8 weeks
60,000+ lines Low 2–4 months

The estimate is refined after the audit. Cost is calculated individually.

Migration is an investment. A team working on Kotlin with coroutines and StateFlow closes tasks faster than the same team on Java with RxJava. Not because Kotlin is magically better, but because there's less boilerplate, better analysis tools (KSP vs KAPT, Kotlin lint rules), and the library ecosystem no longer resists. Write to us for a specialist consultation and a preliminary project estimate.

We are a team with 7 years of Android development experience, having completed over 30 Java-to-Kotlin migration projects. Order a code audit and we will prepare a detailed transition plan.