您的位置:首页 > 移动开发

APP实用开发—RxJava 和 Retrofit 结合使用

2017-02-10 22:34 627 查看
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  RxJava Retrofit