實現(xiàn)功能:
網(wǎng)絡數(shù)據(jù)請求,緩存,等待窗口,刷新加載,recyclerview封裝。
知識點:
Rxjava2+retrofit2+okhttp3網(wǎng)路請求,Glide圖片加載,recyclerview使用,自定義控件。
網(wǎng)絡結(jié)構(gòu)圖:

RxjavaActivity.png
使用說明:
導入包

Rxjava依賴包.jpg
清單文件
注意關聯(lián)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; //需要請求的數(shù)據(jù)數(shù)量
@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;
}
});
}
/**
*調(diào)用說明
* 1.調(diào)用RxSingleRxHttp
* 2.關聯(lián)url
* 3.開啟緩存
* 4.讀取時間
* 5.關聯(lián)api接口
* 6.api接口中具體內(nèi)容
* 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 = "網(wǎng)絡鏈接超時,請檢查您的網(wǎng)絡狀態(tài),稍后重試!";
public static final String errorMsg_ConnectException = "網(wǎng)絡鏈接異常,請檢查您的網(wǎng)絡狀態(tài)";
public static final String errorMsg_UnknownHostException = "網(wǎng)絡異常,請檢查您的網(wǎng)絡狀態(tài)";
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 提示內(nèi)容
*/
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;
}
}
具體實現(xiàn)請看源碼
補充:BaseObserver中的T可繼承BaseResponse對code和msg同一處理,處理地點在BaseObserver的onNext中。
注意:Gilde4.0-RC1可能出現(xiàn)圖片加載異常,替換Gilde4.0可修復
參考:
Rxjava2 學習(九篇容易理解)good
Rxjava1學習(大神級教程)good
封裝完整版
okhttp