DEV Community

Daniel Ioni
Daniel Ioni

Posted on

Building an Android App with Kotlin, Retrofit, and Coroutines: A Practical Guide

Building an Android App with Kotlin, Retrofit, and Coroutines: A Practical Guide

Introduction

In this article, I'll share my experience building a production-ready Android app for MyZubster, an open-source skill exchange platform. I'll cover the key architectural decisions and code patterns I used.

Tech Stack Overview

Component Technology
Language Kotlin
Networking Retrofit + OkHttp
Async Coroutines + Flow
UI Material Design + ViewBinding
Storage SharedPreferences (Token)
QR Code ZXing
Architecture MVVM + Repository Pattern

1. Authentication & Token Management

I implemented JWT-based authentication with automatic token injection.


kotlin
// TokenManager.kt
class TokenManager(context: Context) {
    private val prefs = context.getSharedPreferences("MyZubsterPrefs", Context.MODE_PRIVATE)

    fun saveAuthData(token: String, userId: String, email: String, name: String) {
        prefs.edit().apply {
            putString("jwt_token", token)
            putString("user_id", userId)
            putString("user_email", email)
            putString("user_name", name)
            apply()
        }
    }

    fun getToken(): String? = prefs.getString("jwt_token", null)
    fun isLoggedIn(): Boolean = !getToken().isNullOrEmpty()
}
2. Networking with Retrofit

I used Retrofit with an AuthInterceptor to automatically add the JWT token to requests.
kotlin

// AuthInterceptor.kt
class AuthInterceptor(private val tokenManager: TokenManager) : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        val token = tokenManager.getToken()

        val newRequest = if (!token.isNullOrEmpty()) {
            request.newBuilder()
                .header("Authorization", "Bearer $token")
                .build()
        } else {
            request
        }

        return chain.proceed(newRequest)
    }
}

3. Booking History with Pagination

I implemented a RecyclerView with pagination using the Repository pattern.
kotlin

// BookingHistoryViewModel.kt
class BookingHistoryViewModel : ViewModel() {
    private val _bookings = MutableStateFlow<List<BookingHistory>>(emptyList())
    val bookings: StateFlow<List<BookingHistory>> = _bookings.asStateFlow()

    private var currentPage = 1
    private var hasMoreData = true

    fun loadBookings(userId: String, page: Int = 1) {
        viewModelScope.launch {
            try {
                val response = repository.getBookingHistory(userId, page, 10)
                if (response.isSuccessful) {
                    _bookings.value = response.body()?.data ?: emptyList()
                    currentPage = response.body()?.pagination?.page ?: 1
                }
            } catch (e: Exception) {
                // Handle error
            }
        }
    }
}

4. QR Code Generation

For Monero payments, I integrated QR code generation for payment addresses.
kotlin

// PaymentActivity.kt
fun generateQRCode(address: String): Bitmap {
    val writer = QRCodeWriter()
    val bitMatrix = writer.encode(address, BarcodeFormat.QR_CODE, 200, 200)
    val bitmap = Bitmap.createBitmap(200, 200, Bitmap.Config.RGB_565)

    for (x in 0 until 200) {
        for (y in 0 until 200) {
            bitmap.setPixel(x, y, if (bitMatrix[x, y]) Color.BLACK else Color.WHITE)
        }
    }
    return bitmap
}

5. Session Management with Countdown

I implemented a session timer that shows remaining time in the UI.
kotlin

// SessionManager.kt
class SessionManager(private val context: Context) {
    fun getSessionCountdown(callback: (String) -> Unit) {
        Thread {
            while (isSessionValid()) {
                val remaining = tokenManager.getSessionRemainingTime()
                val formatted = formatTime(remaining)
                Handler(Looper.getMainLooper()).post {
                    callback(formatted)
                }
                sleep(1000)
            }
        }.start()
    }
}

Key Takeaways

    Use Repository Pattern - Separates data sources from UI logic

    Implement AuthInterceptor - Automates token injection

    Use StateFlow - For reactive UI updates

    Handle Pagination - For efficient data loading

    Session Management - Improves user experience

Resources

The full project is open-source and available on GitHub:

DanielIoni-creator/MyZubsterAPP

Follow me on GitHub: DanielIoni-creator
Enter fullscreen mode Exit fullscreen mode

Top comments (0)