All Projects → githubhaohao → Mvvmrxjavaretrofitsample

githubhaohao / Mvvmrxjavaretrofitsample

MVVM RxJava Retrofit Sample

Programming Languages

java
68154 projects - #9 most used programming language

Projects that are alternatives of or similar to Mvvmrxjavaretrofitsample

AndroidGo
Android、Flutter 开发者帮助 APP。包含事件分发、性能分析、Google Jetpack组件、OkHttp、RxJava、Retrofit、Volley、Canvas绘制以及优秀博文代码案例等内容,帮助开发者快速上手!
Stars: ✭ 30 (-79.73%)
Mutual labels:  rxjava, retrofit, mvvm
Mentorship Android
Mentorship System is an application that matches women in tech to mentor each other, on career development, through 1:1 relations during a certain period of time. This is the Android application of this project.
Stars: ✭ 117 (-20.95%)
Mutual labels:  rxjava, mvvm, retrofit
Relax
☘☘Relax 基于Kotlin语言编写的一套组件化框架,不紧整体组件化、内部也高度组件化🎋你可配置MVP、MVVM的开发模式、也可以配置所需要的业务组件🍁🍁
Stars: ✭ 253 (+70.95%)
Mutual labels:  rxjava, mvvm, retrofit
Mvvmhabit
goldze: 本人喜欢尝试新的技术,以后发现有好用的东西,我将会在企业项目中实战,没有问题了就会把它引入到MVVMHabit中,一直维护着这套框架,谢谢各位朋友的支持。如果觉得这套框架不错的话,麻烦点个 star,你的支持则是我前进的动力!
Stars: ✭ 6,789 (+4487.16%)
Mutual labels:  rxjava, mvvm, retrofit
Awesome Android Kotlin Apps
👓 A curated list of awesome android kotlin apps by open-source contributors.
Stars: ✭ 1,058 (+614.86%)
Mutual labels:  rxjava, mvvm, retrofit
Alfonz
Mr. Alfonz is here to help you build your Android app, make the development process easier and avoid boilerplate code.
Stars: ✭ 90 (-39.19%)
Mutual labels:  rxjava, mvvm, retrofit
Viabus Architecture
让 Android 开发可以像流水线一样高效的,职责分离架构 ⚡ 不同于 MVP 的配置解耦,也不能和 似是而非 的 MVVM - Clean 同日而语。VIABUS 是世界范围内首个明确提出,通过职责分离,来真正实现 UI 和 业务并行开发的 Android 项目级开发架构和设计模式理念。
Stars: ✭ 485 (+227.7%)
Mutual labels:  rxjava, mvvm, retrofit
Mvvmhabitcomponent
👕基于MVVMHabit框架,结合阿里ARouter打造的一套Android MVVM组件化开发方案
Stars: ✭ 857 (+479.05%)
Mutual labels:  rxjava, mvvm, retrofit
Beaver
Android MVVM + Dagger 2 (Hilt) + JetPack project template
Stars: ✭ 144 (-2.7%)
Mutual labels:  rxjava, mvvm, retrofit
Androcat
AndroCat is a GitHub client for Android phones and provides to user GitHub user interface like how they used to.
Stars: ✭ 87 (-41.22%)
Mutual labels:  rxjava, mvvm, retrofit
Android Clean Architecture Mvvm Dagger Rx
Implemented by Clean Architecture, Dagger2, MVVM, LiveData, RX, Retrofit2, Room, Anko
Stars: ✭ 138 (-6.76%)
Mutual labels:  rxjava, sample, mvvm
Basemvp Master
一个基本的MVP应用框架(RxJava+Retrofit+Glide+IjkPlayer),封装比较完善,易于使用,帮助日常快速开发一个项目。
Stars: ✭ 101 (-31.76%)
Mutual labels:  rxjava, retrofit
Mvvm Reddit
A companion project for our blog post on better Android software development using MVVM with RxJava.
Stars: ✭ 106 (-28.38%)
Mutual labels:  rxjava, mvvm
Brick
【此git仓库已停止更新,其中的若干个模块将被拆分为多个仓库,详情请点开本人的仓库列表查看。】使用Kotlin Coroutine和ViewModel、LiveData等Android Jetpack组件搭建而成的MVP、MVVM架构框架。实现了业务代码的高复用性的核心特点,并且使用简单、代码简洁。 如果使用Retrofit作为网络请求工具,可以为Model层自动注入Retrofit Api实例,进一步精简代码。同样的,也可以注入Room数据库框架的Dao层接口。注:配合http模块食用,风味更佳!
Stars: ✭ 109 (-26.35%)
Mutual labels:  mvvm, retrofit
Novate
A safety client by Https for android, (Android网络框架,基于Retrofit和RxJava打造的链式网络库, 支持okhttp的调用风格,又兼容Retrofit API,并支持rxJava链式操作)
Stars: ✭ 1,442 (+874.32%)
Mutual labels:  rxjava, retrofit
Qbox
🐈 RxJava+Retrofit+Okhttp+Glide + A life tool App, contains modules: news; jokes; constellation fortune; LED; weather; calendar; two-dimensional code, and more ... 小秋魔盒是一个生活工具 App,主要功能有:新闻资讯;微信精选美文;笑话趣图;星座运势;LED字幕;天气;日历;二维码;手电筒;老黄历。在开发中尽可能多的用了目前比较流行的框架和库。
Stars: ✭ 1,360 (+818.92%)
Mutual labels:  rxjava, retrofit
Aachulk
️🔥️🔥️🔥AACHulk是以Google的ViewModel+DataBinding+LiveData+Lifecycles框架为基础, 结合Okhttp+Retrofit+BaseRecyclerViewAdapterHelper+SmartRefreshLayout+ARouter打造的一款快速MVVM开发框架
Stars: ✭ 109 (-26.35%)
Mutual labels:  mvvm, retrofit
Mvvm Architecture
The practice of MVVM + Jetpack architecture in Android.
Stars: ✭ 1,634 (+1004.05%)
Mutual labels:  rxjava, mvvm
Jd Test
仿京东app 全新组件化架构升级
Stars: ✭ 1,346 (+809.46%)
Mutual labels:  rxjava, retrofit
Foodsearch
Showcase project of MVP+Dagger+RxJava+StorIO
Stars: ✭ 117 (-20.95%)
Mutual labels:  rxjava, retrofit

Sample 简介

一个简单的结合 Retrofit 和 RxJava 框架实现 MVVM 架构的例子。

最近在研究 Kotlin for Android,做了一个基于 Clean 架构以及 Retrofit , RxKotlin , Dagger 框架实现的 Kotlin for Android App ,更多详情请戳这里

效果预览

result

Demo 下载

准备知识

MVC

mvc

  • 视图(View):用户界面。
  • 控制器(Controller):业务逻辑
  • 模型(Model):数据保存

  1. View 传送指令到 Controller
  2. Controller 完成业务逻辑后,要求 Model 改变状态
  3. Model 将新的数据发送到 View,使用户得到反馈

缺陷:View 和 Model 是相互可知,耦合性大,像 Activity 或者 Fragment 既是 Controller 层,又是 View 层,造成工程的可扩展性可维护性非常差。

MVP

mvp

在 MVP 设计架构中,Controller 变成了 Presenter。

  1. 各层之间的通信,都是双向的。
  2. View 与 Model 不直接发生联系,都通过 Presenter 进行间接通信。
  3. Model 层与 Presenter 层,Presenter 层与 View 层之间通过接口建立联系。

采用 MVP 设计架构,Activity 与 Fragment 只位于 View 层。

MVP 的缺陷在于:由于我们使用了接口的方式去连接 View 层和 Presenter 层,这样就导致了一个问题,当你的页面逻辑很复杂的时候,你的接口会有很多,如果你的 app 中有很多个这样复杂的页面,维护接口的成本就会变的非常的大。

MVVM

MVVM

MVVM 模式将 Presenter 改名为 ViewModel,基本上与 MVP 模式完全一致。 区别在于: View 层与 ViewModel 层通过DataBinding相互绑定,View的变动,自动反映在 ViewModel,反之亦然。

RxJava

RxJava 在 GitHub 主页上的自我介绍是 "a library for composing asynchronous and event-based programs using observable sequences for the Java VM"(一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库)。

RxJava 本质上是一个异步操作库,是一个能让你用极其简洁的逻辑去处理繁琐复杂任务的异步事件库。

简而言之,RxJava 可以用几个关键字概括:简洁队列化异步

Retrofit

retrofit

一个 Android 和 Java 上 HTTP 库(利用注解和 okhttp 来实现和服务器的数据交互)。

Retrofit 官方文档:http://square.github.io/retrofit/

DataBinding

data-binding

在今年的 Google IO 2015 中,Google 在 support-v7 中新增了 Data Binding,使用 Data Binding 可以直接在布局的 xml 中绑定布局与数据,从而简化代码,Android Data Binding 是Android 的 MVVM 框架。因为 Data Binding 是包含在 support-v7 包里面的,所以可以向下兼容到最低 Android 2.1 (API level 7+).

实践

嫌代码不够高亮?请移步博客http://haohaochang.cn

直接上代码。

依赖的第三方类库

    compile 'io.reactivex:rxjava:1.1.0'
    compile 'io.reactivex:rxandroid:1.1.0'
    compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
    compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
    compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'
    compile 'com.github.bumptech.glide:glide:3.7.0'

API

https://api.douban.com/v2/movie/top250?start=0&count=20

引入DataBinding

android {
    ......

    dataBinding {
        enabled = true
    }
}

工程目录结构

目录

MVVM 之 View

MainActivity.java

getFragmentManager().beginTransaction().add(R.id.movie_fragment, MovieFragment.getInstance()).commit();

MovieFragment.java

public class MovieFragment extends Fragment implements CompletedListener,SwipeRefreshLayout.OnRefreshListener{

    private static String TAG = MovieFragment.class.getSimpleName();
    private MainViewModel viewModel;
    private MovieFragmentBinding movieFragmentBinding;
    private MovieAdapter movieAdapter;

    public static MovieFragment getInstance() {
        return new MovieFragment();
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View contentView = inflater.inflate(R.layout.movie_fragment, container, false);
        movieFragmentBinding = MovieFragmentBinding.bind(contentView);
        initData();
        return contentView;
    }

    private void initData() {
        movieAdapter = new MovieAdapter();
        movieFragmentBinding.recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
        movieFragmentBinding.recyclerView.setItemAnimator(new DefaultItemAnimator());
        movieFragmentBinding.recyclerView.setAdapter(movieAdapter);
        movieFragmentBinding.swipeRefreshLayout.setColorSchemeResources(R.color.colorAccent, R.color.colorPrimary, R.color.colorPrimaryDark);
        movieFragmentBinding.swipeRefreshLayout.setOnRefreshListener(this);
        viewModel = new MainViewModel(movieAdapter,this);
        movieFragmentBinding.setViewModel(viewModel);

    }

    @Override
    public void onRefresh() {
        movieAdapter.clearItems();
        viewModel.refreshData();
    }

    @Override
    public void onCompleted() {
        if (movieFragmentBinding.swipeRefreshLayout.isRefreshing()) {
            movieFragmentBinding.swipeRefreshLayout.setRefreshing(false);
        }
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context=".view.MainActivity">

    <!-- ... -->

    <FrameLayout
        android:layout_marginTop="?attr/actionBarSize"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/movie_fragment"/>

    <!-- ... -->

</android.support.design.widget.CoordinatorLayout>

movie_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="viewModel"
            type="com.jc.mvvmrxjavaretrofitsample.viewModel.MainViewModel"/>
    </data>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <android.support.v4.widget.SwipeRefreshLayout
            android:visibility="@{viewModel.contentViewVisibility}"
            android:id="@+id/swipe_refresh_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <android.support.v7.widget.RecyclerView
                android:id="@+id/recycler_view"
                android:background="#ddd"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:padding="8dp">
            </android.support.v7.widget.RecyclerView>

        </android.support.v4.widget.SwipeRefreshLayout>

        <ProgressBar
            style="?android:attr/progressBarStyleLarge"
            android:id="@+id/progress_bar"
            android:visibility="@{viewModel.progressBarVisibility}"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"/>

        <LinearLayout
            android:layout_width="match_parent"
            android:id="@+id/error_info_layout"
            android:visibility="@{viewModel.errorInfoLayoutVisibility}"
            android:orientation="vertical"
            android:layout_height="match_parent">
            <TextView
                android:layout_gravity="center"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{viewModel.exception}"/>
        </LinearLayout>
    </RelativeLayout>
</layout>

movie_item.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/tools">
    <data>
        <variable
            name="viewModel"
            type="com.jc.mvvmrxjavaretrofitsample.viewModel.MovieViewModel"/>
    </data>
    <android.support.v7.widget.CardView
        xmlns:card_view="http://schemas.android.com/apk/res-auto"
        android:id="@+id/card_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        card_view:cardCornerRadius="4dp"
        card_view:cardBackgroundColor="@color/background"
        card_view:cardUseCompatPadding="true">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <ImageView
                android:layout_margin="8dp"
                android:layout_width="60dp"
                android:layout_height="100dp"
                android:src="@drawable/cover"
                app:imageUrl="@{viewModel.imageUrl}"
                android:id="@+id/cover"/>
            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_margin="8dp"
                android:orientation="vertical">
                <TextView
                    android:textColor="@android:color/black"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="@{viewModel.title}"
                    android:textSize="12sp"/>
                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="4dp"
                    android:orientation="horizontal">
                    <android.support.v7.widget.AppCompatRatingBar
                        android:id="@+id/ratingBar"
                        style="?android:attr/ratingBarStyleSmall"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="center_vertical"
                        android:isIndicator="true"
                        android:max="10"
                        android:numStars="5"
                        android:rating="@{viewModel.rating}" />

                    <TextView
                        android:id="@+id/rating_text"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="center_vertical"
                        android:layout_marginLeft="6dp"
                        android:text="@{viewModel.ratingText}"
                        android:textColor="?android:attr/textColorSecondary"
                        android:textSize="10sp" />

                </LinearLayout>
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textColor="?android:attr/textColorSecondary"
                    android:textSize="10sp"
                    android:text="@{viewModel.movieType}"
                    android:id="@+id/movie_type_text"
                    android:layout_marginTop="6dp"
                    />
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textColor="?android:attr/textColorSecondary"
                    android:textSize="10sp"
                    android:text="@{viewModel.year}"
                    android:id="@+id/year_text"
                    android:layout_marginTop="6dp"
                    />
            </LinearLayout>

        </LinearLayout>

    </android.support.v7.widget.CardView>
</layout>

MovieAdapter.java

public class MovieAdapter extends RecyclerView.Adapter<MovieAdapter.BindingHolder> {
    private List<Movie> movies;

    public MovieAdapter() {
        movies = new ArrayList<>();
    }

    @Override
    public BindingHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        MovieItemBinding itemBinding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.movie_item, parent, false);
        return new BindingHolder(itemBinding);
    }

    @Override
    public void onBindViewHolder(BindingHolder holder, int position) {
        MovieViewModel movieViewModel = new MovieViewModel(movies.get(position));
        holder.itemBinding.setViewModel(movieViewModel);
    }

    @Override
    public int getItemCount() {
        return movies.size();
    }

    public void addItem(Movie movie) {
        movies.add(movie);
        notifyItemInserted(movies.size() - 1);
    }

    public void clearItems() {
        movies.clear();
        notifyDataSetChanged();
    }

    public static class BindingHolder extends RecyclerView.ViewHolder {
        private MovieItemBinding itemBinding;

        public BindingHolder(MovieItemBinding itemBinding) {
            super(itemBinding.cardView);
            this.itemBinding = itemBinding;
        }
    }
}

回调接口** CompletedListener.java**

public interface CompletedListener {
    void onCompleted();
}

MVVM 之 ViewModel

MainViewModel.java

public class MainViewModel {
    public ObservableField<Integer> contentViewVisibility;
    public ObservableField<Integer> progressBarVisibility;
    public ObservableField<Integer> errorInfoLayoutVisibility;
    public ObservableField<String> exception;
    private Subscriber<Movie> subscriber;
    private MovieAdapter movieAdapter;
    private CompletedListener completedListener;

    public MainViewModel(MovieAdapter movieAdapter,CompletedListener completedListener) {
        this.movieAdapter = movieAdapter;
        this.completedListener = completedListener;
        initData();
        getMovies();
    }

    private void getMovies() {
        subscriber = new Subscriber<Movie>() {
            @Override
            public void onCompleted() {
                Log.d("[MainViewModel]", "onCompleted");
                hideAll();
                contentViewVisibility.set(View.VISIBLE);
                completedListener.onCompleted();
            }

            @Override
            public void onError(Throwable e) {
                hideAll();
                errorInfoLayoutVisibility.set(View.VISIBLE);
                exception.set(e.getMessage());
            }

            @Override
            public void onNext(Movie movie) {
                movieAdapter.addItem(movie);
            }
        };
        RetrofitHelper.getInstance().getMovies(subscriber, 0, 20);
    }

    public void refreshData() {
        getMovies();
    }

    private void initData() {
        contentViewVisibility = new ObservableField<>();
        progressBarVisibility = new ObservableField<>();
        errorInfoLayoutVisibility = new ObservableField<>();
        exception = new ObservableField<>();
        contentViewVisibility.set(View.GONE);
        errorInfoLayoutVisibility.set(View.GONE);
        progressBarVisibility.set(View.VISIBLE);
    }

    private void hideAll(){
        contentViewVisibility.set(View.GONE);
        errorInfoLayoutVisibility.set(View.GONE);
        progressBarVisibility.set(View.GONE);
    }
}

MovieViewModel.java

public class MovieViewModel extends BaseObservable {
    private Movie movie;

    public MovieViewModel(Movie movie) {
        this.movie = movie;
    }

    public String getCoverUrl() {
        return movie.getImages().getSmall();
    }

    public String getTitle() {
        return movie.getTitle();
    }

    public float getRating() {
        return movie.getRating().getAverage();
    }

    public String getRatingText(){
        return String.valueOf(movie.getRating().getAverage());
    }

    public String getYear() {
        return movie.getYear();
    }

    public String getMovieType() {
        StringBuilder builder = new StringBuilder();
        for (String s : movie.getGenres()) {
            builder.append(s + " ");
        }
        return builder.toString();
    }

    public String getImageUrl() {
        return movie.getImages().getSmall();
    }

    @BindingAdapter({"app:imageUrl"})
    public static void loadImage(ImageView imageView,String url) {
        Glide.with(imageView.getContext())
                .load(url)
                .placeholder(R.drawable.cover)
                .error(R.drawable.cover)
                .into(imageView);

    }
}

MVVM 之 Model

DouBanMovieService.java

public interface DouBanMovieService {
    String BASE_URL = "https://api.douban.com/v2/movie/";

    @GET("top250")
    Observable<Response<List<Movie>>> getMovies(@Query("start") int start, @Query("count") int count);
}

RetrofitHelper.java

public class RetrofitHelper {
    private static final int DEFAULT_TIMEOUT = 10;
    private Retrofit retrofit;
    private DouBanMovieService movieService;
    OkHttpClient.Builder builder;

    /**
     * 获取RetrofitHelper对象的单例
     * */
    private static class Singleton {
        private static final RetrofitHelper INSTANCE = new RetrofitHelper();
    }

    public static RetrofitHelper getInstance() {
        return Singleton.INSTANCE;
    }

    public RetrofitHelper() {
        builder = new OkHttpClient.Builder();
        builder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);

        retrofit = new Retrofit.Builder()
                .client(builder.build())
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(DouBanMovieService.BASE_URL)
                .build();
        movieService = retrofit.create(DouBanMovieService.class);
    }

    public void getMovies(Subscriber<Movie> subscriber, int start, int count) {
        movieService.getMovies(start, count)
                .map(new Func1<Response<List<Movie>>, List<Movie>>() {
                    @Override
                    public List<Movie> call(Response<List<Movie>> listResponse) {
                        return listResponse.getSubjects();
                    }
                })
                .flatMap(new Func1<List<Movie>, Observable<Movie>>() {
                    @Override
                    public Observable<Movie> call(List<Movie> movies) {
                        return Observable.from(movies);
                    }
                })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(subscriber);
    }
}

还有 entity 类,这里就不贴出来了。

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].