Fetching and displaying JSON data from a server is a fundamental requirement in modern Android apps. Whether it’s news feeds, API responses, or remote configuration, JSON (JavaScript Object Notation) remains the most widely used data format for RESTful APIs.
This updated guide on javatechig.com explains how to implement a JSON feed reader in Android using robust networking, parsing, and UI handling techniques with both Kotlin and Java.
What Is a JSON Feed Reader?
A JSON feed reader in Android:
- Sends HTTP requests to a server
- Receives JSON responses
- Parses the JSON into usable objects
- Renders data in UI components like RecyclerView
Modern Android applications should use lifecycle-aware networking and asynchronous tasks to ensure smooth performance and responsiveness.
Choosing the Right Networking Library
Shared modern options:
1. Retrofit (Recommended)
- Type-safe HTTP client
- Built-in JSON support
- Works well with coroutines
2. OkHttp
- Low-level HTTP client
- Suited for custom networking
3. Volley
- Good for quick requests
- Less flexible than Retrofit
This guide focuses on Retrofit with Gson because it balances simplicity and power.
Step 1 — Add Dependencies
In build.gradle:
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
Also add:
implementation 'androidx.recyclerview:recyclerview:1.3.1'
Step 2 — Define JSON Data Model
Assuming the JSON feed:
[
{
"title": "First Article",
"description": "Description here",
"imageUrl": "https://example.com/image.jpg"
}
]
Kotlin Data Class
data class FeedItem(
val title: String,
val description: String,
val imageUrl: String
)
Java Model Class
public class FeedItem {
private String title;
private String description;
private String imageUrl;
// getters and setters
}
Step 3 — Create Retrofit API Interface
interface ApiService {
@GET("feed.json")
suspend fun fetchFeed(): List<FeedItem>
}
For Java with Callbacks:
public interface ApiService {
@GET("feed.json")
Call<List<FeedItem>> fetchFeed();
}
Step 4 — Initialize Retrofit
Kotlin
val retrofit = Retrofit.Builder()
.baseUrl("https://your-api-domain.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()
val api = retrofit.create(ApiService::class.java)
Java
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://your-api-domain.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
ApiService api = retrofit.create(ApiService.class);
Step 5 — Fetch JSON Feed
Kotlin (Coroutines)
lifecycleScope.launch {
try {
val feed = api.fetchFeed()
adapter.submitList(feed)
} catch (e: Exception) {
Log.e("JSONFeed", "Error: ${e.localizedMessage}")
}
}
Java (Callback)
api.fetchFeed().enqueue(new Callback<List<FeedItem>>() {
@Override
public void onResponse(Call<List<FeedItem>> call, Response<List<FeedItem>> response) {
adapter.setData(response.body());
}
@Override
public void onFailure(Call<List<FeedItem>> call, Throwable t) {
Log.e("JSONFeed", "Error: " + t.getMessage());
}
});
Step 6 — Display Data in RecyclerView
Create an adapter that binds FeedItem objects to a RecyclerView.
Kotlin Adapter Snippet
class FeedAdapter : ListAdapter<FeedItem, FeedAdapter.ViewHolder>(DiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ItemFeedBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(getItem(position))
}
}
Bind data in the view holder with image loaders like Glide or Coil for performance.
Handling Errors & Edge Cases
1. API Failure or No Internet
Show a retry UI and message:
- Display Snackbar or Toast
- Provide retry button
2. Empty Response
Show a placeholder or “No items available”.
3. JSON Parsing Errors
Ensure model matches API structure. Use @SerializedName where necessary.
Best Practices (2026 Updated)
- Use Retrofit + Gson/Moshi
- Use coroutines with LiveData or Flow
- Avoid networking on the main thread
- Cache responses with OkHttp cache
- Use pagination for large feeds
- Secure API calls with HTTPS
Performance Considerations
- Load images with Glide/Coil asynchronously
- Use DiffUtil in RecyclerView adapters
- Avoid heavy UI operations on bind()


