Inside stormzhang/9GAG, an unofficial 9GAG client for Android from 2014
Android unofficial REST Client of 9GAG.
At a glance
- What is it?
- stormzhang/9GAG is an unofficial Android client for 9GAG, written in Java in 2014 as a learning project and marked unmaintained by its own opening notice. What it still shows is one era's Android stack in full: Volley listed beside OkHttp, ButterKnife view binding, and a build pinned to Gradle 2.2.1.
- Who is it for?
- Read stormzhang/9GAG as reference material rather than as a starting point: the layer split under me/storm/ninegag and the card feed with a category drawer are worth studying closely, while Gradle 2.2.1 with Android Gradle Plugin 1.5.0 rules out a build on any current toolchain.
- Can I use it commercially?
- Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
- Is it still maintained?
- Yes. The repository last received commits 176 days ago.
- What is it written in?
- Mainly Java, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 6, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A card feed reader for 9GAG, frozen at Android 5.1
The repository header calls stormzhang/9GAG an Android unofficial REST Client of 9GAG, and the README describes an unofficial Android client for 9gag.com built with Android Studio and Gradle under Material Design guidelines. Scope is one site on one phone form factor, with no account, no sync and no second service in the feature list. Six features are named, and each maps to a screen or a layer: feeds browsing with a card-style layout, swipe-back gesture navigation, an image detail view with zoom support, a navigation drawer with category filtering, local data caching with SQLite, and a shimmer loading animation. Read as a set, that is a reading app, and a small one.
Underneath sits a version pair: Android 5.1 (API 22) as the target and Android 4.0 (API 14) as the minimum, a spread that was unremarkable in 2014 and is now the first thing that dates the code. A project configured that way compiles against a support library generation that current Android Studio versions no longer offer by default. It also picks up no behaviour change from any platform version shipped after 5.1. The opening notice gives the reason plainly: built in 2014 as a learning project to demonstrate Android development best practices of that era, with code and dependencies called outdated and the project kept for reference.
Seven packages and one Application class under me/storm/ninegag
All Java code sits under `app/src/main/java/me/storm/ninegag/`, and the package list reads in one pass: `api/` for network requests, `dao/` for the SQLite data access layer, `data/` for data sources, `model/` for Feed and Category, the ui package for activities, fragments and adapters, `util/` for cache, bitmap and blur helpers, `view/` for custom views including SwipeBack, then `App.java` as the application entry point.
The order of those names carries the design. `api/` and `data/` sit above `dao/`, so the SQLite layer is not what talks to the network: something in the data package mediates between a request and a cached row, a split that many projects of that period collapsed into a single `dao/` or left as repository classes parked inside ui. Two model classes is the entire domain here, which matches the feature list exactly, because the navigation drawer needs categories and the feed needs entries, and nothing in the other four features needs a type of its own. Custom views live in `view/` rather than inside ui, so the swipe-back gesture is project code and not something a library hands over.
Two HTTP stacks share one row of the dependency table
The package comment above `api/` names Volley as the network layer, and the dependency table then puts two HTTP clients on the same row: Volley and OkHttp, both linked. The project claims both, and no file says which one serves which call. Anyone hoping to learn from this has to work out for themselves where the second library earns its keep, and that answer is written down nowhere.
The same split shows up around images. Glide is the image loading entry while `util/` carries its own bitmap helpers, so image work is divided between a library and project code with no stated rule for the boundary. PhotoView handles the zoom in the detail view while `view/` holds the custom views, which splits the gesture story across two places as well. Navigation is the one area left entirely alone: no drawer or refresh widget appears in the table, so the swipe-back class in `view/` was written by the author. Delegated where a library existed, hand-written where none did, describes most Android apps of that period, and it also marks exactly which parts of this code would need replacing.
Building on Gradle 2.2.1 with the Android Gradle Plugin 1.5.0
One command appears in the build section, and it is a clone:
git clone https://github.com/stormzhang/9GAG.gitAfter that, open the project in Android Studio and sync Gradle. The top-level file list confirms the standard multi-file layout sitting behind that step: `build.gradle`, `config.gradle`, `settings.gradle`, `gradle.properties`, `gradle/`, `gradlew`, `gradlew.bat`, `app/` and `extras/`, alongside `.gitignore` and the two READMEs. A separate `config.gradle` is the older convention for holding shared version numbers, and the committed `gradlew` means the wrapper decides which Gradle runs rather than whatever sits on your machine.
The note under the build section decides whether any of this works for you. Gradle 2.2.1 and Android Gradle Plugin 1.5.0 are the versions named there, and the note warns that an older version of Android Studio or manual Gradle configuration may be needed to build successfully. No prebuilt binary is linked anywhere, and no step goes past cloning and syncing. Expect the first build to be a toolchain problem before it becomes a code problem.
The REST surface is never named in the repository
A client described as a REST client ought to say what it calls, and this one does not. No host path, endpoint, query parameter, authentication scheme, rate limit or pagination rule appears in any file given, and the six features describe only what a user sees: browse, filter, open an image, come back. How a category chosen in the drawer becomes a request is left to whoever reads the code.
The silence covers behaviour after the request too. Caching with SQLite is named as a feature, and no cache lifetime, refresh trigger or failure path is documented. The shimmer animation is named as the loading state, and no error or empty state is. Nothing in the top-level entries is a test directory or a CI configuration either. That pairing matters more than it first looks: anyone aiming this code at a live 9GAG endpoint inherits undocumented error handling and no visible safety net in the same move.
Shimmer, LeakCanary and the rest of a 2014 dependency set
Count what the table asks a build system to resolve: FoldableLayout, AndroidStaggeredGrid, Shimmer, PhotoView, ButterKnife, Glide, Volley, OkHttp and LeakCanary. Five of those are community widgets for jobs the framework handled poorly in 2014, namely a staggered grid, a shimmer placeholder, a pinch-zoom image view, a foldable layout and annotation-based view binding, and one is a development diagnostic with no framework counterpart at all.
That is where the real comparison lies, and it is not another 9GAG client. Later Android versions absorbed most of those jobs into the framework and its support library, so the direction the platform travelled was fewer third-party views, one HTTP client instead of two, and view binding that needs no code generator. Measured against that direction, this repository is a snapshot taken just before the widgets arrived, which is what makes it worth reading. What it cannot hand you is a pattern to carry forward, because ButterKnife and the Volley era both belong to the build configuration the README already pins to two tool versions from 2014.
What a 2026 push means for a codebase called unmaintained
The licence shown in the repository header is unknown, while the README file carries the full Apache 2.0 notice under a 2014 copyright line, so read the file rather than the header field before reusing anything from it. The last push was on 2026-04-30, yet the opening notice says the project is no longer maintained; that date records a commit to the repository and says nothing about whether the client still builds or still resolves 9gag.com.
Two smaller artefacts show how carefully the place was left. A Chinese translation sits beside the English one as `README_CN.md`, and the single screenshot is hot-linked from an external Chinese image host instead of being kept in the repository, so the only visual evidence in the project can vanish without touching the code. The homepage field points at stormzhang.com rather than at documentation, and nothing in the README or the file list mentions an issue tracker, a support policy or an upgrade path.
Editorial conclusion
Read stormzhang/9GAG as reference material rather than as a starting point: the layer split under me/storm/ninegag and the card feed with a category drawer are worth studying closely, while Gradle 2.2.1 with Android Gradle Plugin 1.5.0 rules out a build on any current toolchain. Anyone reusing the code should read the grant text kept in the README file itself, and expect to write the request layer and the failure paths from scratch, since no endpoint, cache rule or error state is written down anywhere.
Frequently asked questions
Can I build stormzhang/9GAG with a current Android Studio?
The build note names Gradle 2.2.1 and Android Gradle Plugin 1.5.0 and warns that an older Android Studio or manual Gradle configuration may be needed. Nothing in the README describes a newer toolchain.
Which Android versions does the 9GAG client support?
The minimum is Android 4.0 (API 14) and the target is Android 5.1 (API 22).
Does stormzhang/9GAG work offline, and how long does the cache last?
Local data caching with SQLite is listed as a feature. The README does not document a cache lifetime, a refresh trigger or an offline mode.
Which 9GAG API endpoints does the client call?
The repository header calls it a REST client, but no host path, endpoint or parameter is written down in the files. Reading the api/ and data/ packages is the only route to the answer.
Can I reuse the code from stormzhang/9GAG in a commercial app?
Rely on the notice text kept in the README file, which carries a 2014 copyright line and a permissive grant. The repository header shows no identifier at all, so the header alone answers nothing.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/stormzhang-9gag)Was this useful?