包名解释:
base:基类库。
BaseDto类为服务器返回公共实体;BaseHttpSubscriber类自定义请求服务器被观察者;BaseRepository类请求网络数据基类。
exception:异常类模块。
ApiException类前端自定义Exception;ServerException类服务器返回的Exception;ExceptionEngine类拦截各种异常处理。
https:Retrofit+OkHttp封装网络请求模块。
ApiService接口API的Retrofit注解;RequetRetrofit类的网络请求用到的Retrofit+OkHttp。
interceptor:自定义网络请求拦截器。
model:数据模型层。定义实体类。
repository:数据仓库。包括网络数据获取,sqlite小型数据库,文件File,SharedPreferences数据存储。
view:视图层。主要包含Activity+Fragment实体类。
viewmodel:VM视图模型层。
implementation 'com.alibaba:fastjson:1.1.70.android' implementation 'com.google.code.gson:gson:2.8.4' implementation 'com.squareup.okhttp3:okhttp:3.11.0' //Rxlifecycle implementation 'com.trello:rxlifecycle:0.3.1' implementation 'com.trello:rxlifecycle-components:0.3.1' implementation 'com.github.bumptech.glide:glide:4.8.0' implementation 'com.squareup.retrofit2:converter-gson:2.+' //必须使用 implementation 'com.lzy.net:okgo:3.0.4' implementation 'com.squareup.okio:okio:1.5.0' implementation 'io.reactivex.rxjava2:rxjava:2.2.2' implementation 'io.reactivex.rxjava2:rxandroid:2.1.0' implementation 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.+' implementation 'com.squareup.retrofit2:retrofit:2.+' implementation 'com.squareup.okhttp3:logging-interceptor:3.11.0' implementation 'com.squareup.retrofit2:converter-gson:2.+' implementation 'com.squareup.retrofit2:converter-scalars:2.0.0' implementation 'com.facebook.stetho:stetho:1.4.2' implementation 'com.facebook.stetho:stetho-okhttp3:1.4.2' // 依赖以下两个库,会自动引用基础库与Android库 implementation 'com.trello.rxlifecycle2:rxlifecycle-components:2.1.0' implementation 'com.trello.rxlifecycle2:rxlifecycle-navi:2.1.0' implementation 'com.tbruyelle.rxpermissions:rxpermissions:0.7.0@aar' implementation 'com.jakewharton.rxbinding:rxbinding:1.+' // Lifecycles, LiveData 和 ViewModel implementation "android.arch.lifecycle:extensions:1.1.0" // 对 RxJava 的支持 implementation "android.arch.persistence.room:rxjava2:1.0.0-alpha5"
1、BaseDto类
package com.ylink.frameworkdemo.base; import java.io.Serializable; /** * 服务器返回公共实体 * * @param* @author twilight * @Time 2019-07-21 */ public class BaseDto implements Serializable { private String statusCode; private String statusDesc; private T data; public String getStatusCode() { return statusCode; } public void setStatusCode(String statusCode) { this.statusCode = statusCode; } public String getStatusDesc() { return statusDesc; } public void setStatusDesc(String statusDesc) { this.statusDesc = statusDesc; } public T getData() { return data; } public void setData(T data) { this.data = data; } }
2、BaseHttpSubscriber类
package com.ylink.frameworkdemo.base; import androidx.lifecycle.MutableLiveData; import com.ylink.frameworkdemo.Constant; import com.ylink.frameworkdemo.exception.ApiException; import com.ylink.frameworkdemo.exception.ExceptionEngine; import com.ylink.frameworkdemo.exception.ServerException; import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; /** * 自定义请服务器被观察者 * * @author twilight * @Time 2019-07-21 */ public class BaseHttpSubscriberimplements Subscriber > { //异常类 private ApiException ex; public BaseHttpSubscriber() { data = new MutableLiveData(); } private MutableLiveData > data; public MutableLiveData > get() { return data; } public void set(BaseDto t) { this.data.setValue(t); } public void onFinish(BaseDto t) { set(t); } @Override public void onSubscribe(Subscription s) { // 观察者接收事件 = 1个 s.request(1); } @Override public void onNext(BaseDto t) { if (t.getStatusCode().equals(Constant.RespCode.R000)) { onFinish(t); } else{ ex = ExceptionEngine.handleException(new ServerException(t.getStatusCode(), t.getStatusDesc())); getErrorDto(ex); } } @Override public void onError(Throwable t) { ex = ExceptionEngine.handleException(t); getErrorDto(ex); } /** * 初始化错误的dto * * @param ex */ private void getErrorDto(ApiException ex) { BaseDto dto = new BaseDto(); dto.setStatusCode(ex.getStatusCode()); dto.setStatusDesc(ex.getStatusDesc()); onFinish((BaseDto ) dto); } @Override public void onComplete() { } }
3、BaseRepository类
package com.ylink.frameworkdemo.base; import io.reactivex.Flowable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; /** * Repository基类 * * @author twilight * @Time 2019-07-21 */ public class BaseRepository { /** * 请求网络 * @param flowable * @param* @return */ public BaseHttpSubscriber request(Flowable > flowable){ BaseHttpSubscriber baseHttpSubscriber = new BaseHttpSubscriber<>(); //RxJava Subscriber回调 flowable.subscribeOn(Schedulers.io()) //解决背压 .observeOn(AndroidSchedulers.mainThread()) .subscribe(baseHttpSubscriber); return baseHttpSubscriber; } }
4、ApiException类
package com.ylink.frameworkdemo.exception; /** * 前端自定义Exception */ public class ApiException extends Exception { private String statusCode;//错误码 private String statusDesc;//错误信息 public ApiException(Throwable throwable, String statusCode) { super(throwable); this.statusCode = statusCode; } public ApiException(String statusCode, String statusDesc) { this.statusCode = statusCode; this.statusDesc = statusDesc; } public String getStatusCode() { return statusCode; } public void setStatusCode(String statusCode) { this.statusCode = statusCode; } public String getStatusDesc() { return statusDesc; } public void setStatusDesc(String statusDesc) { this.statusDesc = statusDesc; } }
5、ServerException类
package com.ylink.frameworkdemo.exception; /** * 服务器返回的Exception */ public class ServerException extends RuntimeException { private String statusCode;//错误码 private String statusDesc;//错误信息 public ServerException(String statusCode, String statusDesc) { this.statusCode = statusCode; this.statusDesc = statusDesc; } public String getStatusCode() { return statusCode; } public void setStatusCode(String statusCode) { this.statusCode = statusCode; } public String getStatusDesc() { return statusDesc; } public void setStatusDesc(String statusDesc) { this.statusDesc = statusDesc; } }
6、ExceptionEngine类
package com.ylink.frameworkdemo.exception; import android.net.ParseException; import android.util.MalformedJsonException; import com.google.gson.JsonParseException; import org.json.JSONException; import java.net.ConnectException; import java.net.SocketTimeoutException; import java.net.UnknownHostException; import retrofit2.HttpException; public class ExceptionEngine { //客户端报错 public static final int UN_KNOWN_ERROR = 9000;//未知错误 public static final int ANALYTIC_SERVER_DATA_ERROR = 9001;//解析(服务器)数据错误 public static final int ANALYTIC_CLIENT_DATA_ERROR = 9002;//解析(客户端)数据错误 public static final int CONNECT_ERROR = 9003;//网络连接错误 public static final int TIME_OUT_ERROR = 9004;//网络连接超时 public static final int UNKNOWNHOSTEXCEPTION = 9005;//网络连接超时 public static ApiException handleException(Throwable e) { ApiException ex; if (e instanceof HttpException) { //HTTP错误 HttpException httpExc = (HttpException) e; ex = new ApiException(e, String.valueOf(httpExc.code())); ex.setStatusDesc("网络错误,请稍后再试"); //均视为网络错误 return ex; } else if (e instanceof ServerException) { //服务器返回的错误 ServerException serverExc = (ServerException) e; ex = new ApiException(serverExc, serverExc.getStatusCode()); ex.setStatusDesc(serverExc.getStatusDesc()); return ex; } else if (e instanceof JsonParseException || e instanceof JSONException || e instanceof ParseException || e instanceof MalformedJsonException) { //解析数据错误 ex = new ApiException(e, String.valueOf(ANALYTIC_SERVER_DATA_ERROR)); ex.setStatusDesc("客户端异常,请稍后再试"); return ex; } else if (e instanceof ConnectException) {//连接网络错误 ex = new ApiException(e, String.valueOf(CONNECT_ERROR)); ex.setStatusDesc("网络连接错误,请稍后再试"); return ex; } else if (e instanceof SocketTimeoutException) {//网络超时 ex = new ApiException(e, String.valueOf(TIME_OUT_ERROR)); ex.setStatusDesc("网络连接超时,请稍后再试"); return ex; } else if (e instanceof UnknownHostException) {//网络异常 ex = new ApiException(e, String.valueOf(UNKNOWNHOSTEXCEPTION)); ex.setStatusDesc("网络异常,请检查您的网络连接"); return ex; } else { //未知错误 ex = new ApiException(e, String.valueOf(UN_KNOWN_ERROR)); ex.setStatusDesc("系统异常,请稍后再试"); return ex; } } }
7、ApiService接口
package com.ylink.frameworkdemo.https; import com.ylink.frameworkdemo.Constant; import com.ylink.frameworkdemo.base.BaseDto; import com.ylink.frameworkdemo.model.dto.LoginDto; import com.ylink.frameworkdemo.model.vo.LoginVo; import io.reactivex.Flowable; import retrofit2.http.Body; import retrofit2.http.POST; /** * api接口 * * @author twilight * @Time 2019-07-21 * * retrofit的注解学习https://blog.csdn.net/qiang_xi/article/details/53959437 */ public interface ApiService { /** * 登录 * @param loginVo * @return */ @POST(Constant.Server.LOGIN) Flowable> login(@Body LoginVo loginVo); }
8、RequestRetrofit类
package com.ylink.frameworkdemo.https; import android.util.Log; import com.facebook.stetho.okhttp3.StethoInterceptor; import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; import com.ylink.frameworkdemo.Constant; import com.ylink.frameworkdemo.interceptor.AddCookiesInterceptor; import com.ylink.frameworkdemo.interceptor.ReceivedCookiesInterceptor; import java.util.concurrent.TimeUnit; import okhttp3.OkHttpClient; import okhttp3.logging.HttpLoggingInterceptor; import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; /** * 普通的网络请求用到的Retrofit */ public class RequetRetrofit { private static final String TAG = "RequetRetrofit"; /** * 创建okhttp相关对象 */ private static OkHttpClient okHttpClient; /** * 创建Retrofit相关对象 */ private static Retrofit retrofit; public staticT getInstance(final Class service) { if (okHttpClient == null) { synchronized (RequetRetrofit.class) { if(okHttpClient == null) { /** * 创建okhttp相关对象 */ okHttpClient = new OkHttpClient.Builder() .addInterceptor(new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() { @Override public void log(String message) { //访问网络请求,和服务端响应请求时。将数据拦截并输出 Log.d(TAG, "log: " + message); } }).setLevel(HttpLoggingInterceptor.Level.BODY)) //Log等级 .connectTimeout(Constant.Server.TIME_OUT, TimeUnit.SECONDS) //超时时间 .readTimeout(Constant.Server.TIME_OUT, TimeUnit.SECONDS) .writeTimeout(Constant.Server.TIME_OUT, TimeUnit.SECONDS) .addNetworkInterceptor(new StethoInterceptor()) .addInterceptor(new AddCookiesInterceptor()) // .addInterceptor(new ReceivedCookiesInterceptor()) .build(); } } } if (retrofit == null) { synchronized (RequetRetrofit.class) { if(retrofit == null) { retrofit = new Retrofit.Builder() .baseUrl(Constant.Server.ROOT_URL) //BaseUrl .client(okHttpClient) //请求的网络框架 .addConverterFactory(GsonConverterFactory.create()) //解析数据格式 .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 使用RxJava作为回调适配器 .build(); } } } return retrofit.create(service); } }
9、AddCookiesInterceptor类
package com.ylink.frameworkdemo.interceptor; import com.alibaba.fastjson.JSONObject; import com.ylink.frameworkdemo.Constant; import com.ylink.frameworkdemo.utils.SPUtil; import java.io.IOException; import java.util.List; import okhttp3.Interceptor; import okhttp3.Request; import okhttp3.Response; /** * 自定义拦截器刷新sessionId 非首次请求的处理 * @author twilight * @Time 2019-07-21 */ public class AddCookiesInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request.Builder builder = chain.request().newBuilder(); String cookieStr = SPUtil.getData(Constant.SP.SP, Constant.SP.SESSION_ID, String.class, null); Listcookies = JSONObject.parseArray(cookieStr, String.class); if (cookies != null) { for (String cookie : cookies) { builder.addHeader("Cookie", cookie); } } return chain.proceed(builder.build()); } }
10、ReceivedCookiesInterceptor类
package com.ylink.frameworkdemo.interceptor; import com.alibaba.fastjson.JSONObject; import com.ylink.frameworkdemo.Constant; import com.ylink.frameworkdemo.utils.SPUtil; import java.io.IOException; import java.util.ArrayList; import java.util.List; import okhttp3.Interceptor; import okhttp3.Response; /** * 自定义拦截器刷新sessionId 首次请求的处理 * @author twilight * @Time 2019-07-21 */ public class ReceivedCookiesInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Response originalResponse = chain.proceed(chain.request()); if (!originalResponse.headers("Set-Cookie").isEmpty()) { Listcookies = new ArrayList<>(); for (String header : originalResponse.headers("Set-Cookie")) { cookies.add(header); } String cookieStr = JSONObject.toJSONString(cookies); SPUtil.putData(Constant.SP.SP, Constant.SP.SESSION_ID, cookieStr); } return originalResponse; } }
1、登录Vo
package com.ylink.frameworkdemo.model.vo; import java.io.Serializable; /** * 登陆vo * * @author twilight * @Time 2020-01-14 */ public class LoginVo implements Serializable { private String password; private String username; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
2、登录Dto
package com.ylink.frameworkdemo.model.dto; import java.io.Serializable; /** * 登陆返回实体 * * @author twilight * @Time 2020-01-14 */ public class LoginDto implements Serializable { private String id; private String userName; private String userAccount; private String sex; private String age; private String telephone; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getUserAccount() { return userAccount; } public void setUserAccount(String userAccount) { this.userAccount = userAccount; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } public String getTelephone() { return telephone; } public void setTelephone(String telephone) { this.telephone = telephone; } }
1、ILoginRepository接口类
package com.ylink.frameworkdemo.repository.network.impl; import androidx.lifecycle.LiveData; import com.ylink.frameworkdemo.base.BaseDto; import com.ylink.frameworkdemo.model.dto.LoginDto; import com.ylink.frameworkdemo.model.vo.LoginVo; /** * 登录 */ public interface ILoginRepository { /** * 登录 * @param loginVo * @return */ LiveData> login(LoginVo loginVo); }
2、LoginRepository接口实现类
package com.ylink.frameworkdemo.repository.network; import androidx.lifecycle.LiveData; import com.ylink.frameworkdemo.base.BaseDto; import com.ylink.frameworkdemo.base.BaseRepository; import com.ylink.frameworkdemo.https.ApiService; import com.ylink.frameworkdemo.https.RequetRetrofit; import com.ylink.frameworkdemo.model.dto.LoginDto; import com.ylink.frameworkdemo.model.vo.LoginVo; import com.ylink.frameworkdemo.repository.network.impl.ILoginRepository; /** * 登录 */ public class LoginRepository extends BaseRepository implements ILoginRepository { /** * 登录 * @param loginVo * @return */ @Override public LiveData> login(LoginVo loginVo) { return request(RequetRetrofit.getInstance(ApiService.class).login(loginVo)).get(); } }
1、创建activity_login.xml文件
2、创建LoginActivity类
package com.ylink.frameworkdemo.view.login; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModelProviders; import com.ylink.frameworkdemo.Constant; import com.ylink.frameworkdemo.R; import com.ylink.frameworkdemo.base.BaseDto; import com.ylink.frameworkdemo.model.dto.LoginDto; import com.ylink.frameworkdemo.model.vo.LoginVo; import com.ylink.frameworkdemo.viewmodel.login.LoginViewmodel; public class LoginActivity extends AppCompatActivity { EditText usernameEditText; EditText passwordEditText; Button loginButton; private LoginViewmodel viewmodel; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); viewmodel = ViewModelProviders.of(this).get(LoginViewmodel.class); usernameEditText = findViewById(R.id.username); passwordEditText = findViewById(R.id.password); loginButton = findViewById(R.id.login); loginButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { login(); } }); } /** * 登录 */ private void login(){ String username = usernameEditText.getText().toString().trim(); String password = passwordEditText.getText().toString().trim(); LoginVo loginVo = new LoginVo(); loginVo.setUsername(username); loginVo.setPassword(password); viewmodel.login(loginVo).observe(this, new Observer>() { @Override public void onChanged(@Nullable BaseDto loginDtoBaseDto) { if(loginDtoBaseDto.getStatusCode().equals(Constant.RespCode.R000)){ Toast.makeText(LoginActivity.this,"登录成功",Toast.LENGTH_LONG).show(); }else{ Toast.makeText(LoginActivity.this,loginDtoBaseDto.getStatusDesc(),Toast.LENGTH_LONG).show(); } } }); } }
package com.ylink.frameworkdemo.viewmodel.login; import androidx.lifecycle.LiveData; import androidx.lifecycle.ViewModel; import com.ylink.frameworkdemo.base.BaseDto; import com.ylink.frameworkdemo.model.dto.LoginDto; import com.ylink.frameworkdemo.model.vo.LoginVo; import com.ylink.frameworkdemo.repository.network.LoginRepository; import com.ylink.frameworkdemo.repository.network.impl.ILoginRepository; /** * 登录页面viewmodel */ public class LoginViewmodel extends ViewModel { public LiveData> login(LoginVo loginVo){ ILoginRepository loginRepository = new LoginRepository(); return loginRepository.login(loginVo); } }