Retrofit
?Retrofit
早已不是什么新技术了,想必看到这篇博客的你们都早已熟知,这里就不啰嗦了,简单介绍下:REST
客户机。它经过基于 REST
的 web 服务检索和上传 JSON (或其余结构化数据)变得相对容易。在使用中,您能够配置用于数据序列化的转换器。对于 JSON ,一般使用Gson
,可是能够添加自定义转换器来处理 XML
或其余协议。Retrofit 对 HTTP 请求使用 OkHttp
库。A type-safe HTTP client for Android and Javajava
build.gradle
中添加如下依赖:// OkHttp3
api 'com.squareup.okhttp3:okhttp:3.10.0'
api 'com.squareup.okio:okio:1.8.0'
// Retrofit
api 'com.squareup.retrofit2:retrofit:2.7.0'
// Gson 服务器数据交互
api 'com.google.code.gson:gson:2.8.6'
复制代码
依赖注入很简单, Retrofit 一直是结合
OkHttp
和 Gson(无所谓什么 JSON 解析器都行,这里就用Gson
了) 我这里专门找了最新的版本库,so~ 你们直接用便可android
Retrofit
是结合 OkHttp
作网络请求用的,因此悉心提醒记得开下网络权限:<uses-permission android:name="android.permission.INTERNET" />
复制代码
Retrofit
的教程可谓琳瑯满目,可是总给人一种云里雾里的感受Retrofit
出现以前,原始社会的咱们通常是这样进行网络请求的:public void login2() {
OkHttpClient okHttpClient = new OkHttpClient();
//Form表单格式的参数传递
FormBody formBody = new FormBody
.Builder()
//设置参数名称和参数值
.add("username",mAccountEdit.getText().toString())
.add("password",mPasswordEdit.getText().toString())
.build();
Request request = new Request
.Builder()
//Post请求的参数传递
.post(formBody)
.url("http://hyh.hljdx.net:8080/SitUpWebServer/login")
.build();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(okhttp3.Call call, IOException e) {
Log.d("my_Test", e.getMessage());
}
@Override
public void onResponse(okhttp3.Call call, Response response) throws IOException {
String result = response.body().toString();
UserBean userBean = JSON.parseObject(result, UserBean.class);
Log.d("my_Test",userBean.getUser_head_img());
response.body().close();
}
});
}
复制代码
Post
请求的 Body
对象,那么有的同窗会问什么是 POST
,什么是 Body
?这个问题建议你们 Google
下,这里我建议你们学一些后端或者计网的知识,很简单也颇有必要Request
对象,也就是咱们的请求体,在这里设置信息要提交到哪去okHttpClient
的相应方法,将前面实现的东西组合发送,并在回调里接收FormBody
又是封装 Request
,搞了半天还要用 okHttpClient
发送,一套下来头晕眼花,那么如何解决呢?Retrofit
救世主就出现了Retrofit
的形式Retrofit
实现只须要:// baseUrl() 设置路由地址
Retrofit retrofit = new Retrofit
.Builder()
.baseUrl(ApiUtils.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
// 设置参数
Call<UserBean> call = retrofit.create(UserMgrService.class)
.login( mAccountEdit.getText().toString(),
mPasswordEdit.getText().toString());
// 回调
call.enqueue(new Callback<UserBean>() {
@Override
public void onResponse(Call<UserBean> call, Response<UserBean> response) {
Log.d("123123", "msg--" + response.body().getUser_head_img());
}
@Override
public void onFailure(Call<UserBean> call, Throwable t) {
// 失败时作处理
}
});
复制代码
okHttp
代码同样的功能Retrofit
的实例化过程,只要服务器不换代码几乎是不变的,因此咱们彻底能够将它封装OkHttp
咱们的返回值是一个 Response
对象,咱们还须要在其中提取相应 JSON
对象,进行类型转换,而在 Retrofit
中,因为使用了数据解析器,因此这一大块代码都省略了/** * @author fishinwater-1999 * @version 2019-12-21 */
public interface UserMgrService {
/** * GET 用 Query */
@GET("login")
Call<UserBean> login(@Query("username") String username, @Query("password") String password);
}
复制代码
@GET()
注解就能够猜到,这将会是一个 Get
请求UserBean
的 Call<>
对象String username
和 String password
@Query("...")
注解@Query("...")
里的参数咱们发现,这与 okHttp
建立 FormBody
时,add
的参数不谋而合看到这里想必你们都明白了,若是你们还不明白什么是 Get 请求,以及 @Query("...") 里的 username 和 password 是怎么的话,我这里简单说下 好比说咱们如今随便打开一个网页,就拿百度图片里搜索 Github 页面为例:git
HashMap get(“key”)
方法取值同样拿出来GET
方法以外 还有一种 POST
方法,相比于使用 GET
,使用 POST
有不少其余的优势,这里就很少说了GET
的思路同样,若是用 POST
那么咱们的代码将会是这样的:public interface UserMgrService {
/** * POST 用 Field */
@POST("login")
@FormUrlEncoded
Call<UserBean> login(@Field("username") String username, @Field("password") String password);
}
复制代码
@POST("...")
下再加上一个 @FormUrlEncoded
注解// baseUrl() 设置路由地址
Retrofit retrofit = new Retrofit
.Builder()
.baseUrl(ApiUtils.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
复制代码
baseUrl
、设置数据解析器baseUrl
?就拿我以前用 OkHttp
设置的那个 url 为例http://hyh.hljdx.net:8080/SitUpWebServer/login
复制代码
url = baseurl + @GET("...")
注解里传入的字符串@GET("login")
那这里 baseurl
就是:http://hyh.hljdx.net:8080/SitUpWebServer/
是否是一会儿就明白了,可是其余博客不照顾新人,从没说清楚// Gson 服务器数据交互
api 'com.google.code.gson:gson:2.8.6'
复制代码
JSON
的形式交互的,好比 Bing
每日壁纸接口具体这个对象怎么得到,你们能够联系后端,或者百度搜下 JsonFormat 插件使用或者 JSON 对象生成器,门路不少这里都告诉大家啦github
UserMgrService service = retrofit.create(UserMgrService.class);
复制代码
retrofit
对象的 create()
方法传入接口的 class
文件便可call
对象的 enqueue()
方法Call
对象怎么得到呢?其实很简单:Call<UserBean> call = service.login( mAccountEdit.getText().toString(), mPasswordEdit.getText().toString());
复制代码
Call
对象Response<UserBean> response = call.execute();
Log.d("123123", "msg--" + response.body().getUser_head_img());
复制代码
call
的 execute()
会返回一个值ANR
)// 回调
call.enqueue(new Callback<UserBean>() {
@Override
public void onResponse(Call<UserBean> call, Response<UserBean> response) {
Log.d("123123", "msg--" + response.body().getUser_head_img());
}
@Override
public void onFailure(Call<UserBean> call, Throwable t) {
// 失败时作处理
}
});
复制代码
call
的 enqueue
方法,传入一个 Callback
接口便可onResponse
方法,方法 里的 response
就是处理好的结果Retrofit
的使用Retrofit
MVP
+ ButterKnife
,你们很容易在网上找到资料,这就不赘述了ILoginModel
/** * @author fishinwater-1999 * @version 2019-11-12 */
public interface IBaseLog<L> {
/** * 登陆 Api * @param userAccount * @param mPassword * @param loginCallback */
void login(String userAccount, String mPassword, L loginCallback);
}
复制代码
/** * @author fishinwater-1999 * @version 2019-12-23 */
public interface IBaseRetCallback<T> {
void onSucceed(Response<T> response);
void onFailed(Throwable t);
}
复制代码
LoginModel
实现 ILoginModel
接口login
方法,请求成功后回调 IBaseRetCallback
监听/** * @author fishinwater-1999 * @version 2019-11-12 */
public class LogViewModel implements IBaseLog<IBaseRetCallback<UserBean>> {
private final String TAG = "LogViewModel";
@Override
public void login(String userAccount, String userPassword, final IBaseRetCallback<UserBean> retCallback) {
// baseUrl() 设置路由地址
Retrofit retrofit = new Retrofit
.Builder()
.baseUrl(ApiUtils.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
// 设置参数
UserMgrService service = retrofit.create(UserMgrService.class);
retrofit2.Call<UserBean> call = service.login( userAccount, userPassword);
// 回调
call.enqueue(new Callback<UserBean>() {
@Override
public void onResponse(retrofit2.Call<UserBean> call, Response<UserBean> response) {
retCallback.onSucceed(response);
}
@Override
public void onFailure(retrofit2.Call<UserBean> call, Throwable t) {
// 失败时作处理
retCallback.onFailed(t);
}
});
}
}
复制代码
Presenter
层基类Presenter
层基类,首先要实现器接口/** * @author fishinwater-1999 * @version 2019-11-12 */
public interface IBasePresenter<V> {
/** * 绑定 * @param mLogView */
void attachView(V mLogView);
/** * 解绑 */
void detachView();
/** * 登陆 * @param userName * @param userPassword * @param resultListener */
void login(String userName, String userPassword, V resultListener);
}
复制代码
BasePresenter
实现 IBasePresenter
接口/** * @author fishinwater-1999 * @version 2019-11-12 */
public abstract class BasePresenter<V> implements IBasePresenter<V> {
private V view;
@Override
public void attachView(V mLogView) {
this.view = mLogView;
}
@Override
public void detachView() {
this.view = null;
}
@Override
public V getLoginVew() {
return this.view;
}
}
复制代码
LogPresenter
类的实现LogPresenter
类须要持有 View 层和 Model 层接口/** * @author fishinwater-1999 * @version 2019-11-12 */
public class LogPresenter extends BasePresenter<ILoginView> {
private IBaseLog logViewModel;
public LogPresenter(IBaseLog logViewModel) {
this.logViewModel = logViewModel;
}
@Override
public void login(String userName, String userPassword, final ILoginView iLoginView) {
logViewModel.login(userName, userPassword, new IBaseRetCallback<UserBean>() {
@Override
public void onSucceed(Response<UserBean> response) {
UserBean userBean = response.body();
if (userBean != null) {
String user_id = userBean.getUser_id();
iLoginView.showLoginSuccess(user_id);
}
}
@Override
public void onFailed(Throwable t) {
iLoginView.showLoginFailed(ILoginView.ErrCode.WRONG_NET_WORK);
}
});
}
}
复制代码
View
层负责实例化 Model
层,并与 Presenter
层绑定BaseFragment<V , P extends IBasePresenter<V>>
基类/** * @author fishinwater-1999 * @version 2019-11-12 */
public abstract class BaseFragment<V , P extends IBasePresenter<V>> extends Fragment {
/** * Presenter 层 */
private P mBaseResister;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 自动绑定
if (mBaseResister == null) {
mBaseResister = createProsenter();
}
}
/** * 在这里肯定要生成的 Presenter 对象类型 * @return */
public abstract P createProsenter();
/** * 得到 Presenter 对象 * @return */
public P getPresenter() {
if (mBaseResister == null) {
createProsenter();
}
return mBaseResister;
}
/** * 碎片销毁时解绑 */
@Override
public void onStop() {
super.onStop();
mBaseResister = null;
}
}
复制代码
View
层逻辑/** * @author fishinwater-1999 */
public class LoginFragment extends BaseFragment<ILoginView, LogPresenter> implements ILoginView {
private static final String TAG = "LoginFragment";
private LogViewModel mLogViewModel;
private LoginFragmentBinding binding;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
binding = DataBindingUtil.inflate(inflater, R.layout.login_fragment, container, false);
View view = binding.getRoot();
binding.setLogCallback(getLogActivity());
binding.setFragment(this);
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (mLogViewModel == null) {
mLogViewModel = new LogViewModel();
}
}
public void login(View v) {
getPresenter().login(
getUserName(),
getUserPwd(),
this);
}
@Override
public LogPresenter createPresenter() {
if (mLogViewModel == null) {
mLogViewModel = new LogViewModel();
}
return new LogPresenter(mLogViewModel);
}
@Override
public String getUserName() {
return binding.userAccount.getText().toString();
}
@Override
public String getUserPwd() {
return binding.userPassword.getText().toString();
}
@Override
public void showLoginSuccess(String response) {
Toast.makeText(getActivity(), "登陆成功", Toast.LENGTH_LONG).show();
SharedPreferencesUtil.putString(getActivity(), SharedPreferencesUtil.PRE_NAME_SITUP, SharedPreferencesUtil.USER_ID, response);
ARouter.getInstance().build(RouteUtils.MainActivity).navigation();
getActivity().finish();
}
@Override
public void showLoginFailed(ErrCode errCode) {
if (errCode == ErrCode.WRONG_USER_NAME) {
Toast.makeText(getActivity(), "用户名错误", Toast.LENGTH_LONG).show();
}else if (errCode == ErrCode.WRONG_USER_PWD){
Toast.makeText(getActivity(), "密码错误", Toast.LENGTH_LONG).show();
}else if (errCode == ErrCode.WRONG_NET_WORK) {
Toast.makeText(getActivity(), "未知,请检查网络", Toast.LENGTH_LONG).show();
}
}
}
复制代码
这里我将上述过程写在个人 Demo
里,地址在 GitHub
你们能够直接查看改仓库源码,记得给我点个 star
哦~:web
Demo
地址:FIWKeepApp - LoginFragment后端
Retrofit
的使用都已近有了必定的了解,但 Retrofit 的好处并不仅是这些,还有不少跟深刻的只是须要了解,但本文限于篇幅,没法向你们一一介绍Android
的各类知识点、Framework
层源码,三方库等进行解析,欢迎你们关注 _yuanhao的掘金 及时接收更多优质博文!