koush/ion
Android Asynchronous Networking and Image Loading
Stale — last commit 2y ago
weakest axisnon-standard license (Other); last commit was 2y ago…
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
last commit was 2y ago; no CI workflows detected
- ✓11 active contributors
- ✓Other licensed
- ✓Tests present
Show all 7 evidence items →Show less
- ⚠Stale — last commit 2y ago
- ⚠Single-maintainer risk — top contributor 86% of recent commits
- ⚠Non-standard license (Other) — review terms
- ⚠No CI workflows detected
What would change the summary?
- →Use as dependency Concerns → Mixed if: clarify license terms
- →Deploy as-is Mixed → Healthy if: 1 commit in the last 180 days
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Forkable" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/koush/ion)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/koush/ion on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: koush/ion
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/koush/ion shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
WAIT — Stale — last commit 2y ago
- 11 active contributors
- Other licensed
- Tests present
- ⚠ Stale — last commit 2y ago
- ⚠ Single-maintainer risk — top contributor 86% of recent commits
- ⚠ Non-standard license (Other) — review terms
- ⚠ No CI workflows detected
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live koush/ion
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/koush/ion.
What it runs against: a local clone of koush/ion — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in koush/ion | Confirms the artifact applies here, not a fork |
| 2 | License is still Other | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 857 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of koush/ion. If you don't
# have one yet, run these first:
#
# git clone https://github.com/koush/ion.git
# cd ion
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of koush/ion and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "koush/ion(\\.git)?\\b" \\
&& ok "origin remote is koush/ion" \\
|| miss "origin remote is not koush/ion (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(Other)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"Other\"" package.json 2>/dev/null) \\
&& ok "license is Other" \\
|| miss "license drift — was Other at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "ion/src/com/koushikdutta/ion/BitmapFetcher.java" \\
&& ok "ion/src/com/koushikdutta/ion/BitmapFetcher.java" \\
|| miss "missing critical file: ion/src/com/koushikdutta/ion/BitmapFetcher.java"
test -f "ion/build.gradle" \\
&& ok "ion/build.gradle" \\
|| miss "missing critical file: ion/build.gradle"
test -f "ion/src/com/koushikdutta/ion/BitmapCallback.java" \\
&& ok "ion/src/com/koushikdutta/ion/BitmapCallback.java" \\
|| miss "missing critical file: ion/src/com/koushikdutta/ion/BitmapCallback.java"
test -f "ion-kotlin/build.gradle" \\
&& ok "ion-kotlin/build.gradle" \\
|| miss "missing critical file: ion-kotlin/build.gradle"
test -f "README.md" \\
&& ok "README.md" \\
|| miss "missing critical file: README.md"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 857 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~827d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/koush/ion"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Ion is an Android library that simplifies asynchronous HTTP networking and image loading through a fluent, chainable API. It handles downloading images (including animated GIFs), JSON, files, and custom Java types via Gson, with built-in support for modern HTTP features (SPDY, HTTP/2, connection pooling, caching, gzip compression) and transparent lifecycle-aware request cancellation tied to Activity lifespan. Multi-module Gradle project: root build.gradle coordinates the build; ion-sample/ is a reference Android app demonstrating features (Twitter client, image galleries, file downloads); ion-kotlin/ is a separate Kotlin DSL wrapper with its own build.gradle and instrumented tests under ion-kotlin/test/src/. Core networking logic lives in the unnamed main module (inferred from file structure).
👥Who it's for
Android developers building apps that need to fetch remote data and images without blocking the UI thread; particularly those who want declarative networking syntax (e.g., Ion.with(context).load(url).intoImageView(imageView)) instead of manually managing AsyncTasks or Retrofit setup.
🌱Maturity & risk
Moderately mature but showing signs of slower maintenance. The codebase is stable (457K lines of Java, clear structure with sample apps), but the last visible activity in the file list references Android build tools v28.0.3 (2018 era). Kotlin support exists but is minimal (7K lines). No modern CI/CD files (.github/workflows) are visible; FUNDING.yml suggests the project is seeking sponsorship.
Moderate risk due to age and apparent single-maintainer status (koush). No visible test harness in the main codebase (only ion-kotlin/test/ exists), making refactoring dangerous. Dependencies on NIO and AndroidAsync create vendor lock-in. The last commit recency is unknown from provided data, but build config targets old Android API levels (28).
Active areas of work
Active development status is unclear from the provided snapshot. The presence of ion-kotlin/ with Kotlin coroutine support (mentioned in README) suggests recent modernization attempts, but no specific PRs, milestones, or recent commits are visible in the file list.
🚀Get running
git clone https://github.com/koush/ion.git
cd ion
./gradlew build
./gradlew :ion-sample:installDebug
Daily commands:
./gradlew :ion-sample:installDebug
adb shell am start -n com.koushikdutta.ion.sample/.MainActivity
Or import into Android Studio and run the ion-sample configuration.
🗺️Map of the codebase
ion/src/com/koushikdutta/ion/BitmapFetcher.java— Core image loading and fetching logic—handles bitmap retrieval, caching, and async operations that are central to the library's main feature setion/build.gradle— Primary build configuration defining dependencies (Gson, Android support), target SDK, and artifact publication settingsion/src/com/koushikdutta/ion/BitmapCallback.java— Callback interface for async bitmap operations—fundamental contract between request initiation and result deliveryion-kotlin/build.gradle— Kotlin extension module configuration enabling coroutine and suspend support, a major feature advertised in READMEREADME.md— Complete API documentation and usage examples; essential reference for understanding the fluent API design and supported content typesion/AndroidManifest.xml— Library manifest declaring required permissions (INTERNET, etc.) and lifecycle integrations for automatic cancellation on Activity finishCHANGELOG.md— Historical record of breaking changes and API evolution—critical for understanding deprecations and version migration paths
🛠️How to make changes
Add a new Image Loading Sample
- Create a new Activity class in ion-sample/src/com/koushikdutta/ion/sample/ (
ion-sample/src/com/koushikdutta/ion/sample/YourNewSample.java) - Extend the fluent API pattern: Ion.with(context).load(url).intoImageView(imageView) (
ion-sample/src/com/koushikdutta/ion/sample/YourNewSample.java) - Add a layout XML file in ion-sample/res/layout/ for your activity UI (
ion-sample/res/layout/your_new_sample.xml) - Register the activity in ion-sample/src/com/koushikdutta/ion/sample/Samples.java menu (
ion-sample/src/com/koushikdutta/ion/sample/Samples.java) - Declare the activity in ion-sample/AndroidManifest.xml (
ion-sample/AndroidManifest.xml)
Add Kotlin Coroutine Extension
- Create a new .kt file in ion-kotlin/ with suspend function wrapper (
ion-kotlin/src/com/koushikdutta/ion/kotlin/YourExtension.kt) - Use withContext(Dispatchers.IO) to wrap Ion async calls into suspend functions (
ion-kotlin/src/com/koushikdutta/ion/kotlin/YourExtension.kt) - Add instrumented test in ion-kotlin/test/src/ to verify suspend behavior (
ion-kotlin/test/src/com/koushikdutta/ion/kotlin/test/YourTest.kt) - Update ion-kotlin/build.gradle if new dependencies are needed (
ion-kotlin/build.gradle)
Add Support for a New Content Type
- Create a new Fetcher class in ion/src/com/koushikdutta/ion/ (e.g., CustomTypeFetcher.java) (
ion/src/com/koushikdutta/ion/CustomTypeFetcher.java) - Implement async fetching and caching following BitmapFetcher.java patterns (
ion/src/com/koushikdutta/ion/CustomTypeFetcher.java) - Create a Callback interface (e.g., CustomTypeCallback.java) similar to BitmapCallback.java (
ion/src/com/koushikdutta/ion/CustomTypeCallback.java) - Extend the fluent builder in the main Ion class to expose .asCustomType() (
ion/src/com/koushikdutta/ion/Ion.java) - Add a sample in ion-sample/ demonstrating the new content type (
ion-sample/src/com/koushikdutta/ion/sample/CustomTypeSample.java)
Add a Progress Tracking Feature
- Implement ProgressCallback interface in ion/src/com/koushikdutta/ion/ (
ion/src/com/koushikdutta/ion/ProgressCallback.java) - Integrate progress callbacks into BitmapFetcher.java download loop (
ion/src/com/koushikdutta/ion/BitmapFetcher.java) - Create a sample activity demonstrating progress in ion-sample/ (
ion-sample/src/com/koushikdutta/ion/sample/ProgressBarDownload.java) - Add progress layout XML with ProgressBar in ion-sample/res/layout/ (
ion-sample/res/layout/progress.xml)
🔧Why these technologies
- Gson (Google JSON Serializer) — Seamless Java object serialization/deserialization for REST API responses without manual JSON parsing
- Android Support Library v4 — Backward compatibility layer for fragments, loaders, and lifecycle utilities across API levels
- Kotlin Coroutines & Suspend Functions — Modern async/await pattern reduces callback nesting and integrates naturally with Kotlin codebases
- AsyncTask & Handler-based Threading — Native Android threading model ensures lifecycle awareness and automatic UI thread marshalling
- Bitmap Caching (Memory + Disk) — Prevents redundant network requests and decoding operations for repeated image loads
⚖️Trade-offs already made
-
Single-library approach (networking + image loading + JSON parsing)
- Why: Reduces dependency bloat and simplifies integration for typical Android apps
- Consequence: Larger library footprint; developers cannot swap individual components (e.g., networking layer)
-
Activity-scoped request cancellation (automatic on finish)
- Why: Prevents memory leaks and stale callbacks when activities are destroyed
- Consequence: Requires tight coupling to Activity lifecycle; harder to test without instrumentation
-
In-memory bitmap cache with weak references
- Why: Quick repeated loads without re-fetching or re-decoding; respects GC pressure
- Consequence: Cache eviction unpredictable; cold starts may cause jank on low-memory devices
-
undefined
- Why: undefined
- Consequence: undefined
🪤Traps & gotchas
Android build tools v28.0.3 is outdated (current is 34+); may fail on Java 11+ without AGP upgrade. NIO and AndroidAsync are custom-built async frameworks—no easy swap to RxJava or Retrofit without major refactoring. Lifecycle-aware cancellation is tied to Activity context, not Fragment; potential memory leaks if misused. No visible Gradle lock file or dependency version pinning—transitive dependency conflicts may occur. Kotlin module is separate and must be explicitly included in settings.gradle (not shown), which is non-obvious.
🏗️Architecture
💡Concepts to learn
- NIO (Non-blocking I/O) and Selector-based multiplexing — Ion's entire async foundation is built on Java NIO selectors instead of thread pools; understanding this is critical to debugging connection hangs or performance issues.
- HTTP Connection Keep-Alive and Connection Pooling — Ion's transparent reuse of TCP connections across requests is a core performance feature; misunderstanding connection limits can cause deadlocks in high-concurrency scenarios.
- Gzip/Deflate transparent compression negotiation — Ion automatically compresses request bodies and decompresses responses; this reduces bandwidth but can mask actual payload size during debugging.
- SPDY and HTTP/2 protocol negotiation — Ion transparently upgrades to SPDY or HTTP/2 if the server supports it; understanding protocol fallback behavior is important for compatibility testing.
- Lifecycle-aware request cancellation via WeakReference/LifecycleObserver patterns — Ion's killer feature—requests are automatically cancelled when the calling Activity is destroyed. This requires careful Context handling to avoid memory leaks.
- Bitmap caching and LRU eviction policies — Ion manages in-memory image caches with LRU (Least Recently Used) eviction; tuning cache size is critical for apps loading galleries without OOM crashes.
- Multipart/form-data encoding and streaming uploads — Ion handles chunked file uploads with progress callbacks; understanding stream buffering and cancellation during upload is essential for robust file transfer features.
🔗Related repos
square/retrofit— Industry-standard REST client library for Android; offers similar fluent API but focuses on type-safe endpoints rather than Ion's media-first approach.bumptech/glide— Image loading library that competes directly with Ion's image pipeline; Glide is more optimized for gallery-scale image throughput.koush/AndroidAsync— Direct dependency and foundation of Ion; provides the NIO event loop and async primitives that power Ion's networking.ReactiveX/RxAndroid— Alternative async model (reactive streams) that modern Android apps use instead of Ion's Future-based approach.greenrobot/EventBus— Commonly paired with Ion for decoupling network callbacks from UI; handles posting results back to Activity/Fragment after Ion requests complete.
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add instrumented tests for ion-kotlin Kotlin coroutine API coverage
The ion-kotlin module only has 2 test files (ExampleInstrumentedTest.kt and KotlinTests.kt) with minimal test coverage for the Kotlin coroutine/suspend support advertised in the README. Given that Kotlin coroutine support is a headlining feature, comprehensive tests for suspend functions, error handling, cancellation, and timeout behavior would catch regressions and improve maintainability.
- [ ] Review existing tests in ion-kotlin/test/src/com/koushikdutta/ion/kotlin/test/KotlinTests.kt to identify coverage gaps
- [ ] Add instrumented tests for: suspend function chainability, coroutine cancellation behavior, timeout handling, error propagation, and concurrent requests
- [ ] Ensure tests cover both image loading and JSON deserialization flows with coroutines
- [ ] Update ion-kotlin/README.md with examples of tested coroutine patterns
Create GitHub Actions CI workflow for automated testing and library publishing
The repo has a .github/FUNDING.yml but no CI workflows (no .github/workflows/ directory). With multiple subprojects (ion-kotlin, ion-sample) and recent Gradle/Android plugin versions (3.2.0, compileSdk 28), automated testing on PRs and releases would prevent regressions. This is especially important for an async networking library where edge cases matter.
- [ ] Create .github/workflows/android-tests.yml to run Gradle tests on PR for both ion-kotlin and ion-sample modules
- [ ] Add matrix testing for multiple Android API levels (21, 28, 29+) using emulator or robolectric
- [ ] Create .github/workflows/publish.yml to automate Maven/JCenter publishing on git tags
- [ ] Document build/test/publish steps in CONTRIBUTING.md or similar
Consolidate and document sample implementations for image loading and networking
The ion-sample module has multiple layout files (gallery.xml, image.xml, image_search.xml, lollipop_fullscreen.xml, etc.) and sample Activities (GallerySample.java, ImageSearch.java, DeepZoomSample.java) but these lack documented use case descriptions or a sample README explaining which Activity demonstrates which feature. New contributors cannot easily understand the feature matrix or find relevant code examples.
- [ ] Create ion-sample/SAMPLES.md documenting each Activity (GallerySample, ImageSearch, DeepZoomSample, etc.) with its purpose, features demonstrated, and key code snippets
- [ ] Add inline Javadoc comments to ion-sample/src/com/koushikdutta/ion/sample/*.java files explaining the pattern each demonstrates
- [ ] Create a feature matrix in SAMPLES.md showing which sample covers image caching, progressive loading, GIF animation, error handling, upload progress, etc.
- [ ] Update main README.md to link to SAMPLES.md for contributors wanting to understand API usage
🌿Good first issues
- Add unit tests for ion-kotlin/ coroutine wrappers: Create test cases in ion-kotlin/test/src/com/koushikdutta/ion/kotlin/test/ covering suspend functions for image loads, JSON parsing, and cancellation scenarios (currently only ExampleInstrumentedTest.kt exists).
- Upgrade build.gradle to Android API 33+ and Gradle 8.x: Update compileSdkVersion, buildToolsVersion, and com.android.tools.build:gradle in buildscript to modern versions, verify ion-sample still builds, and document breaking changes in CHANGELOG.md.
- Document RequestGroup API and lifecycle behavior: Create a guide explaining how Ion.with(context) automatically cancels requests when the Activity is destroyed, with code examples showing common pitfalls (e.g., Fragment context vs Activity context).
⭐Top contributors
Click to expand
Top contributors
- @koush — 86 commits
- @davebren — 3 commits
- @Artyom — 3 commits
- @fabLouis — 1 commits
- @kakao-tommy-kim — 1 commits
📝Recent commits
Click to expand
Recent commits
2e48671— update (koush)d6754ba— publishing (koush)5439578— asserts (koush)60bb741— Create FUNDING.yml (koush)ed828e9— 309 (koush)1fb6562— null check the loaders (koush)98b292a— fixup loader bug not actually resolving as it should (koush)374efdf— update (koush)fafb9fa— merge (koush)918ba3b— remove apache dependency (koush)
🔒Security observations
The Ion library has several security concerns primarily related to outdated build infrastructure and dependencies. The most critical issues are the use of defunct jcenter() repository and severely outdated Gradle/Build Tools (from 2018). While the library itself appears to be focused on networking, there's insufficient visibility into secure TLS/certificate handling and potential injection risks from Gson deserialization. The sample application may demonstrate insec
- High · Outdated Gradle and Android Build Tools —
build.gradle (buildscript dependencies and subprojects configuration). The build.gradle uses Gradle Android Plugin version 3.2.0 (released in September 2018) and Build Tools 28.0.3 (from 2018). These versions are significantly outdated and contain known security vulnerabilities and deprecated dependencies. Modern Android development requires much newer versions to receive security patches and bug fixes. Fix: Update to the latest stable versions: Android Gradle Plugin 8.x and Build Tools 34.x minimum. Review and update all transitive dependencies through dependency management. - High · Use of Deprecated jcenter() Repository —
build.gradle (buildscript and subprojects repositories). The project configuration includes jcenter() repository which was shut down by JFrog in February 2021. This repository is no longer maintained and no longer serves dependencies. Builds relying on it may fail, and it introduces risk if any malicious packages were left in the deprecated repository. Fix: Remove jcenter() repository entirely. Use only mavenCentral() and google() repositories. Update to use mavenCentral() as the primary public repository. - Medium · Potential Network Security: Unverified HTTPS/TLS —
ion module (main networking library). As an Android networking library that performs asynchronous HTTP operations, the codebase likely handles network requests. Without visible security configuration files or manifest analysis, there's risk of missing proper certificate pinning, TLS version enforcement, or cleartext traffic restrictions. Fix: Implement network security configuration (network_security_config.xml) with: cleartextTrafficPermitted set to false, certificate pinning for critical endpoints, and minimum TLS 1.2 enforcement. - Medium · Sample Application with Potential Insecure Practices —
ion-sample/src/com/koushikdutta/ion/sample/ (all sample files). The ion-sample application contains multiple sample implementations (ImageViewSample, Twitter, etc.) that may demonstrate insecure patterns such as hardcoded URLs, improper credential handling, or unsafe deserialization with Gson without proper type verification. Fix: Review all sample code for secure coding practices. Ensure samples don't hardcode credentials, API endpoints, or authentication tokens. Add comments about security best practices. - Medium · Kotlin Coroutine Implementation - Potential Scope Issues —
ion-kotlin/src/com/koushikdutta/ion/kotlin/ (Kotlin implementation files). The kotlin extension for ion (ion-kotlin) uses suspend functions for async operations. Improper coroutine scope handling could lead to memory leaks, uncaught exceptions, or race conditions if not properly implemented with lifecycle-aware scopes. Fix: Ensure all coroutines use proper lifecycle-aware scopes (lifecycleScope, viewModelScope). Implement proper exception handling with try-catch or CoroutineExceptionHandler. Add structured concurrency patterns. - Low · Missing Security Headers Configuration —
ion-test-server/main.py. The test server (ion-test-server/main.py) appears to be a Python backend. Without visible code, there's potential missing implementation of security headers (HSTS, X-Content-Type-Options, X-Frame-Options, CSP). Fix: Review and implement proper HTTP security headers in the test server. Add HSTS, CSP, X-Content-Type-Options: nosniff, X-Frame-Options: DENY headers. - Low · Sensitive Assets in Repository —
ion-sample/ (various PNG and image files). Image assets (charles.png, screenshot files) are committed to the repository. If any of these contain sensitive information or represent test credentials, they should be removed from version control history. Fix: Review committed images for sensitive data. Use .gitignore to exclude large binary assets. Consider using Git LFS for necessary image files.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.