Retrofit ?Retrofit 早已不是什么新技术了,想必看到这篇博客的大家都早已熟知,这里就不啰嗦了,简单介绍下:
 
REST 客户机。它通过基于 REST 的 web 服务检索和上传 JSON (或其他结构化数据)变得相对容易。在使用中,您可以配置用于数据序列化的转换器。对于 JSON ,通常使用Gson ,但是可以添加自定义转换器来处理 XML 或其他协议。Retrofit 对 HTTP 请求使用 OkHttp 库。A type-safe HTTP client for Android and Java

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~ 大家直接用即可
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 页面为例:

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/loginurl = 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 对象生成器,门路很多这里都告诉你们啦
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 的使用RetrofitMVP + 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> 基类/**
 * @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 哦~:
 Demo 地址:FIWKeepApp - LoginFragment
 Android 的各种知识点、Framework 层源码,三方库等进行解析,欢迎大家关注 _yuanhao CSDN 及时接收更多优质博文!