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

0 0
原创粉丝点击