├── .gitignore
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── rengwuxian
│ │ └── rxjavasamples
│ │ ├── App.java
│ │ ├── BaseFragment.java
│ │ ├── MainActivity.java
│ │ ├── adapter
│ │ ├── ItemListAdapter.java
│ │ └── ZhuangbiListAdapter.java
│ │ ├── model
│ │ ├── FakeThing.java
│ │ ├── FakeToken.java
│ │ ├── GankBeauty.java
│ │ ├── GankBeautyResult.java
│ │ ├── Item.java
│ │ └── ZhuangbiImage.java
│ │ ├── module
│ │ ├── cache_6
│ │ │ ├── CacheFragment.java
│ │ │ └── data
│ │ │ │ ├── Data.java
│ │ │ │ └── Database.java
│ │ ├── elementary_1
│ │ │ └── ElementaryFragment.java
│ │ ├── map_2
│ │ │ └── MapFragment.java
│ │ ├── token_4
│ │ │ └── TokenFragment.java
│ │ ├── token_advanced_5
│ │ │ └── TokenAdvancedFragment.java
│ │ └── zip_3
│ │ │ └── ZipFragment.java
│ │ ├── network
│ │ ├── Network.java
│ │ └── api
│ │ │ ├── FakeApi.java
│ │ │ ├── GankApi.java
│ │ │ └── ZhuangbiApi.java
│ │ └── util
│ │ └── GankBeautyResultToItemsMapper.java
│ └── res
│ ├── drawable
│ └── upload.jpg
│ ├── layout
│ ├── activity_main.xml
│ ├── dialog_cache.xml
│ ├── dialog_elementary.xml
│ ├── dialog_map.xml
│ ├── dialog_token.xml
│ ├── dialog_token_advanced.xml
│ ├── dialog_zip.xml
│ ├── fragment_cache.xml
│ ├── fragment_elementary.xml
│ ├── fragment_map.xml
│ ├── fragment_token.xml
│ ├── fragment_token_advanced.xml
│ ├── fragment_zip.xml
│ ├── grid_item.xml
│ ├── list_item.xml
│ └── tip_bt.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxxhdpi
│ └── ic_launcher.png
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── images
├── screenshot_1.png
├── screenshot_2.png
├── screenshot_3.png
├── screenshot_4.png
├── screenshot_5.png
└── screenshot_6.png
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea
5 | .DS_Store
6 | /build
7 | /captures
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 样例代码已正式切换到基于 RxJava 2
2 | ================
3 |
4 | > 需要旧版 RxJava 1 代码的点[这里](https://github.com/rengwuxian/RxJavaSamples/tree/1.x)
5 |
6 | ### 项目介绍
7 |
8 | RxJava 2 和 Retrofit 结合使用的几个最常见使用方式举例。
9 |
10 | 1. **基本使用**
11 |
12 | 实现最基本的网络请求和结果处理。
13 | 
14 |
15 | 2. **转换(map)**
16 |
17 | 把返回的数据转换成更方便处理的格式再交给 Observer。
18 | 
19 |
20 | 3. **压合(zip)**
21 |
22 | 将不同接口并行请求获取到的数据糅合在一起后再处理。
23 | 
24 |
25 | 4. **一次性 token**
26 |
27 | 需要先请求 token 再访问的接口,使用 flatMap() 将 token 的请求和实际数据的请求连贯地串起来,而不必写嵌套的 Callback 结构。
28 | 
29 |
30 | 5. **非一次性 token**
31 |
32 | 对于非一次性的 token (即可重复使用的 token),在获取 token 后将它保存起来反复使用,并通过 retryWhen() 实现 token 失效时的自动重新获取,将 token 获取的流程彻底透明化,简化开发流程。
33 | 
34 |
35 | 6. **缓存**
36 |
37 | 使用 BehaviorSubject 缓存数据。
38 | 
39 |
40 | ### apk 下载
41 | [RxJavaSamples_2.0.apk](https://github.com/rengwuxian/RxJavaSamples/releases/download/2.0/RxJavaSamples_2.0.apk)
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | //noinspection GradleCompatible
2 | apply plugin: 'com.android.application'
3 |
4 | android {
5 | compileSdkVersion 26
6 | buildToolsVersion "26.0.1"
7 |
8 | defaultConfig {
9 | applicationId "com.rengwuxian.rxjavasamples"
10 | minSdkVersion 15
11 | targetSdkVersion 26
12 | versionCode 1
13 | versionName "2.0"
14 | }
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 | }
22 |
23 | dependencies {
24 | compile fileTree(include: ['*.jar'], dir: 'libs')
25 | testCompile 'junit:junit:4.12'
26 | compile 'com.android.support:appcompat-v7:26.1.0'
27 | compile 'com.android.support:support-v4:26.1.0'
28 | compile 'com.android.support:support-v13:26.1.0'
29 | compile 'com.android.support:design:26.1.0'
30 | compile 'com.android.support:cardview-v7:26.1.0'
31 | compile 'com.squareup.okhttp3:okhttp:3.8.0'
32 | compile 'com.squareup.retrofit2:retrofit:2.3.0'
33 | compile 'com.squareup.retrofit2:converter-gson:2.3.0'
34 | compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
35 | compile 'com.github.bumptech.glide:glide:4.1.1'
36 | annotationProcessor 'com.github.bumptech.glide:compiler:4.1.1'
37 | compile 'com.jakewharton:butterknife:8.8.1'
38 | annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
39 | compile 'io.reactivex.rxjava2:rxjava:2.0.7'
40 | compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
41 | compile 'com.jakewharton.rxbinding2:rxbinding:2.0.0'
42 | }
43 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/rengwuxian/.android-sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/rengwuxian/rxjavasamples/App.java:
--------------------------------------------------------------------------------
1 | // (c)2016 Flipboard Inc, All Rights Reserved.
2 |
3 | package com.rengwuxian.rxjavasamples;
4 |
5 | import android.app.Application;
6 |
7 | public class App extends Application {
8 | private static App INSTANCE;
9 |
10 | public static App getInstance() {
11 | return INSTANCE;
12 | }
13 |
14 | @Override
15 | public void onCreate() {
16 | super.onCreate();
17 | INSTANCE = this;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/com/rengwuxian/rxjavasamples/BaseFragment.java:
--------------------------------------------------------------------------------
1 | // (c)2016 Flipboard Inc, All Rights Reserved.
2 |
3 | package com.rengwuxian.rxjavasamples;
4 |
5 | import android.app.AlertDialog;
6 | import android.app.Fragment;
7 |
8 | import butterknife.OnClick;
9 | import io.reactivex.disposables.Disposable;
10 |
11 | public abstract class BaseFragment extends Fragment {
12 | protected Disposable disposable;
13 |
14 | @OnClick(R.id.tipBt)
15 | void tip() {
16 | new AlertDialog.Builder(getActivity())
17 | .setTitle(getTitleRes())
18 | .setView(getActivity().getLayoutInflater().inflate(getDialogRes(), null))
19 | .show();
20 | }
21 |
22 | @Override
23 | public void onDestroyView() {
24 | super.onDestroyView();
25 | unsubscribe();
26 | }
27 |
28 | protected void unsubscribe() {
29 | if (disposable != null && !disposable.isDisposed()) {
30 | disposable.dispose();
31 | }
32 | }
33 |
34 | protected abstract int getDialogRes();
35 |
36 | protected abstract int getTitleRes();
37 | }
38 |
--------------------------------------------------------------------------------
/app/src/main/java/com/rengwuxian/rxjavasamples/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.rengwuxian.rxjavasamples;
2 |
3 | import android.os.Bundle;
4 | import android.support.design.widget.TabLayout;
5 | import android.app.Fragment;
6 | import android.support.v13.app.FragmentPagerAdapter;
7 | import android.support.v4.view.ViewPager;
8 | import android.support.v7.app.AppCompatActivity;
9 | import android.support.v7.widget.Toolbar;
10 |
11 | import com.rengwuxian.rxjavasamples.module.token_advanced_5.TokenAdvancedFragment;
12 | import com.rengwuxian.rxjavasamples.module.token_4.TokenFragment;
13 | import com.rengwuxian.rxjavasamples.module.cache_6.CacheFragment;
14 | import com.rengwuxian.rxjavasamples.module.zip_3.ZipFragment;
15 | import com.rengwuxian.rxjavasamples.module.elementary_1.ElementaryFragment;
16 | import com.rengwuxian.rxjavasamples.module.map_2.MapFragment;
17 |
18 | import butterknife.BindView;
19 | import butterknife.ButterKnife;
20 |
21 | public class MainActivity extends AppCompatActivity {
22 | @BindView(android.R.id.tabs) TabLayout tabLayout;
23 | @BindView(R.id.viewPager) ViewPager viewPager;
24 | @BindView(R.id.toolBar) Toolbar toolBar;
25 |
26 | @Override
27 | protected void onCreate(Bundle savedInstanceState) {
28 | super.onCreate(savedInstanceState);
29 | setContentView(R.layout.activity_main);
30 | ButterKnife.bind(this);
31 |
32 | setSupportActionBar(toolBar);
33 |
34 | viewPager.setAdapter(new FragmentPagerAdapter(getFragmentManager()) {
35 | @Override
36 | public int getCount() {
37 | return 6;
38 | }
39 |
40 | @Override
41 | public Fragment getItem(int position) {
42 | switch (position) {
43 | case 0:
44 | return new ElementaryFragment();
45 | case 1:
46 | return new MapFragment();
47 | case 2:
48 | return new ZipFragment();
49 | case 3:
50 | return new TokenFragment();
51 | case 4:
52 | return new TokenAdvancedFragment();
53 | case 5:
54 | return new CacheFragment();
55 | default:
56 | return new ElementaryFragment();
57 | }
58 | }
59 |
60 | @Override
61 | public CharSequence getPageTitle(int position) {
62 | switch (position) {
63 | case 0:
64 | return getString(R.string.title_elementary);
65 | case 1:
66 | return getString(R.string.title_map);
67 | case 2:
68 | return getString(R.string.title_zip);
69 | case 3:
70 | return getString(R.string.title_token);
71 | case 4:
72 | return getString(R.string.title_token_advanced);
73 | case 5:
74 | return getString(R.string.title_cache);
75 | default:
76 | return getString(R.string.title_elementary);
77 | }
78 | }
79 | });
80 | tabLayout.setupWithViewPager(viewPager);
81 | }
82 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/rengwuxian/rxjavasamples/adapter/ItemListAdapter.java:
--------------------------------------------------------------------------------
1 | // (c)2016 Flipboard Inc, All Rights Reserved.
2 |
3 | package com.rengwuxian.rxjavasamples.adapter;
4 |
5 | import android.support.v7.widget.RecyclerView;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.ImageView;
10 | import android.widget.TextView;
11 |
12 | import com.bumptech.glide.Glide;
13 | import com.rengwuxian.rxjavasamples.R;
14 | import com.rengwuxian.rxjavasamples.model.Item;
15 |
16 | import java.util.List;
17 |
18 | import butterknife.BindView;
19 | import butterknife.ButterKnife;
20 |
21 | public class ItemListAdapter extends RecyclerView.Adapter {
22 | List- images;
23 |
24 | @Override
25 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
26 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.grid_item, parent, false);
27 | return new DebounceViewHolder(view);
28 | }
29 |
30 | @Override
31 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
32 | DebounceViewHolder debounceViewHolder = (DebounceViewHolder) holder;
33 | Item image = images.get(position);
34 | Glide.with(holder.itemView.getContext()).load(image.imageUrl).into(debounceViewHolder.imageIv);
35 | debounceViewHolder.descriptionTv.setText(image.description);
36 | }
37 |
38 | @Override
39 | public int getItemCount() {
40 | return images == null ? 0 : images.size();
41 | }
42 |
43 | public void setItems(List
- images) {
44 | this.images = images;
45 | notifyDataSetChanged();
46 | }
47 |
48 | static class DebounceViewHolder extends RecyclerView.ViewHolder {
49 | @BindView(R.id.imageIv) ImageView imageIv;
50 | @BindView(R.id.descriptionTv) TextView descriptionTv;
51 | public DebounceViewHolder(View itemView) {
52 | super(itemView);
53 | ButterKnife.bind(this, itemView);
54 | }
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/app/src/main/java/com/rengwuxian/rxjavasamples/adapter/ZhuangbiListAdapter.java:
--------------------------------------------------------------------------------
1 | // (c)2016 Flipboard Inc, All Rights Reserved.
2 |
3 | package com.rengwuxian.rxjavasamples.adapter;
4 |
5 | import android.support.v7.widget.RecyclerView;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.ImageView;
10 | import android.widget.TextView;
11 |
12 | import com.bumptech.glide.Glide;
13 | import com.rengwuxian.rxjavasamples.R;
14 | import com.rengwuxian.rxjavasamples.model.ZhuangbiImage;
15 |
16 | import java.util.List;
17 |
18 | import butterknife.BindView;
19 | import butterknife.ButterKnife;
20 |
21 | public class ZhuangbiListAdapter extends RecyclerView.Adapter {
22 | List images;
23 |
24 | @Override
25 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
26 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.grid_item, parent, false);
27 | return new DebounceViewHolder(view);
28 | }
29 |
30 | @Override
31 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
32 | DebounceViewHolder debounceViewHolder = (DebounceViewHolder) holder;
33 | ZhuangbiImage image = images.get(position);
34 | Glide.with(holder.itemView.getContext()).load(image.image_url).into(debounceViewHolder.imageIv);
35 | debounceViewHolder.descriptionTv.setText(image.description);
36 | }
37 |
38 | @Override
39 | public int getItemCount() {
40 | return images == null ? 0 : images.size();
41 | }
42 |
43 | public void setImages(List images) {
44 | this.images = images;
45 | notifyDataSetChanged();
46 | }
47 |
48 | static class DebounceViewHolder extends RecyclerView.ViewHolder {
49 | @BindView(R.id.imageIv) ImageView imageIv;
50 | @BindView(R.id.descriptionTv) TextView descriptionTv;
51 | public DebounceViewHolder(View itemView) {
52 | super(itemView);
53 | ButterKnife.bind(this, itemView);
54 | }
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/app/src/main/java/com/rengwuxian/rxjavasamples/model/FakeThing.java:
--------------------------------------------------------------------------------
1 | // (c)2016 Flipboard Inc, All Rights Reserved.
2 |
3 | package com.rengwuxian.rxjavasamples.model;
4 |
5 | public class FakeThing {
6 | public int id;
7 | public String name;
8 | }
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/rengwuxian/rxjavasamples/model/FakeToken.java:
--------------------------------------------------------------------------------
1 | // (c)2016 Flipboard Inc, All Rights Reserved.
2 |
3 | package com.rengwuxian.rxjavasamples.model;
4 |
5 | public class FakeToken {
6 | public String token;
7 | public boolean expired;
8 |
9 | public FakeToken() {
10 | }
11 |
12 | public FakeToken(boolean expired) {
13 | this.expired = expired;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/java/com/rengwuxian/rxjavasamples/model/GankBeauty.java:
--------------------------------------------------------------------------------
1 | // (c)2016 Flipboard Inc, All Rights Reserved.
2 |
3 | package com.rengwuxian.rxjavasamples.model;
4 |
5 | public class GankBeauty {
6 | public String createdAt;
7 | public String url;
8 | }
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/rengwuxian/rxjavasamples/model/GankBeautyResult.java:
--------------------------------------------------------------------------------
1 | // (c)2016 Flipboard Inc, All Rights Reserved.
2 |
3 | package com.rengwuxian.rxjavasamples.model;
4 |
5 | import com.google.gson.annotations.SerializedName;
6 |
7 | import java.util.List;
8 |
9 | public class GankBeautyResult {
10 | public boolean error;
11 | public @SerializedName("results") List beauties;
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/rengwuxian/rxjavasamples/model/Item.java:
--------------------------------------------------------------------------------
1 | // (c)2016 Flipboard Inc, All Rights Reserved.
2 |
3 | package com.rengwuxian.rxjavasamples.model;
4 |
5 | public class Item {
6 | public String description;
7 | public String imageUrl;
8 | }
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/rengwuxian/rxjavasamples/model/ZhuangbiImage.java:
--------------------------------------------------------------------------------
1 | // (c)2016 Flipboard Inc, All Rights Reserved.
2 |
3 | package com.rengwuxian.rxjavasamples.model;
4 |
5 | public class ZhuangbiImage {
6 | public String description;
7 | public String image_url;
8 | }
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/rengwuxian/rxjavasamples/module/cache_6/CacheFragment.java:
--------------------------------------------------------------------------------
1 | // (c)2016 Flipboard Inc, All Rights Reserved.
2 |
3 | package com.rengwuxian.rxjavasamples.module.cache_6;
4 |
5 | import android.graphics.Color;
6 | import android.os.Bundle;
7 | import android.support.annotation.Nullable;
8 | import android.support.v4.widget.SwipeRefreshLayout;
9 | import android.support.v7.widget.GridLayoutManager;
10 | import android.support.v7.widget.RecyclerView;
11 | import android.view.LayoutInflater;
12 | import android.view.View;
13 | import android.view.ViewGroup;
14 | import android.widget.TextView;
15 | import android.widget.Toast;
16 |
17 | import com.rengwuxian.rxjavasamples.BaseFragment;
18 | import com.rengwuxian.rxjavasamples.R;
19 | import com.rengwuxian.rxjavasamples.adapter.ItemListAdapter;
20 | import com.rengwuxian.rxjavasamples.model.Item;
21 | import com.rengwuxian.rxjavasamples.module.cache_6.data.Data;
22 |
23 | import java.util.List;
24 |
25 | import butterknife.BindView;
26 | import butterknife.ButterKnife;
27 | import butterknife.OnClick;
28 | import io.reactivex.Observer;
29 | import io.reactivex.annotations.NonNull;
30 | import io.reactivex.functions.Consumer;
31 |
32 | public class CacheFragment extends BaseFragment {
33 | @BindView(R.id.loadingTimeTv) TextView loadingTimeTv;
34 | @BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout swipeRefreshLayout;
35 | @BindView(R.id.cacheRv) RecyclerView cacheRv;
36 | ItemListAdapter adapter = new ItemListAdapter();
37 | private long startingTime;
38 |
39 | @OnClick(R.id.clearMemoryCacheBt)
40 | void clearMemoryCache() {
41 | Data.getInstance().clearMemoryCache();
42 | adapter.setItems(null);
43 | Toast.makeText(getActivity(), R.string.memory_cache_cleared, Toast.LENGTH_SHORT).show();
44 | }
45 |
46 | @OnClick(R.id.clearMemoryAndDiskCacheBt)
47 | void clearMemoryAndDiskCache() {
48 | Data.getInstance().clearMemoryAndDiskCache();
49 | adapter.setItems(null);
50 | Toast.makeText(getActivity(), R.string.memory_and_disk_cache_cleared, Toast.LENGTH_SHORT).show();
51 | }
52 |
53 | @OnClick(R.id.loadBt)
54 | void load() {
55 | swipeRefreshLayout.setRefreshing(true);
56 | startingTime = System.currentTimeMillis();
57 | unsubscribe();
58 | disposable = Data.getInstance()
59 | .subscribeData(new Consumer
>() {
60 | @Override
61 | public void accept(@NonNull List- items) throws Exception {
62 | swipeRefreshLayout.setRefreshing(false);
63 | int loadingTime = (int) (System.currentTimeMillis() - startingTime);
64 | loadingTimeTv.setText(getString(R.string.loading_time_and_source, loadingTime, Data.getInstance().getDataSourceText()));
65 | adapter.setItems(items);
66 | }
67 | }, new Consumer() {
68 | @Override
69 | public void accept(@NonNull Throwable throwable) throws Exception {
70 | throwable.printStackTrace();
71 | swipeRefreshLayout.setRefreshing(false);
72 | Toast.makeText(getActivity(), R.string.loading_failed, Toast.LENGTH_SHORT).show();
73 | }
74 | });
75 | }
76 |
77 | @Nullable
78 | @Override
79 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
80 | View view = inflater.inflate(R.layout.fragment_cache, container, false);
81 | ButterKnife.bind(this, view);
82 | cacheRv.setLayoutManager(new GridLayoutManager(getActivity(), 2));
83 | cacheRv.setAdapter(adapter);
84 | swipeRefreshLayout.setColorSchemeColors(Color.BLUE, Color.GREEN, Color.RED, Color.YELLOW);
85 | swipeRefreshLayout.setEnabled(false);
86 | return view;
87 | }
88 |
89 | @Override
90 | protected int getDialogRes() {
91 | return R.layout.dialog_cache;
92 | }
93 |
94 | @Override
95 | protected int getTitleRes() {
96 | return R.string.title_cache;
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/app/src/main/java/com/rengwuxian/rxjavasamples/module/cache_6/data/Data.java:
--------------------------------------------------------------------------------
1 | // (c)2016 Flipboard Inc, All Rights Reserved.
2 |
3 | package com.rengwuxian.rxjavasamples.module.cache_6.data;
4 |
5 | import android.support.annotation.IntDef;
6 | import android.support.annotation.NonNull;
7 |
8 | import com.rengwuxian.rxjavasamples.App;
9 | import com.rengwuxian.rxjavasamples.network.Network;
10 | import com.rengwuxian.rxjavasamples.R;
11 | import com.rengwuxian.rxjavasamples.model.Item;
12 | import com.rengwuxian.rxjavasamples.util.GankBeautyResultToItemsMapper;
13 |
14 | import java.util.List;
15 |
16 | import io.reactivex.Observable;
17 | import io.reactivex.ObservableEmitter;
18 | import io.reactivex.ObservableOnSubscribe;
19 | import io.reactivex.Observer;
20 | import io.reactivex.android.schedulers.AndroidSchedulers;
21 | import io.reactivex.disposables.Disposable;
22 | import io.reactivex.functions.Consumer;
23 | import io.reactivex.observers.DefaultObserver;
24 | import io.reactivex.schedulers.Schedulers;
25 | import io.reactivex.subjects.BehaviorSubject;
26 |
27 | public class Data {
28 | private static Data instance;
29 | private static final int DATA_SOURCE_MEMORY = 1;
30 | private static final int DATA_SOURCE_DISK = 2;
31 | private static final int DATA_SOURCE_NETWORK = 3;
32 |
33 | @IntDef({DATA_SOURCE_MEMORY, DATA_SOURCE_DISK, DATA_SOURCE_NETWORK})
34 | @interface DataSource {
35 | }
36 |
37 | BehaviorSubject
> cache;
38 |
39 | private int dataSource;
40 |
41 | private Data() {
42 | }
43 |
44 | public static Data getInstance() {
45 | if (instance == null) {
46 | instance = new Data();
47 | }
48 | return instance;
49 | }
50 |
51 | private void setDataSource(@DataSource int dataSource) {
52 | this.dataSource = dataSource;
53 | }
54 |
55 | public String getDataSourceText() {
56 | int dataSourceTextRes;
57 | switch (dataSource) {
58 | case DATA_SOURCE_MEMORY:
59 | dataSourceTextRes = R.string.data_source_memory;
60 | break;
61 | case DATA_SOURCE_DISK:
62 | dataSourceTextRes = R.string.data_source_disk;
63 | break;
64 | case DATA_SOURCE_NETWORK:
65 | dataSourceTextRes = R.string.data_source_network;
66 | break;
67 | default:
68 | dataSourceTextRes = R.string.data_source_network;
69 | }
70 | return App.getInstance().getString(dataSourceTextRes);
71 | }
72 |
73 | public void loadFromNetwork() {
74 | Network.getGankApi()
75 | .getBeauties(100, 1)
76 | .subscribeOn(Schedulers.io())
77 | .map(GankBeautyResultToItemsMapper.getInstance())
78 | .doOnNext(new Consumer>() {
79 | @Override
80 | public void accept(List- items) {
81 | Database.getInstance().writeItems(items);
82 | }
83 | })
84 | .subscribe(new Consumer
>() {
85 | @Override
86 | public void accept(List- items) {
87 | cache.onNext(items);
88 | }
89 | }, new Consumer() {
90 | @Override
91 | public void accept(Throwable throwable) {
92 | throwable.printStackTrace();
93 | cache.onError(throwable);
94 | }
95 | });
96 | }
97 |
98 | public Disposable subscribeData(@NonNull Consumer
> onNext, @NonNull Consumer onError) {
99 | if (cache == null) {
100 | cache = BehaviorSubject.create();
101 | Observable.create(new ObservableOnSubscribe>() {
102 | @Override
103 | public void subscribe(ObservableEmitter> e) throws Exception {
104 | List- items = Database.getInstance().readItems();
105 | if (items == null) {
106 | setDataSource(DATA_SOURCE_NETWORK);
107 | loadFromNetwork();
108 | } else {
109 | setDataSource(DATA_SOURCE_DISK);
110 | e.onNext(items);
111 | }
112 | }
113 | })
114 | .subscribeOn(Schedulers.io())
115 | .subscribe(cache);
116 | } else {
117 | setDataSource(DATA_SOURCE_MEMORY);
118 | }
119 | return cache.doOnError(new Consumer() {
120 | @Override
121 | public void accept(@io.reactivex.annotations.NonNull Throwable throwable) throws Exception {
122 | cache = null;
123 | }
124 | })
125 | .observeOn(AndroidSchedulers.mainThread())
126 | .subscribe(onNext, onError);
127 | }
128 |
129 | public void clearMemoryCache() {
130 | cache = null;
131 | }
132 |
133 | public void clearMemoryAndDiskCache() {
134 | clearMemoryCache();
135 | Database.getInstance().delete();
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/app/src/main/java/com/rengwuxian/rxjavasamples/module/cache_6/data/Database.java:
--------------------------------------------------------------------------------
1 | // (c)2016 Flipboard Inc, All Rights Reserved.
2 |
3 | package com.rengwuxian.rxjavasamples.module.cache_6.data;
4 |
5 | import com.google.gson.Gson;
6 | import com.google.gson.reflect.TypeToken;
7 | import com.rengwuxian.rxjavasamples.App;
8 | import com.rengwuxian.rxjavasamples.model.Item;
9 |
10 | import java.io.File;
11 | import java.io.FileNotFoundException;
12 | import java.io.FileReader;
13 | import java.io.FileWriter;
14 | import java.io.IOException;
15 | import java.io.Reader;
16 | import java.io.Writer;
17 | import java.util.List;
18 |
19 | public class Database {
20 | private static String DATA_FILE_NAME = "data.db";
21 |
22 | private static Database INSTANCE;
23 |
24 | File dataFile = new File(App.getInstance().getFilesDir(), DATA_FILE_NAME);
25 | Gson gson = new Gson();
26 |
27 | private Database() {
28 | }
29 |
30 | public static Database getInstance() {
31 | if (INSTANCE == null) {
32 | INSTANCE = new Database();
33 | }
34 | return INSTANCE;
35 | }
36 |
37 | public List
- readItems() {
38 | // Hard code adding some delay, to distinguish reading from memory and reading disk clearly
39 | try {
40 | Thread.sleep(100);
41 | } catch (InterruptedException e) {
42 | e.printStackTrace();
43 | }
44 |
45 | try {
46 | Reader reader = new FileReader(dataFile);
47 | return gson.fromJson(reader, new TypeToken
>(){}.getType());
48 | } catch (FileNotFoundException e) {
49 | e.printStackTrace();
50 | return null;
51 | }
52 | }
53 |
54 | public void writeItems(List- items) {
55 | String json = gson.toJson(items);
56 | try {
57 | if (!dataFile.exists()) {
58 | try {
59 | dataFile.createNewFile();
60 | } catch (IOException e) {
61 | e.printStackTrace();
62 | }
63 | }
64 | Writer writer = new FileWriter(dataFile);
65 | writer.write(json);
66 | writer.flush();
67 | } catch (IOException e) {
68 | e.printStackTrace();
69 | }
70 | }
71 |
72 | public void delete() {
73 | dataFile.delete();
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/app/src/main/java/com/rengwuxian/rxjavasamples/module/elementary_1/ElementaryFragment.java:
--------------------------------------------------------------------------------
1 | // (c)2016 Flipboard Inc, All Rights Reserved.
2 |
3 | package com.rengwuxian.rxjavasamples.module.elementary_1;
4 |
5 | import android.graphics.Color;
6 | import android.os.Bundle;
7 | import android.support.annotation.Nullable;
8 | import android.support.v4.widget.SwipeRefreshLayout;
9 | import android.support.v7.widget.GridLayoutManager;
10 | import android.support.v7.widget.RecyclerView;
11 | import android.view.LayoutInflater;
12 | import android.view.View;
13 | import android.view.ViewGroup;
14 | import android.widget.RadioButton;
15 | import android.widget.Toast;
16 |
17 | import com.rengwuxian.rxjavasamples.BaseFragment;
18 | import com.rengwuxian.rxjavasamples.network.Network;
19 | import com.rengwuxian.rxjavasamples.R;
20 | import com.rengwuxian.rxjavasamples.adapter.ZhuangbiListAdapter;
21 | import com.rengwuxian.rxjavasamples.model.ZhuangbiImage;
22 |
23 | import java.util.List;
24 |
25 | import butterknife.BindView;
26 | import butterknife.ButterKnife;
27 | import butterknife.OnCheckedChanged;
28 | import io.reactivex.Observer;
29 | import io.reactivex.android.schedulers.AndroidSchedulers;
30 | import io.reactivex.annotations.NonNull;
31 | import io.reactivex.functions.Consumer;
32 | import io.reactivex.schedulers.Schedulers;
33 |
34 | public class ElementaryFragment extends BaseFragment {
35 | @BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout swipeRefreshLayout;
36 | @BindView(R.id.gridRv) RecyclerView gridRv;
37 |
38 | ZhuangbiListAdapter adapter = new ZhuangbiListAdapter();
39 |
40 | @OnCheckedChanged({R.id.searchRb1, R.id.searchRb2, R.id.searchRb3, R.id.searchRb4})
41 | void onTagChecked(RadioButton searchRb, boolean checked) {
42 | if (checked) {
43 | unsubscribe();
44 | adapter.setImages(null);
45 | swipeRefreshLayout.setRefreshing(true);
46 | search(searchRb.getText().toString());
47 | }
48 | }
49 |
50 | private void search(String key) {
51 | disposable = Network.getZhuangbiApi()
52 | .search(key)
53 | .subscribeOn(Schedulers.io())
54 | .observeOn(AndroidSchedulers.mainThread())
55 | .subscribe(new Consumer
>() {
56 | @Override
57 | public void accept(@NonNull List images) throws Exception {
58 | swipeRefreshLayout.setRefreshing(false);
59 | adapter.setImages(images);
60 | }
61 | }, new Consumer() {
62 | @Override
63 | public void accept(@NonNull Throwable throwable) throws Exception {
64 | swipeRefreshLayout.setRefreshing(false);
65 | Toast.makeText(getActivity(), R.string.loading_failed, Toast.LENGTH_SHORT).show();
66 | }
67 | });
68 | }
69 |
70 | @Nullable
71 | @Override
72 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
73 | View view = inflater.inflate(R.layout.fragment_elementary, container, false);
74 | ButterKnife.bind(this, view);
75 |
76 | gridRv.setLayoutManager(new GridLayoutManager(getActivity(), 2));
77 | gridRv.setAdapter(adapter);
78 | swipeRefreshLayout.setColorSchemeColors(Color.BLUE, Color.GREEN, Color.RED, Color.YELLOW);
79 | swipeRefreshLayout.setEnabled(false);
80 |
81 | return view;
82 | }
83 |
84 | @Override
85 | protected int getDialogRes() {
86 | return R.layout.dialog_elementary;
87 | }
88 |
89 | @Override
90 | protected int getTitleRes() {
91 | return R.string.title_elementary;
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/app/src/main/java/com/rengwuxian/rxjavasamples/module/map_2/MapFragment.java:
--------------------------------------------------------------------------------
1 | // (c)2016 Flipboard Inc, All Rights Reserved.
2 |
3 | package com.rengwuxian.rxjavasamples.module.map_2;
4 |
5 | import android.graphics.Color;
6 | import android.os.Bundle;
7 | import android.support.annotation.Nullable;
8 | import android.support.v4.widget.SwipeRefreshLayout;
9 | import android.support.v7.widget.RecyclerView;
10 | import android.support.v7.widget.StaggeredGridLayoutManager;
11 | import android.view.LayoutInflater;
12 | import android.view.View;
13 | import android.view.ViewGroup;
14 | import android.widget.Button;
15 | import android.widget.TextView;
16 | import android.widget.Toast;
17 |
18 | import com.rengwuxian.rxjavasamples.BaseFragment;
19 | import com.rengwuxian.rxjavasamples.network.Network;
20 | import com.rengwuxian.rxjavasamples.R;
21 | import com.rengwuxian.rxjavasamples.adapter.ItemListAdapter;
22 | import com.rengwuxian.rxjavasamples.model.Item;
23 | import com.rengwuxian.rxjavasamples.util.GankBeautyResultToItemsMapper;
24 |
25 | import java.util.List;
26 |
27 | import butterknife.BindView;
28 | import butterknife.ButterKnife;
29 | import butterknife.OnClick;
30 | import io.reactivex.Observer;
31 | import io.reactivex.android.schedulers.AndroidSchedulers;
32 | import io.reactivex.annotations.NonNull;
33 | import io.reactivex.functions.Consumer;
34 | import io.reactivex.schedulers.Schedulers;
35 |
36 | public class MapFragment extends BaseFragment {
37 | private int page = 0;
38 |
39 | @BindView(R.id.pageTv) TextView pageTv;
40 | @BindView(R.id.previousPageBt) Button previousPageBt;
41 | @BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout swipeRefreshLayout;
42 | @BindView(R.id.gridRv) RecyclerView gridRv;
43 |
44 | ItemListAdapter adapter = new ItemListAdapter();
45 |
46 | @OnClick(R.id.previousPageBt)
47 | void previousPage() {
48 | loadPage(--page);
49 | if (page == 1) {
50 | previousPageBt.setEnabled(false);
51 | }
52 | }
53 |
54 | @OnClick(R.id.nextPageBt)
55 | void nextPage() {
56 | loadPage(++page);
57 | if (page == 2) {
58 | previousPageBt.setEnabled(true);
59 | }
60 | }
61 |
62 | private void loadPage(int page) {
63 | swipeRefreshLayout.setRefreshing(true);
64 | unsubscribe();
65 | disposable = Network.getGankApi()
66 | .getBeauties(10, page)
67 | .map(GankBeautyResultToItemsMapper.getInstance())
68 | .subscribeOn(Schedulers.io())
69 | .observeOn(AndroidSchedulers.mainThread())
70 | .subscribe(new Consumer>() {
71 | @Override
72 | public void accept(@NonNull List- items) throws Exception {
73 | swipeRefreshLayout.setRefreshing(false);
74 | pageTv.setText(getString(R.string.page_with_number, MapFragment.this.page));
75 | adapter.setItems(items);
76 | }
77 | }, new Consumer() {
78 | @Override
79 | public void accept(@NonNull Throwable throwable) throws Exception {
80 | swipeRefreshLayout.setRefreshing(false);
81 | Toast.makeText(getActivity(), R.string.loading_failed, Toast.LENGTH_SHORT).show();
82 | }
83 | });
84 | }
85 |
86 | @Nullable
87 | @Override
88 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
89 | View view = inflater.inflate(R.layout.fragment_map, container, false);
90 | ButterKnife.bind(this, view);
91 |
92 | gridRv.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));
93 | gridRv.setAdapter(adapter);
94 | swipeRefreshLayout.setColorSchemeColors(Color.BLUE, Color.GREEN, Color.RED, Color.YELLOW);
95 | swipeRefreshLayout.setEnabled(false);
96 | return view;
97 | }
98 |
99 | @Override
100 | protected int getDialogRes() {
101 | return R.layout.dialog_map;
102 | }
103 |
104 | @Override
105 | protected int getTitleRes() {
106 | return R.string.title_map;
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/app/src/main/java/com/rengwuxian/rxjavasamples/module/token_4/TokenFragment.java:
--------------------------------------------------------------------------------
1 | // (c)2016 Flipboard Inc, All Rights Reserved.
2 |
3 | package com.rengwuxian.rxjavasamples.module.token_4;
4 |
5 | import android.graphics.Color;
6 | import android.os.Bundle;
7 | import android.support.annotation.Nullable;
8 | import android.support.v4.widget.SwipeRefreshLayout;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.widget.TextView;
13 | import android.widget.Toast;
14 |
15 | import com.rengwuxian.rxjavasamples.BaseFragment;
16 | import com.rengwuxian.rxjavasamples.network.Network;
17 | import com.rengwuxian.rxjavasamples.R;
18 | import com.rengwuxian.rxjavasamples.network.api.FakeApi;
19 | import com.rengwuxian.rxjavasamples.model.FakeThing;
20 | import com.rengwuxian.rxjavasamples.model.FakeToken;
21 |
22 | import butterknife.BindView;
23 | import butterknife.ButterKnife;
24 | import butterknife.OnClick;
25 | import io.reactivex.Observable;
26 | import io.reactivex.android.schedulers.AndroidSchedulers;
27 | import io.reactivex.functions.Consumer;
28 | import io.reactivex.functions.Function;
29 | import io.reactivex.schedulers.Schedulers;
30 |
31 | public class TokenFragment extends BaseFragment {
32 |
33 | @BindView(R.id.tokenTv) TextView tokenTv;
34 | @BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout swipeRefreshLayout;
35 |
36 | @OnClick(R.id.requestBt)
37 | void upload() {
38 | swipeRefreshLayout.setRefreshing(true);
39 | unsubscribe();
40 | final FakeApi fakeApi = Network.getFakeApi();
41 | disposable = fakeApi.getFakeToken("fake_auth_code")
42 | .flatMap(new Function>() {
43 | @Override
44 | public Observable apply(FakeToken fakeToken) {
45 | return fakeApi.getFakeData(fakeToken);
46 | }
47 | })
48 | .subscribeOn(Schedulers.io())
49 | .observeOn(AndroidSchedulers.mainThread())
50 | .subscribe(new Consumer() {
51 | @Override
52 | public void accept(FakeThing fakeData) {
53 | swipeRefreshLayout.setRefreshing(false);
54 | tokenTv.setText(getString(R.string.got_data, fakeData.id, fakeData.name));
55 | }
56 | }, new Consumer() {
57 | @Override
58 | public void accept(Throwable throwable) {
59 | swipeRefreshLayout.setRefreshing(false);
60 | Toast.makeText(getActivity(), R.string.loading_failed, Toast.LENGTH_SHORT).show();
61 | }
62 | });
63 | }
64 |
65 | @Nullable
66 | @Override
67 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
68 | View view = inflater.inflate(R.layout.fragment_token, container, false);
69 | ButterKnife.bind(this, view);
70 | swipeRefreshLayout.setColorSchemeColors(Color.BLUE, Color.GREEN, Color.RED, Color.YELLOW);
71 | swipeRefreshLayout.setEnabled(false);
72 | return view;
73 | }
74 |
75 | @Override
76 | protected int getDialogRes() {
77 | return R.layout.dialog_token;
78 | }
79 |
80 | @Override
81 | protected int getTitleRes() {
82 | return R.string.title_token;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/app/src/main/java/com/rengwuxian/rxjavasamples/module/token_advanced_5/TokenAdvancedFragment.java:
--------------------------------------------------------------------------------
1 | // (c)2016 Flipboard Inc, All Rights Reserved.
2 |
3 | package com.rengwuxian.rxjavasamples.module.token_advanced_5;
4 |
5 | import android.graphics.Color;
6 | import android.os.Bundle;
7 | import android.support.annotation.Nullable;
8 | import android.support.v4.widget.SwipeRefreshLayout;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.widget.TextView;
13 | import android.widget.Toast;
14 |
15 | import com.rengwuxian.rxjavasamples.BaseFragment;
16 | import com.rengwuxian.rxjavasamples.network.Network;
17 | import com.rengwuxian.rxjavasamples.R;
18 | import com.rengwuxian.rxjavasamples.network.api.FakeApi;
19 | import com.rengwuxian.rxjavasamples.model.FakeThing;
20 | import com.rengwuxian.rxjavasamples.model.FakeToken;
21 |
22 | import butterknife.BindView;
23 | import butterknife.ButterKnife;
24 | import butterknife.OnClick;
25 | import io.reactivex.Observable;
26 | import io.reactivex.android.schedulers.AndroidSchedulers;
27 | import io.reactivex.functions.Consumer;
28 | import io.reactivex.functions.Function;
29 | import io.reactivex.schedulers.Schedulers;
30 |
31 | public class TokenAdvancedFragment extends BaseFragment {
32 |
33 | @BindView(R.id.tokenTv) TextView tokenTv;
34 | @BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout swipeRefreshLayout;
35 | final FakeToken cachedFakeToken = new FakeToken(true);
36 | boolean tokenUpdated;
37 |
38 | @OnClick(R.id.invalidateTokenBt)
39 | void invalidateToken() {
40 | cachedFakeToken.expired = true;
41 | Toast.makeText(getActivity(), R.string.token_destroyed, Toast.LENGTH_SHORT).show();
42 | }
43 |
44 | @OnClick(R.id.requestBt)
45 | void upload() {
46 | tokenUpdated = false;
47 | swipeRefreshLayout.setRefreshing(true);
48 | unsubscribe();
49 | final FakeApi fakeApi = Network.getFakeApi();
50 | disposable = Observable.just(1)
51 | .flatMap(new Function