Project Name | Stars | Downloads | Repos Using This | Packages Using This | Most Recent Commit | Total Releases | Latest Release | Open Issues | License | Language |
---|---|---|---|---|---|---|---|---|---|---|
Android Tech Frontier | 10,389 | 2 years ago | 11 | apache-2.0 | ||||||
【停止维护】一个定期翻译国外Android优质的技术、开源库、软件架构设计、测试等文章的开源项目 | ||||||||||
Mvparms | 10,129 | a year ago | 41 | apache-2.0 | Java | |||||
⚔️ A common architecture for Android applications developing based on MVP, integrates many open source projects, to make your developing quicker and easier (一个整合了大量主流开源项目高度可配置化的 Android MVP 快速集成框架). | ||||||||||
Bookreader | 6,273 | 6 months ago | 36 | apache-2.0 | Java | |||||
:closed_book: "任阅" 网络小说阅读器,3D翻页效果、txt/pdf/epub书籍阅读、Wifi传书~ | ||||||||||
Androidproject | 5,116 | 7 months ago | 1 | apache-2.0 | Java | |||||
Android 技术中台,但愿人长久,搬砖不再有 | ||||||||||
Awesome Rxjava | 4,834 | 2 years ago | 5 | |||||||
RxJava resources | ||||||||||
Android Mvp Architecture | 4,421 | 4 months ago | 40 | apache-2.0 | Java | |||||
This repository contains a detailed sample app that implements MVP architecture using Dagger2, GreenDao, RxJava2, FastAndroidNetworking and PlaceholderView | ||||||||||
Geeknews | 3,492 | 5 years ago | 50 | Java | ||||||
:books:A pure reading App based on Material Design + MVP + RxJava2 + Retrofit + Dagger2 + Realm + Glide | ||||||||||
Kotlinmvp | 3,216 | 3 years ago | 14 | apache-2.0 | Kotlin | |||||
:fire: 「停止维护」基于Kotlin+MVP+Retrofit+RxJava+Glide 等架构实现短视频类小项目,简约风格及详细注释,欢迎 star or fork! | ||||||||||
Lqrwechat | 3,069 | 4 years ago | 25 | mit | Java | |||||
本项目仿最新版微信6.5.7(除图片选择器外),基于融云SDK,使用目前较火的 Rxjava+Retrofit+MVP+Glide 技术开发。相比上个版本,加入发送位置消息,红包消息等功能。 | ||||||||||
Android Mvp Mvvm Flytour | 2,885 | 2 years ago | 8 | apache-2.0 | Java | |||||
🔥🔥🔥 FlyTour是Android MVVM+MVP+Dagger2+Retrofit+RxJava+组件化+插件组成的双编码架构+双工程架构+双语言Android应用开发框架,通过不断的升级迭代该框架已经有了十个不同的版本,5.0之前工程架构采用gradle配置实现组件化,5.0之后的工程架构采用VirtualAPK实现了插件化,5.0之前采用Java编码实现,5.0之后采用Kotlin编码实现,编码架构由MVVM和MVP组成,工程架构和编码架构及编码语言开发者可根据自己具体的项目实际需求去决定选择使用,该框架是Android组件化、Android插件化、Android MVP架构、Android MVVM架构的集大成者,帮助你快速的搭建自己的App项目开发框架,以便把主要的精力放在自己的项目的业务功能实现上,另外在长期的工作实践中总结整理大量的实用工具类在项目lib_common组件的util包当中方便大家调用。 |
A showcase of RxJava and Model View Presenter, plus a number of other popular libraries for Android development, including AutoValue, Retrofit, Moshi, and ButterKnife. Unit tested with Mockito covering any business logic.
The app is a simple master/detail implementation: we retrieve a list of gifs from the Giphy api and present them on the TrendingActivity
in a RecyclerView
. When a gif is clicked on, we load it in by itself in the GifDetailActivity
.
This setup has a number of advantages over a non-MVP app architecture
Presenter
is view agnostic and does not care how an action was triggered, making a clear division which is easy to changeView
interface is very simple - the methods are usually one liners, doing something on the android Activity
e.g. just setting a view's state to View.GONE
- which also makes them easy to testPresenter
object and abstracts the View
for easy mocking, so we can unit test all the things, e.g:
Observable
s exposing future actions via the View
interface, allowing our Presenter
s to be entirely statelessThe app is packaged by component/feature, under the com.emmaguy.giphymvp.feature
package, to keep everything as private as possible. This means that any classes which contain logic for the trending
feature is contained within feature.trending
package and cannot be mistakenly used or extended elsewhere.
Each component consists of a Presenter
class, a View
interface which the corresponding Activity
implements and a Module
/Component
for dependencies. The components currently map 1-1 to Activities, but could easily use custom views instead.
The View
interface enables the Presenter
to be pure Java and not have to know about anything android:
interface View extends PresenterView {
Observable<Object> onRefreshAction();
void showLoading();
void hideLoading();
...
}
The interface exposes:
Observable<Object>
)
Presenter
's one lifecycle method, onViewAttached
CompositeSubscription
via the method unsubscribeOnViewDetach
, which will unsubscribe from all subscriptions when the view is detachedPresenter
is exposed to by using a return type of Observable<Void>
, often it's enough just to know the action has happenedshow
/hide
), or methods which set
data/stateopen
e.g. openGifDetail
)Are responsible for presentation of whatever the view has (using a view interface), constrained by some business logic.
For example, TrendingPresenter
can react to refreshes. The consequence of a refresh varies depending on whether we successfully retrieve gifs or not, we can either show the grid of gifs or an error.
While the view introduces two kinds of refresh, loading (a ProgressBar
centered on screen as there's nothing else to see) and incremental loading (a swipe to refresh view), we have cheated slightly and just set both the loading and incremental loading to hidden after we refresh. The Giphy API does not support pagination, so this is not the place to try and demo incremental loading. We don't need to show incremental errors because we either have no data or some cached. In a real application, it's likely the cache is too stale to show anything useful, but this sample is not that complex!
A class containing state, for the moment this is just whether we have some gifs, or whether there's been an error
We only have one in this project, TrendingManager
, which is responsible for managing the network and the cache. We hit the cache - if there's something in it, we go with that. If not, let's refresh and cache it.
An advantage of this separation is that we are able to have unit tests covering the useful logic here - do we actually save gifs in storage when we successfully get some? Do we avoid the network when we use the cache?
As you might expect, these classes just persist things. Here we only have TrendingStorage
which is just an in memory cache of the last list of trending gifs we successfully received. No timestamp or concept of invalidation, just some gifs to show to the user.
This project does not use Dagger, instead it provides the required classes manually.
We instead create simple classes suffixed with Module
that contain static factory methods that construct the required dependencies, and create interfaces suffixed Component
which list the injectable items for each feature
.
Example Module:
class TrendingModule {
private static TrendingPresenter presenter;
static TrendingPresenter trendingGifsPresenter() {
return new TrendingPresenter(trendingGifManager(), AndroidSchedulers.mainThread());
}
....
}
Example Component:
interface TrendingComponent extends BaseComponent {
TrendingPresenter getPresenter();
}
Then, when the dependencies are needed, we can create the required components using the factory methods. We abstract this into the BaseActivity
, which also performs the ButterKnife binding/unbinding and Presenter
lifecycle methods attaching/detaching the view.
@CallSuper @Override protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
inject(createComponent());
setContentView(getLayoutId());
unbinder = ButterKnife.bind(this);
onViewCreated(savedInstanceState);
getPresenter().onViewAttached(getPresenterView());
}
We separate the createComponent
and inject
steps as an easy way to support orientation change - the first time we call both create
and inject
, any subsequent times we need to inject we can just call inject
and we can reuse the classes - which means we use our memory cache of data from our network requests (held in TrendingStorage
) rather than hit the network again.
Copyright 2016-2017 Emma Guy
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.