A lightweight, flexible network library for Android written in Kotlin. The Communication library provides a clean and intuitive API for handling network requests with support for LiveData, Flow, object deserialization, and pagination.
-
Multiple Response Types
- Support for LiveData responses
- Support for Flow responses
- Direct object deserialization
-
Android Architecture Components Integration
- Seamless integration with Android ViewModel and LiveData
- Coroutines and Flow support for reactive programming
-
Pagination Support
- Built-in pagination handling with Jetpack Paging 3 library
- Customizable page parameters
-
Flexibility
- Customizable headers and parameters
- Support for all HTTP methods
- Easy to configure base URL
-
Local Data Integration
- Support for caching and local data observation
- Callbacks for handling successful network responses
In your root settings.gradle file, add the JitPack repository:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
}In your app module's build.gradle file:
dependencies {
// Core module (required)
implementation("com.github.kmpbits.communication:communication-core:latest_version")
// Android-specific extensions (optional)
// Only if you need LiveData responses
implementation("com.github.kmpbits.communication:communication-android:latest_version")
// Pagination support (optional)
// Only if you need pagination functionality
implementation("com.github.kmpbits.communication:communication-paging:latest_version")
}Replace latest_version with the current release version from JitPack.
Create a client instance in your application class, a singleton, or your dependency injection setup:
val client = communicationClient {
baseUrl = "https://api.example.com"
// Optional: Add default headers
header(Header(HttpHeader.CONTENT_TYPE, "application/json"))
header(Header(HttpHeader.custom("custom-header"), "This is a custom header"))
}val response: CommunicationResponse = client.call {
path = "/users"
method = HttpMethod.Get
}.response()val user: User = client.call {
path = "/users/1"
}.responseToModel<User>()Retrieve data as a Flow with built-in state handling:
val userFlow: Flow<ResultState<User>> = client.call {
path = "/users/1"
parameter("include" to "details")
}.responseFlow()You can also customize the flow response behavior:
val usersFlow = client.call {
path = "/users"
method = HttpMethod.Get
}.responseFlow<List<User>> {
// Handle successful network response
onNetworkSuccess { users ->
// Save to local database
userDao.insertAll(users)
}
// Observe local data source
local {
observe { userDao.getAllUsers() }
}
}Using lifecycle-aware collection:
userFlow.observe(viewLifecycleOwner) { state ->
when(state) {
is ResultState.Loading -> showLoading()
is ResultState.Success -> showUsers(state.data)
is ResultState.Error -> showError(state.exception.message)
is ResultState.Empty -> showEmptyState()
}
}Using coroutines:
lifecycleScope.launch {
userFlow.collectLatest { state ->
when(state) {
is ResultState.Loading -> showLoading()
is ResultState.Success -> showUsers(state.data)
is ResultState.Error -> showError(state.exception.message)
is ResultState.Empty -> showEmptyState()
}
}
}Easy integration with Android's Paging 3 library:
val pagedUsers: Flow<PagingData<User>> = client.call {
path = "/users"
parameter("size" to 20)
}.responsePaginated {
// Use API-only pagination or combine with local storage
onlyApiCall = true
// Customize the page parameter name (default is "page")
pageQueryName = "page"
// If using local storage (when onlyApiCall = false)
pagingSource { userDao.getPagingSource() }
deleteAll { userDao.deleteAll() }
insertAll { users -> userDao.insertAll(users) }
// Optional: Optimize initial loading state
firstItemDatabase { userDao.getFirstUser() }
}// Observe loading states
lifecycleScope.launch {
adapter.loadStateFlow.collectLatest { loadState ->
// Handle refresh loading state
binding.progressBar.isVisible = loadState.refresh is LoadState.Loading
// Handle refresh error state
if (loadState.refresh is LoadState.Error) {
val error = (loadState.refresh as LoadState.Error).error
showErrorMessage(error.message)
}
}
}
// Add loading footer
recyclerView.adapter = userAdapter.withLoadStateFooter(
footer = LoadingStateAdapter(
retry = { userAdapter.retry() }
)
)client.call {
path = "/secure-endpoint"
header(Header(HttpHeader.custom("X-Custom-Header"), "CustomValue"))
}.responseFlow<SecureData>()client.call {
path = "/users"
parameter("role" to "admin")
parameter("active" to true)
}.responseFlow<List<User>>()The library provides several ways to handle errors:
try {
val response = client.call {
path = "/might-fail"
}.responseToModel<Data>()
} catch (e: stateTalkException) {
// Handle stateTalk errors
when (e) {
is NetworkException -> // Handle network errors
is SerializationException -> // Handle parsing errors
is HttpException -> {
// Access HTTP error details
val statusCode = e.code
val errorBody = e.errorBody
}
}
}Contributions are welcome! Feel free to open issues or submit pull requests.
- Fork the project
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.