Android入门学习——RxJava+Retrofit+MVP学习
来源:互联网 发布:美好的每一天剧情知乎 编辑:程序博客网 时间:2024/05/16 16:11
RxJava+Retrofit+MVP学习笔记
本篇笔记是对上一篇Android入门学习——Retrofit+MVP模式学习的补充。这次加上了RxJava的简单使用,并在上一篇中特别简单的Demo的基础上加上了Swiperefreshlayout+RecyclerView的配合使用。加上了下拉刷新以及上拉加载更多。但上拉加载更多也只是个简单的思路,实现的并不好,需要以后再进行优化封装。本人菜鸟,讲解不了啥知识点,只是为了记录学习的过程。想学RxJava可以多看看扔物线大神的给Android开发者的RxJava详解
项目添加的依赖库:
java
compile 'com.android.support:appcompat-v7:23.3.0'
compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.android.support:recyclerview-v7:23.3.0'
compile 'com.google.code.gson:gson:2.2.4'
compile 'com.android.support:cardview-v7:23.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
**compile 'io.reactivex:rxjava:1.1.5'**
**compile 'io.reactivex:rxandroid:1.2.0'**
**compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'**
compile 'com.github.bumptech.glide:glide:3.7.0'
compile 'com.android.support:design:23.3.0'
比上篇多了io.reactivex:rxjava:1.1.5、io.reactivex:rxandroid:1.2.0、com.squareup.retrofit2:adapter-rxjava:2.0.2。使用RxJava这三个都需要添加,并且retrofit2、rxjava、rxandroid版本号要一致,我这里用的都是2.0.2。RxAndroid就是RxJava针对Android推出的。
RxJava的加入
与上一篇相比,工程的目录结构基本没大变化。还是继续尝试学习MVP模式下的目录分层。View和Presenter层基本没啥变化,请求数据的接口依然是上一篇中使用的接口。变化大的是使用Retrofit所创建的接口RetrofitService。
下面贴出RetrofitService的代码:
public interface RetrofitService { @FormUrlEncoded @POST(AppConfigs.URL_DATA) Observable<DataBean> getDataBean(@FieldMap Map<String,String> map);}
代码很简单,就3行。和不用RxJava的区别就是接口中方法的返回值,不再是Retrofit中的Call而是换成了RxJava的Ovservable(被观察者)。
理所当然,Model层中的Retrofit网路请求就发生了重大改变。
public class ShowContentModel implements ShowContentBiz { private Subscription sub; private boolean state = false; public boolean isState() { return state; } @Override public void onResult(final onShowContentListener onShowContentListener ,int p) { Retrofit retrofit = new Retrofit.Builder().baseUrl(AppConfigs.URL_DATA) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build(); RetrofitService retrofitService = retrofit.create(RetrofitService.class); Map<String,String> map = new HashMap<>(); map.put(AppConfigs.APPID_NAME,AppConfigs.APPID); map.put(AppConfigs.SECRECT_NAME,AppConfigs.SECRECT); map.put(AppConfigs.PAGE_NAME,""+p); map.put(AppConfigs.NUM_NAME,AppConfigs.NUM); //Log.e("page","--"+p); state = true;//设置为正在请求数据 sub = retrofitService.getDataBean(map) .subscribeOn(Schedulers.io())//网络请求在io线程 .observeOn(AndroidSchedulers.mainThread())//subscribe()在UI线程 .subscribe(new Subscriber<DataBean>() { @Override public void onCompleted() { state = false; } @Override public void onError(Throwable e) { state = false; onShowContentListener.onFailed(e.getMessage()); } @Override public void onNext(DataBean dataBean) { if (dataBean != null) onShowContentListener.onSuccess(dataBean); } }); } public void cancelRequest(){ if ( sub != null && !sub.isUnsubscribed()){ sub.unsubscribe(); } }}
Retrofit对象的创建加入了.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
这行代码。这行代码必须加,否则会报错。
retrofitService.getDataBean()这个方法的返回对象其实是Observable。只是方法链最后调用了subscribe()
这个方法,返回对象也就变就变成了Subscription。这里返回Subsciption这个对象的目的是为了使用isUnsubscribed()
以及unsubscribe()
这两个方法。 isUnsubscribed()
这个方法的返回值为Boolean类型,这个方法是用来判断被观察者是否已经取消了订阅。 unsubscribe()
这个方法则是取消订阅,也就是取消了网络请求。
在subscribe()
这个方法会先执行onNext()
这个方法。onCompleted()
和onError
这两个方法则是势不两立的,一个执行另外一个就不再执行。
RxJava和Retrofit简单配合使用就完成了。但RxJava最令人拍手叫好的flatMap,这里并没有用到。以后深入的学习后,再记录补充。
Swiperefreshlayout+RecyclerView的配合使用
下拉刷新
Swiperefreshlayout的使用相对比较方便,几行的代码量就可以实现下拉刷新。
在xml文件中:
<android.support.v4.widget.SwipeRefreshLayout android:id="@+id/srfl_main" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:id="@+id/rv_main" android:layout_width="match_parent" android:layout_height="match_parent"> </android.support.v7.widget.RecyclerView></android.support.v4.widget.SwipeRefreshLayout>
界面布局很简单就是一个SwipeRefreshLayout包裹一个RecyclerView。
在MainActvity中:
swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.srfl_main);swipeRefreshLayout.setColorSchemeColors(R.color.colorAccent);swipeRefreshLayout.post(new Runnable() { @Override public void run() { swipeRefreshLayout.setRefreshing(true); } });
.setColorSchemeColors()
设置下拉刷新圆圈的颜色。 swipeRefreshLayout.setRefreshing(true)
设置下拉刷新状态,出现小圆圈在界面转。在数据请求完成的时候设置为false,小圆圈就会消失。
swipeRefreshLayout.post()
这个方法是为了实现有第一次进入界面的时候,有一种自动刷新的效果。
RecyclerView添加FooterView,实现上拉加载更多
我尝试的是通过RecyclerView的Adapter来添加FooterView,也有通过自定义RecyclerView来添加的思路。
下面是完整的BaseRecyclerAdapter代码:
public abstract class BaseRecyclerAdapter <T> extends RecyclerView.Adapter<RecyclerView.ViewHolder>{ protected List <T> datas = new ArrayList<>(); protected final int mLayoutItemId; protected boolean isScrolling; protected Context mContext; private OnRecyclerItemClickListener mListener; //填充布局类型 private final int TYPE_NORMAL = 0 ; private final int TYPE_HEADER = 1; private final int TYPE_FOOTER = 2 ; //FooterView 和 HeaderView private View footerView; private View headerView; public BaseRecyclerAdapter(RecyclerView rv,int mLayoutItemId) { this. mContext =rv.getContext(); this.mLayoutItemId = mLayoutItemId; rv.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); isScrolling = !(newState == RecyclerView.SCROLL_STATE_IDLE); if (!isScrolling) { notifyDataSetChanged(); } } }); } public void setHeaderView(View headerView) { this.headerView = headerView; notifyItemInserted(0); } public void setFooterView(View footerView) { this.footerView = footerView; notifyItemInserted(getItemCount() - 1); } public void removedFooterView(){ if (footerView != null){ notifyItemRemoved(getItemCount()-1); } } @Override public int getItemViewType(int position) { if (headerView !=null && position ==0){ return TYPE_HEADER; } if (footerView != null && position + 1 == getItemCount()) { return TYPE_FOOTER ; } return TYPE_NORMAL ; } @Override public int getItemCount() { return datas.size() == 0? 0 :( footerView ==null ? 0:datas.size() + 1 ); } public void setDataList(List <T> datas){ if (datas != null){ this.datas.clear(); this.datas.addAll(datas); notifyDataSetChanged(); } } public void setItemListener(OnRecyclerItemClickListener mListener){ this.mListener = mListener; } private View.OnClickListener getOnClickListener(final int position){ return new View.OnClickListener(){ @Override public void onClick(View v) { if (mListener != null & v != null){ mListener.onRecyclerItemClick(v,datas.get(position),position); } } }; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { LayoutInflater inflater = LayoutInflater.from(mContext); RecyclerView.ViewHolder holder = null; if (viewType == TYPE_FOOTER && footerView != null){ holder = new FooterOrHeaderViewHolder(footerView); }else if(viewType == TYPE_HEADER && headerView != null){ holder = new FooterOrHeaderViewHolder(headerView); }else{ View view = inflater.inflate(mLayoutItemId,parent,false); holder =new RecyclerHolder(view) ; } holder.setIsRecyclable(true); return holder; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (getItemViewType(position) == TYPE_FOOTER || getItemViewType(position) == TYPE_HEADER){ return; } position = getRealPosition(holder); bindViewData((RecyclerHolder) holder,datas.get(position),position,isScrolling); holder.itemView.setOnClickListener(getOnClickListener(position)); } private int getRealPosition(RecyclerView.ViewHolder viewHolder){ int position = viewHolder.getLayoutPosition(); return headerView == null ? position : (position - 1); } public abstract void bindViewData(RecyclerHolder holder, T item, int position, boolean isScrolling); public interface OnRecyclerItemClickListener { void onRecyclerItemClick(View view, Object data, int position); } private class FooterOrHeaderViewHolder extends RecyclerView.ViewHolder { public FooterOrHeaderViewHolder(View view) { super(view); } } /** * 当使用GridLayoutManager时添加HeaderView和FooterView会调用这个方法 */ @Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); RecyclerView.LayoutManager manager = recyclerView.getLayoutManager(); if(manager instanceof GridLayoutManager) { final GridLayoutManager gridManager = ((GridLayoutManager) manager); gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { if (getItemViewType(position) == TYPE_FOOTER || getItemViewType(position) == TYPE_HEADER){ return gridManager.getSpanCount(); }else{ return 1; } } }); } } /** * 当使用瀑布流添加HeaderView的时候会调用这个方法 */ @Override public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { super.onViewAttachedToWindow(holder); ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams(); if(lp != null&& lp instanceof StaggeredGridLayoutManager.LayoutParams && (holder.getLayoutPosition() == 0||holder.getLayoutPosition() == (getItemCount()-1))) { StaggeredGridLayoutManager.LayoutParams slp = (StaggeredGridLayoutManager.LayoutParams) lp; slp.setFullSpan(true); } }}
onAttachedToRecyclerView()
和onViewAttachedToWindow
这两个方法中的代码是固定的,是为了让添加的HeaderView或者FooterView能够单独占据一行。可以尝试在使用GridLayoutManager和瀑布流的时候不添加这两个方法,看看会出现啥情况。一下子就会搞明白这两个方法干嘛用的了。
在MainActivity中:
rv.setOnScrollChangeListener(new RecyclerView.OnScrollChangeListener(){ @Override public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) { RecyclerView rView = (RecyclerView) v; int lastVisible = ((GridLayoutManager)rView.getLayoutManager()).findLastVisibleItemPosition(); if (!presenter.getRefreshState() && rView.getAdapter().getItemCount() - 1 == lastVisible && lastVisible != mLastVisibleItem){ mLastVisibleItem = lastVisible; presenter.getListData(++ page); } } });
就是给RecyclerView设置滑动监听,判断条件是,是否正在进行数据的请求,最后一个item是否出现,最后一个itme是否为第一次出现。
最后
这篇博客只是记载我的学习以及尝试。代码中的不足以后会修补,下面是源码。
又修改了一部分代码,加入了HeaderView
代码
- Android入门学习——RxJava+Retrofit+MVP学习
- Android入门学习——Retrofit+MVP模式学习
- 学习项目: mvp+Rxjava+Retrofit
- Retrofit+RxJava+MVP学习笔记
- 带你高效学习MVP+RxJava+Retrofit
- 带你高效学习MVP+RxJava+Retrofit
- Android MVP +Retrofit+RxJava
- Android——MVP+xRecyclerView+Retrofit+OkHttp+RxJava结合应用
- Android Mvp+Rxjava+Retrofit实战
- Android Mvp+RxJava+Retrofit 实战
- Android Retrofit+RxJava+MVP封装
- mvp框架学习实战代码(配合retrofit+dagger2+rxjava)
- android 学习RxJava+Retrofit的资料
- android 网络框架学习(okhttp,retrofit,rxjava)
- Retrofit+RxJava 简单学习
- Retrofit + Rxjava 学习1
- 学习Retrofit+RXJava
- Retrofit+MVP模式学习
- 《机器学习实战》--Logistic回归
- 设置Tomcat的JAVA_OPTS参数
- 工作日志——k8s pv&pvc
- poj_3669_广度优先搜索
- [7688] Uboot编译环境搭建以及编译
- Android入门学习——RxJava+Retrofit+MVP学习
- SAPUI5 - Component
- 5-22 龟兔赛跑 (20分)
- C++第六次实验
- 解决HierarchyViewer不能连接真机的问题
- 5-23 币值转换 (20分)
- C++中的结构体内存对齐
- onOptionsItemSelected(具体什么流程)?
- Linux常用命令