实现功能:
网络数据请求,缓存,等待窗口,刷新加载,recyclerview封装。
知识点:
Rxjava2+retrofit2+okhttp3网路请求,Glide图片加载,recyclerview使用,自定义控件。
网络结构图:
使用说明:
导入包
清单文件
注意关联MyApplication,并用自己的application继承,这里用RxApp继承
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.haoyan.rxjava2">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_PROFILE"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:name=".MyApplication"
android:theme="@style/AppTheme">
<activity android:name=".RxjavaActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
其它
加载刷新用values文件下attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SwipyRefreshLayout">
<attr name="direction">
<enum name="top" value="0" />
<enum name="bottom" value="1" />
<enum name="both" value="2" />
</attr>
</declare-styleable>
</resources>
主类RxjavaActivity
public class RxjavaActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private RecyclerView mRecyclerView;
// private TextView mTextView;
private CommonAdapter<RxMovieBean.SubjectsBean> commonadapter;
private SwipyRefreshLayout swipeRefreshLayout;
private Dialog loading_dialog;
private List<RxMovieBean.SubjectsBean> storiesList;
private final int TOP_REFRESH = 1;
private final int BOTTOM_REFRESH = 2;
int start=0; //开始请求位置
int pages=10; //需要请求的数据数量
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rxjava);
initView();
dataView(start,pages);
setListener();
}
private void initView() {
storiesList=new ArrayList<>();
swipeRefreshLayout = (SwipyRefreshLayout) findViewById(R.id.swipeRefreshLayout);
mRecyclerView = (RecyclerView)findViewById(R.id.id_stickynavlayout_innerscrollview);
mRecyclerView.setLayoutManager(new GridLayoutManager(this,2));
loading_dialog = new AlertDialog.Builder(this).setMessage("loading...").create();
commonadapter = new CommonAdapter<RxMovieBean.SubjectsBean>(this,R.layout.rxjava_grid_item,storiesList) {
@Override
public void convert(ViewHolder holder, RxMovieBean.SubjectsBean subjectsBean) {
ImageView imgview=holder.getView(R.id.imageIv);
Glide.with(holder.itemView.getContext())
.load(subjectsBean.getImages().getLarge()).into(imgview);
holder.setText(R.id.descriptionTv,subjectsBean.getTitle());
}
};
mRecyclerView.setAdapter(commonadapter);
commonadapter.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(ViewGroup parent, View view, Object o, int position) {
Toast.makeText(RxjavaActivity.this, "位置"+position, Toast.LENGTH_SHORT).show();
}
@Override
public boolean onItemLongClick(ViewGroup parent, View view, Object o, int position) {
return false;
}
});
}
/**
*调用说明
* 1.调用RxSingleRxHttp
* 2.关联url
* 3.开启缓存
* 4.读取时间
* 5.关联api接口
* 6.api接口中具体内容
* 7.添加分支,等待框
* 8.订阅
* */
private void dataView(int start,int pag) {
RxHttpUtils.getSInstance()
.baseUrl(RxUrl.BASE_URL)
.cache(true)
.readTimeout(500)
.createSApi(Rxdoubanapi.class)
.fetchMovieTop250(start, pag)
.compose(RxTransformer.<RxMovieBean>switchSchedulers(loading_dialog))
.subscribe(new RxCommonObserver<RxMovieBean>(loading_dialog) {
@Override
protected void getDisposable(Disposable d) {
}
@Override
protected void onError(String errorMsg) {
}
@Override
protected void onSuccess(RxMovieBean eMovieBean) {
storiesList.addAll(eMovieBean.getSubjects());
commonadapter.notifyDataSetChanged();
showToast("请求成功");
}
});
}
private void setListener() {
swipeRefreshLayout.setOnRefreshListener(new SwipyRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh(int index) {
Log.i(TAG, "onRefresh: "+index);
dataOption(TOP_REFRESH);
}
@Override
public void onLoad(int index) {
Log.i(TAG, "onLoad: "+index);
dataOption(BOTTOM_REFRESH);
}
});
}
private void dataOption(int option){
switch (option) {
case TOP_REFRESH:
pages=10;
dataView(0,pages);
storiesList.clear();
break;
case BOTTOM_REFRESH:
if(start>30){
Toast.makeText(RxjavaActivity.this, "到头了亲", Toast.LENGTH_SHORT).show();
}else{
start=start+10;
dataView(start,pages);
}
break;
}
swipeRefreshLayout.setRefreshing(false);
commonadapter.notifyDataSetChanged();
}
}
被观察者核心代码:
public class RxRetrofitClient {
private static RxRetrofitClient instance;
private Retrofit.Builder mRetrofitBuilder;
private OkHttpClient.Builder mOkHttpBuilder;
public RxRetrofitClient() {
mOkHttpBuilder = new OkHttpClient.Builder();
mRetrofitBuilder = new Retrofit.Builder()
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.client(mOkHttpBuilder.build());
}
public static RxRetrofitClient getInstance() {
if (instance == null) {
synchronized (RxRetrofitClient.class) {
if (instance == null) {
instance = new RxRetrofitClient();
}
}
}
return instance;
}
public Retrofit.Builder getRetrofitBuilder() {
return mRetrofitBuilder;
}
public Retrofit getRetrofit() {
return mRetrofitBuilder.client(mOkHttpBuilder.build()).build();
}
}
观察者核心代码:
public abstract class RxBaseObserver<T> implements Observer<T>, RxISubscriber<T> {
private Toast mToast;
public static final String errorMsg_SocketTimeoutException = "网络链接超时,请检查您的网络状态,稍后重试!";
public static final String errorMsg_ConnectException = "网络链接异常,请检查您的网络状态";
public static final String errorMsg_UnknownHostException = "网络异常,请检查您的网络状态";
protected void doOnNetError() {
}
@Override
public void onSubscribe(@NonNull Disposable d) {
doOnSubscribe(d);
}
@Override
public void onNext(@NonNull T t) {
doOnNext(t);
}
@Override
public void onError(@NonNull Throwable e) {
if (e instanceof SocketTimeoutException) {
setError(errorMsg_SocketTimeoutException);
} else if (e instanceof ConnectException) {
setError(errorMsg_ConnectException);
} else if (e instanceof UnknownHostException) {
setError(errorMsg_UnknownHostException);
} else {
String error = e.getMessage();
showToast(error);
doOnError(error);
}
}
@Override
public void onComplete() {
doOnCompleted();
}
private void setError(String errorMsg) {
showToast(errorMsg);
doOnError(errorMsg);
doOnNetError();
}
/**
* Toast提示
*
* @param msg 提示内容
*/
protected void showToast(String msg) {
if (mToast == null) {
mToast = Toast.makeText(RxApp.getInstance(), msg, Toast.LENGTH_SHORT);
} else {
mToast.setText(msg);
}
mToast.show();
}
/**
* 错误处理
*
* @param e
* @return
*/
private String handleError(Throwable e) {
String error = null;
try {
ResponseBody errorBody = ((HttpException) e).response().errorBody();
error = errorBody.string();
} catch (IOException e1) {
e1.printStackTrace();
}
return error;
}
}
具体实现请看源码
补充:BaseObserver中的T可继承BaseResponse对code和msg同一处理,处理地点在BaseObserver的onNext中。
注意:Gilde4.0-RC1可能出现图片加载异常,替换Gilde4.0可修复
参考:
Rxjava2 学习(九篇容易理解)good
Rxjava1学习(大神级教程)good
封装完整版
okhttp