APP实用开发—RxJava 和 Retrofit 结合使用
来源:互联网 发布:淘宝卖家如何实名认证 编辑:程序博客网 时间:2024/04/30 02:51
RxJava 和 Retrofit 结合使用的几个最常见使用方式举例。
RxJava中有个叫做Subscription的接口,可以用来取消订阅.
public interface Subscription { void unsubscribe(); boolean isUnsubscribed();}
从上面可以看到,我们只需要调用unsubscribe就可以取消订阅
Observable.subscribe()方法可以返回一个Subscription的对象,即我们每次订阅都会返回.
感觉Subscription就像一个订单,你下单了就会生成一个订单,而你也可以用这个订单取消订单.
基本使用
main.xml文件
<?xml version="1.0" encoding="utf-8"?><LinearLayout 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:orientation="vertical" tools:context="com.rengwuxian.rxjavasamples.MainActivity"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" app:elevation="12dp" app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <android.support.v7.widget.Toolbar android:id="@+id/toolBar" android:layout_width="match_parent" android:layout_height="wrap_content" /> <android.support.design.widget.TabLayout android:id="@android:id/tabs" android:layout_width="match_parent" android:layout_height="48dp" app:tabMode="scrollable" /> </android.support.design.widget.AppBarLayout> <android.support.v4.view.ViewPager android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="match_parent" /></LinearLayout>
main.java
public class MainActivity extends AppCompatActivity { @Bind(android.R.id.tabs) TabLayout tabLayout; @Bind(R.id.viewPager) ViewPager viewPager; @Bind(R.id.toolBar) Toolbar toolBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); setSupportActionBar(toolBar); viewPager.setAdapter(new FragmentPagerAdapter(getFragmentManager()) { @Override public int getCount() { return 6; } @Override public Fragment getItem(int position) { switch (position) { case 0: return new ElementaryFragment(); case 1: return new MapFragment(); case 2: return new ZipFragment(); case 3: return new TokenFragment(); case 4: return new TokenAdvancedFragment(); case 5: return new CacheFragment(); default: return new ElementaryFragment(); } } @Override public CharSequence getPageTitle(int position) { switch (position) { case 0: return getString(R.string.title_elementary); case 1: return getString(R.string.title_map); case 2: return getString(R.string.title_zip); case 3: return getString(R.string.title_token); case 4: return getString(R.string.title_token_advanced); case 5: return getString(R.string.title_cache); default: return getString(R.string.title_elementary); } } }); tabLayout.setupWithViewPager(viewPager); }}
BaseFragment
public abstract class BaseFragment extends Fragment { protected Subscription subscription; @OnClick(R.id.tipBt) void tip() { new AlertDialog.Builder(getActivity()) .setTitle(getTitleRes()) .setView(getActivity().getLayoutInflater().inflate(getDialogRes(), null)) .show(); } @Override public void onDestroyView() { super.onDestroyView(); unsubscribe();//注销订阅 } protected void unsubscribe() { if (subscription != null && !subscription.isUnsubscribed()) { subscription.unsubscribe(); } } protected abstract int getDialogRes(); protected abstract int getTitleRes();}
App
public class App extends Application { private static App INSTANCE; public static App getInstance() { return INSTANCE; } @Override public void onCreate() { super.onCreate(); INSTANCE = this; }}
Network
public class Network { private static ZhuangbiApi zhuangbiApi; private static GankApi gankApi; private static FakeApi fakeApi; private static OkHttpClient okHttpClient = new OkHttpClient(); private static Converter.Factory gsonConverterFactory = GsonConverterFactory.create(); private static CallAdapter.Factory rxJavaCallAdapterFactory = RxJavaCallAdapterFactory.create(); public static ZhuangbiApi getZhuangbiApi() { if (zhuangbiApi == null) { Retrofit retrofit = new Retrofit.Builder() .client(okHttpClient) .baseUrl("http://www.zhuangbi.info/") .addConverterFactory(gsonConverterFactory) .addCallAdapterFactory(rxJavaCallAdapterFactory) .build(); zhuangbiApi = retrofit.create(ZhuangbiApi.class); } return zhuangbiApi; } public static GankApi getGankApi() { if (gankApi == null) { Retrofit retrofit = new Retrofit.Builder() .client(okHttpClient) .baseUrl("http://gank.io/api/") .addConverterFactory(gsonConverterFactory) .addCallAdapterFactory(rxJavaCallAdapterFactory) .build(); gankApi = retrofit.create(GankApi.class); } return gankApi; } public static FakeApi getFakeApi() { if (fakeApi == null) { fakeApi = new FakeApi(); } return fakeApi; }}
1.实现最基本的网络请求和结果处理页面。
适配器
public class ZhuangbiListAdapter extends RecyclerView.Adapter { List<ZhuangbiImage> images; @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.grid_item, parent, false); return new DebounceViewHolder(view); } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { DebounceViewHolder debounceViewHolder = (DebounceViewHolder) holder; ZhuangbiImage image = images.get(position); Glide.with(holder.itemView.getContext()).load(image.image_url).into(debounceViewHolder.imageIv); debounceViewHolder.descriptionTv.setText(image.description); } @Override public int getItemCount() { return images == null ? 0 : images.size(); } public void setImages(List<ZhuangbiImage> images) { this.images = images; notifyDataSetChanged(); } static class DebounceViewHolder extends RecyclerView.ViewHolder { @Bind(R.id.imageIv) ImageView imageIv; @Bind(R.id.descriptionTv) TextView descriptionTv; public DebounceViewHolder(View itemView) { super(itemView); ButterKnife.bind(this, itemView); } }}
R.layout.grid_item
<?xml version="1.0" encoding="utf-8"?><android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="4dp" android:layout_marginBottom="4dp" android:layout_marginStart="8dp" android:layout_marginEnd="8dp" app:cardCornerRadius="2dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="4dp" android:orientation="vertical"> <ImageView android:id="@+id/imageIv" android:layout_width="match_parent" android:layout_height="160dp" /> <TextView android:id="@+id/descriptionTv" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="14sp" /> </LinearLayout></android.support.v7.widget.CardView>
Fragment页面布局
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical"> <RadioGroup android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" android:orientation="horizontal"> <android.support.v7.widget.AppCompatRadioButton android:id="@+id/searchRb1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="可爱" /> <android.support.v7.widget.AppCompatRadioButton android:id="@+id/searchRb2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="110" /> <android.support.v7.widget.AppCompatRadioButton android:id="@+id/searchRb3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="在下" /> <android.support.v7.widget.AppCompatRadioButton android:id="@+id/searchRb4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="装逼" /> </RadioGroup> <include layout="@layout/tip_bt" /> </LinearLayout> <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/swipeRefreshLayout" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:id="@+id/gridRv" android:layout_width="match_parent" android:layout_height="match_parent" /> </android.support.v4.widget.SwipeRefreshLayout></LinearLayout>
public interface ZhuangbiApi { @GET("search") Observable<List<ZhuangbiImage>> search(@Query("q") String query);}
ElementaryFragment
public class ElementaryFragment extends BaseFragment { @Bind(R.id.swipeRefreshLayout) SwipeRefreshLayout swipeRefreshLayout; @Bind(R.id.gridRv) RecyclerView gridRv; ZhuangbiListAdapter adapter = new ZhuangbiListAdapter(); Observer<List<ZhuangbiImage>> observer = new Observer<List<ZhuangbiImage>>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { swipeRefreshLayout.setRefreshing(false); Toast.makeText(getActivity(), R.string.loading_failed, Toast.LENGTH_SHORT).show(); } @Override public void onNext(List<ZhuangbiImage> images) { swipeRefreshLayout.setRefreshing(false); adapter.setImages(images); } }; @OnCheckedChanged({R.id.searchRb1, R.id.searchRb2, R.id.searchRb3, R.id.searchRb4}) void onTagChecked(RadioButton searchRb, boolean checked) { if (checked) { unsubscribe(); adapter.setImages(null); swipeRefreshLayout.setRefreshing(true); search(searchRb.getText().toString()); } } private void search(String key) { subscription = Network.getZhuangbiApi() .search(key) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(observer); } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_elementary, container, false); ButterKnife.bind(this, view); gridRv.setLayoutManager(new GridLayoutManager(getActivity(), 2)); gridRv.setAdapter(adapter); swipeRefreshLayout.setColorSchemeColors(Color.BLUE, Color.GREEN, Color.RED, Color.YELLOW); swipeRefreshLayout.setEnabled(false); return view; } @Override protected int getDialogRes() { return R.layout.dialog_elementary; } @Override protected int getTitleRes() { return R.string.title_elementary; }}
转换(map)
把返回的数据转换成更方便处理的格式再交给 Observer。
源码功能接口
public interface Function {}public interface Func1<T, R> extends Function { R call(T t);}
model
public class GankBeautyResult { public boolean error; public @SerializedName("results") List<GankBeauty> beauties;}
实现功能转换
由什么转换成什么
public class GankBeautyResultToItemsMapper implements Func1<GankBeautyResult, List<Item>> { private static GankBeautyResultToItemsMapper INSTANCE = new GankBeautyResultToItemsMapper(); private GankBeautyResultToItemsMapper() { } public static GankBeautyResultToItemsMapper getInstance() { return INSTANCE; } @Override public List<Item> call(GankBeautyResult gankBeautyResult) { List<GankBeauty> gankBeauties = gankBeautyResult.beauties; List<Item> items = new ArrayList<>(gankBeauties.size()); SimpleDateFormat inputFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SS'Z'"); SimpleDateFormat outputFormat = new SimpleDateFormat("yy/MM/dd HH:mm:ss"); for (GankBeauty gankBeauty : gankBeauties) { Item item = new Item(); try { Date date = inputFormat.parse(gankBeauty.createdAt); item.description = outputFormat.format(date); } catch (ParseException e) { e.printStackTrace(); item.description = "unknown date"; } item.imageUrl = gankBeauty.url; items.add(item); } return items; }}
适配器
public class ItemListAdapter extends RecyclerView.Adapter { List<Item> images; @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.grid_item, parent, false); return new DebounceViewHolder(view); } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { DebounceViewHolder debounceViewHolder = (DebounceViewHolder) holder; Item image = images.get(position); Glide.with(holder.itemView.getContext()).load(image.imageUrl).into(debounceViewHolder.imageIv); debounceViewHolder.descriptionTv.setText(image.description); } @Override public int getItemCount() { return images == null ? 0 : images.size(); } public void setItems(List<Item> images) { this.images = images; notifyDataSetChanged(); } static class DebounceViewHolder extends RecyclerView.ViewHolder { @Bind(R.id.imageIv) ImageView imageIv; @Bind(R.id.descriptionTv) TextView descriptionTv; public DebounceViewHolder(View itemView) { super(itemView); ButterKnife.bind(this, itemView); } }}
R.layout.fragment_map
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingStart="8dp" android:paddingEnd="8dp"> <TextView android:id="@+id/pageTv" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" /> <android.support.v7.widget.AppCompatButton android:id="@+id/previousPageBt" android:layout_width="80dp" android:layout_height="wrap_content" android:enabled="false" android:text="@string/previous_page" /> <android.support.v7.widget.AppCompatButton android:id="@+id/nextPageBt" android:layout_width="80dp" android:layout_height="wrap_content" android:text="@string/next_page" android:layout_marginEnd="16dp" android:layout_marginRight="16dp"/> <include layout="@layout/tip_bt" /> </LinearLayout> <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/swipeRefreshLayout" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:id="@+id/gridRv" android:layout_width="match_parent" android:layout_height="match_parent" /> </android.support.v4.widget.SwipeRefreshLayout></LinearLayout>
GankApi
public interface GankApi { @GET("data/福利/{number}/{page}") Observable<GankBeautyResult> getBeauties(@Path("number") int number, @Path("page") int page);
MapFragment
public class MapFragment extends BaseFragment { private int page = 0; @Bind(R.id.pageTv) TextView pageTv; @Bind(R.id.previousPageBt) Button previousPageBt; @Bind(R.id.swipeRefreshLayout) SwipeRefreshLayout swipeRefreshLayout; @Bind(R.id.gridRv) RecyclerView gridRv; ItemListAdapter adapter = new ItemListAdapter(); Observer<List<Item>> observer = new Observer<List<Item>>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { swipeRefreshLayout.setRefreshing(false); Toast.makeText(getActivity(), R.string.loading_failed, Toast.LENGTH_SHORT).show(); } @Override public void onNext(List<Item> images) { swipeRefreshLayout.setRefreshing(false); pageTv.setText(getString(R.string.page_with_number, page)); adapter.setItems(images); } }; @OnClick(R.id.previousPageBt) void previousPage() { loadPage(--page); if (page == 1) { previousPageBt.setEnabled(false); } } @OnClick(R.id.nextPageBt) void nextPage() { loadPage(++page); if (page == 2) { previousPageBt.setEnabled(true); } } private void loadPage(int page) { swipeRefreshLayout.setRefreshing(true); unsubscribe(); subscription = Network.getGankApi() .getBeauties(10, page) .map(GankBeautyResultToItemsMapper.getInstance()) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(observer); } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_map, container, false); ButterKnife.bind(this, view); gridRv.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)); gridRv.setAdapter(adapter); swipeRefreshLayout.setColorSchemeColors(Color.BLUE, Color.GREEN, Color.RED, Color.YELLOW); swipeRefreshLayout.setEnabled(false); return view; } @Override protected int getDialogRes() { return R.layout.dialog_map; } @Override protected int getTitleRes() { return R.string.title_map; }}
压合(zip)
将不同接口并行请求获取到的数据糅合在一起后再处理。
public class ZipFragment extends BaseFragment { @Bind(R.id.gridRv) RecyclerView gridRv; @Bind(R.id.swipeRefreshLayout) SwipeRefreshLayout swipeRefreshLayout; ItemListAdapter adapter = new ItemListAdapter(); Observer<List<Item>> observer = new Observer<List<Item>>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { swipeRefreshLayout.setRefreshing(false); Toast.makeText(getActivity(), R.string.loading_failed, Toast.LENGTH_SHORT).show(); } @Override public void onNext(List<Item> items) { swipeRefreshLayout.setRefreshing(false); adapter.setItems(items); } }; @OnClick(R.id.zipLoadBt) void load() { swipeRefreshLayout.setRefreshing(true); unsubscribe(); subscription = Observable.zip(Network.getGankApi().getBeauties(200, 1).map(GankBeautyResultToItemsMapper.getInstance()), Network.getZhuangbiApi().search("装逼"), new Func2<List<Item>, List<ZhuangbiImage>, List<Item>>() { @Override public List<Item> call(List<Item> gankItems, List<ZhuangbiImage> zhuangbiImages) { List<Item> items = new ArrayList<Item>(); for (int i = 0; i < gankItems.size() / 2 && i < zhuangbiImages.size(); i++) { items.add(gankItems.get(i * 2)); items.add(gankItems.get(i * 2 + 1)); Item zhuangbiItem = new Item(); ZhuangbiImage zhuangbiImage = zhuangbiImages.get(i); zhuangbiItem.description = zhuangbiImage.description; zhuangbiItem.imageUrl = zhuangbiImage.image_url; items.add(zhuangbiItem); } return items; } }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(observer); } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_zip, container, false); ButterKnife.bind(this, view); gridRv.setLayoutManager(new GridLayoutManager(getActivity(), 2)); gridRv.setAdapter(adapter); swipeRefreshLayout.setColorSchemeColors(Color.BLUE, Color.GREEN, Color.RED, Color.YELLOW); swipeRefreshLayout.setEnabled(false); return view; } @Override protected int getDialogRes() { return R.layout.dialog_zip; } @Override protected int getTitleRes() { return R.string.title_zip; }}
一次性 token
token其实说的更通俗点可以叫暗号,在一些数据传输之前,要先进行暗号的核对,不同的暗号被授权不同的数据操作。例如在USB1.1协议中定义了4类数据包:token包、data包、handshake包和special包。主机和USB设备之间连续数据的交换可以分为三个阶段,第一个阶段由主机发送token包,不同的token包内容不一样(暗号不一样)可以告诉设备做不同的工作,第二个阶段发送data包,第三个阶段由设备返回一个handshake包。
需要先请求 token 再访问的接口,使用 flatMap() 将 token 的请求和实际数据的请求连贯地串起来,而不必写嵌套的 Callback 结构。
FakeApi
public class FakeApi { Random random = new Random(); public Observable<FakeToken> getFakeToken(@NonNull String fakeAuth) { return Observable.just(fakeAuth) .map(new Func1<String, FakeToken>() { @Override public FakeToken call(String fakeAuth) { // Add some random delay to mock the network delay int fakeNetworkTimeCost = random.nextInt(500) + 500; try { Thread.sleep(fakeNetworkTimeCost); } catch (InterruptedException e) { e.printStackTrace(); } FakeToken fakeToken = new FakeToken(); fakeToken.token = createToken(); return fakeToken; } }); } private static String createToken() { return "fake_token_" + System.currentTimeMillis() % 10000; } public Observable<FakeThing> getFakeData(FakeToken fakeToken) { return Observable.just(fakeToken) .map(new Func1<FakeToken, FakeThing>() { @Override public FakeThing call(FakeToken fakeToken) { // Add some random delay to mock the network delay int fakeNetworkTimeCost = random.nextInt(500) + 500; try { Thread.sleep(fakeNetworkTimeCost); } catch (InterruptedException e) { e.printStackTrace(); } if (fakeToken.expired) { throw new IllegalArgumentException("Token expired!"); } FakeThing fakeData = new FakeThing(); fakeData.id = (int) (System.currentTimeMillis() % 1000); fakeData.name = "FAKE_USER_" + fakeData.id; return fakeData; } }); }}
TokenFragment
public class TokenFragment extends BaseFragment { @Bind(R.id.tokenTv) TextView tokenTv; @Bind(R.id.swipeRefreshLayout) SwipeRefreshLayout swipeRefreshLayout; @OnClick(R.id.requestBt) void upload() { swipeRefreshLayout.setRefreshing(true); unsubscribe(); final FakeApi fakeApi = Network.getFakeApi(); subscription = fakeApi.getFakeToken("fake_auth_code") .flatMap(new Func1<FakeToken, Observable<FakeThing>>() { @Override public Observable<FakeThing> call(FakeToken fakeToken) { return fakeApi.getFakeData(fakeToken); } }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1<FakeThing>() { @Override public void call(FakeThing fakeData) { swipeRefreshLayout.setRefreshing(false); tokenTv.setText(getString(R.string.got_data, fakeData.id, fakeData.name)); } }, new Action1<Throwable>() { @Override public void call(Throwable throwable) { swipeRefreshLayout.setRefreshing(false); Toast.makeText(getActivity(), R.string.loading_failed, Toast.LENGTH_SHORT).show(); } }); } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_token, container, false); ButterKnife.bind(this, view); swipeRefreshLayout.setColorSchemeColors(Color.BLUE, Color.GREEN, Color.RED, Color.YELLOW); swipeRefreshLayout.setEnabled(false); return view; } @Override protected int getDialogRes() { return R.layout.dialog_token; } @Override protected int getTitleRes() { return R.string.title_token; }}
非一次性 token
对于非一次性的 token (即可重复使用的 token),在获取 token 后将它保存起来反复使用,并通过 retryWhen() 实现 token 失效时的自动重新获取,将 token 获取的流程彻底透明化,简化开发流程。
public class TokenAdvancedFragment extends BaseFragment { @Bind(R.id.tokenTv) TextView tokenTv; @Bind(R.id.swipeRefreshLayout) SwipeRefreshLayout swipeRefreshLayout; final FakeToken cachedFakeToken = new FakeToken(true); boolean tokenUpdated; @OnClick(R.id.invalidateTokenBt) void invalidateToken() { cachedFakeToken.expired = true; Toast.makeText(getActivity(), R.string.token_destroyed, Toast.LENGTH_SHORT).show(); } @OnClick(R.id.requestBt) void upload() { tokenUpdated = false; swipeRefreshLayout.setRefreshing(true); unsubscribe(); final FakeApi fakeApi = Network.getFakeApi(); subscription = Observable.just(null) .flatMap(new Func1<Object, Observable<FakeThing>>() { @Override public Observable<FakeThing> call(Object o) { return cachedFakeToken.token == null ? Observable.<FakeThing>error(new NullPointerException("Token is null!")) : fakeApi.getFakeData(cachedFakeToken); } }) .retryWhen(new Func1<Observable<? extends Throwable>, Observable<?>>() { @Override public Observable<?> call(Observable<? extends Throwable> observable) { return observable.flatMap(new Func1<Throwable, Observable<?>>() { @Override public Observable<?> call(Throwable throwable) { if (throwable instanceof IllegalArgumentException || throwable instanceof NullPointerException) { return fakeApi.getFakeToken("fake_auth_code") .doOnNext(new Action1<FakeToken>() { @Override public void call(FakeToken fakeToken) { tokenUpdated = true; cachedFakeToken.token = fakeToken.token; cachedFakeToken.expired = fakeToken.expired; } }); } return Observable.error(throwable); } }); } }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1<FakeThing>() { @Override public void call(FakeThing fakeData) { swipeRefreshLayout.setRefreshing(false); String token = cachedFakeToken.token; if (tokenUpdated) { token += "(" + getString(R.string.updated) + ")"; } tokenTv.setText(getString(R.string.got_token_and_data, token, fakeData.id, fakeData.name)); } }, new Action1<Throwable>() { @Override public void call(Throwable throwable) { swipeRefreshLayout.setRefreshing(false); Toast.makeText(getActivity(), R.string.loading_failed, Toast.LENGTH_SHORT).show(); } }); } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_token_advanced, container, false); ButterKnife.bind(this, view); swipeRefreshLayout.setColorSchemeColors(Color.BLUE, Color.GREEN, Color.RED, Color.YELLOW); swipeRefreshLayout.setEnabled(false); return view; } @Override protected int getDialogRes() { return R.layout.dialog_token_advanced; } @Override protected int getTitleRes() { return R.string.title_token_advanced; }}
缓存
使用 BehaviorSubject 缓存数据。
简单
public class MyDataEvent { //能够缓存订阅之前的最新数据(如果有) private static BehaviorSubject<String> sTotalAssetEvent = BehaviorSubject.create(); private MyDataEvent() { } /** * 发送事件 * @param text */ public static void publish(String text) { sTotalAssetEvent.onNext(text); }
点击查看Demo
- APP实用开发—RxJava 和 Retrofit 结合使用
- Retrofit 和 RxJava 结合使用
- Retrofit和RxJava结合使用
- RxJava和Retrofit结合使用
- RxJava和Retrofit结合使用
- rxjava 和retrofit 结合使用
- RxJava + Retrofit 结合使用
- Retrofit结合rxjava使用
- rxjava和retrofit结合
- RxJava和Retrofit结合
- Retrofit和RxJava结合使用例子分析
- RxJava和Retrofit结合使用详解
- Retrofit和RxJava的结合使用
- Rxjava和Retrofit结合使用的案例
- Retrofit 和 Rxjava 的结合使用
- 结合retrofit和rxjava的使用
- rxjava 和retrofit 结合使用 请求网络
- RxJava,Retrofit,OkHttp3结合使用
- Linux防火墙开启与关闭
- ARM:g-sensor数据手册、函数原型atoi&itoa、读取加速度的基础
- java设计模式之代理模式
- 定时关机
- SQL FOREIGN KEY 外键限制学习笔记
- APP实用开发—RxJava 和 Retrofit 结合使用
- java 开发pc小工具 ,打包可运行的 jar
- Android服务(Service)
- gevent调度流程解析
- 制图 | AutoCAD 基本设置和使用
- ubuntu12.04建立交叉编译环境开发openwrt
- 菱形输出 Java
- [机器学习][3]--口袋算法与线性回归
- Linux文件编程