Android开发 retrofit入门讲解
<h1><span style="color: rgba(0, 128, 128, 1)">前言</span></h1><p><span style="color: rgba(0, 128, 128, 1)"> <span style="color: rgba(0, 0, 0, 1)">retrofit基于okhttp封装的网络请求框架,网络请求的工作本质上是 OkHttp 完成,而 retrofit 仅负责网络请求接口的封装.如果你不了解OKhttp建议你还是先了解它在来学习使用retrofit,传送门:</span></span>Android 开发 框架系列 OkHttp使用详解</p>
<p><span style="color: rgba(0, 0, 0, 1)"> Retrofit优势,就是简洁易用,解耦,扩展性强,可搭配多种Json解析框架(例如Gson),另外还支持RxJava.<strong>但是,这篇博客不讲解RxJava配合使用的部分,与RxJava的配合使用将在另外一篇博客中讲解.</strong></span></p>
<p><span style="color: rgba(0, 0, 0, 1)"> 另外<span style="color: rgba(0, 128, 128, 1)"><span style="color: rgba(0, 0, 0, 1)">retrofit</span></span>已经是封装的非常好了,作者的想的很完整,它的封装的思想十分准确而且恰到好处(堪称标准),所以不建议多此一举的再次<span style="color: rgba(0, 128, 128, 1)"><span style="color: rgba(0, 0, 0, 1)">封装<span style="color: rgba(0, 128, 128, 1)"><span style="color: rgba(0, 0, 0, 1)">retrofit</span></span>. 再次封装不会让你很牛逼. 只会让你看起来更蠢。<strong>你会想封装只能说明你压根没理解或者阅读过<span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 128, 128, 1)"><span style="color: rgba(0, 0, 0, 1)">retrofit</span></span></span></strong>。过度封装以后出现一个任何问题都可能出现重构灾难,那就整个项目的接口代码都要增加代码。减少重复工作只需要给2个东西做一个工具类(<span style="color: rgba(0, 0, 0, 1)">OkHttpClient与<span style="color: rgba(0, 0, 0, 1)">Retrofit.Builder())</span></span>,在一些简单场景只需要将配置好的网络接口列表服务类保存好(保存到Application或者单例保存)。</span></span></span></p>
<h1><span style="color: rgba(0, 128, 128, 1)"><strong>Github地址</strong></span></h1>
<p><span style="color: rgba(0, 128, 128, 1)"><strong> https://github.com/square/retrofit</strong></span></p>
<h1><span style="color: rgba(0, 128, 128, 1)">依赖</span></h1>
<p><span style="color: rgba(0, 128, 128, 1)"> <span style="color: rgba(0, 0, 0, 1)">如果你不需要使用RxJava模式,那么你只需要依赖下面2个:</span></span></p>
<div class="cnblogs_code">
<pre> implementation <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">com.squareup.retrofit2:retrofit:2.6.2</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">
implementation </span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">com.squareup.retrofit2:converter-gson:2.4.0</span><span style="color: rgba(128, 0, 0, 1)">'</span></pre>
</div>
<p> gson是用来解析的Json数据使用的(个人偏爱Gson),<span style="color: rgba(0, 128, 128, 1)"><span style="color: rgba(0, 0, 0, 1)">retrofit也支持其他解析工具比如fastJson</span></span></p>
<h1><span style="color: rgba(0, 128, 128, 1)">简单的Demo(异步请求)</span></h1>
<p><span style="color: rgba(0, 0, 0, 1)"> 老规矩按思维顺序讲解demo</span></p>
<h3><span style="color: rgba(0, 0, 0, 1)">1.创建Retrofit请求基础配置</span></h3>
<p> <span style="color: rgba(0, 0, 0, 1)">Retrofit</span>配置好后,你可以将它单例保存,也不可以保存。<span style="color: rgba(0, 0, 0, 1)">Retrofit.Builder()</span>就是希望你根据不同的业务创建出不同的<span style="color: rgba(0, 0, 0, 1)">Retrofit来搭配接口服务使用。</span></p>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Retrofit mRetrofit;
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> initHttpBase(){
mRetrofit </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Retrofit.Builder()
.baseUrl(</span>"http://doclever.cn:8090/mock/5c3c6da33dce46264b24452b/")<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">base的网络地址baseUrl不能为空,且强制要求必需以 / 斜杠结尾</span>
.addConverterFactory(GsonConverterFactory.create())<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">使用Gson解析</span>
.callbackExecutor(Executors.newSingleThreadExecutor())<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">使用单独的线程处理 (这很重要,一般网络请求如果不设置可能不会报错,但是如果是下载文件就会报错)</span>
<span style="color: rgba(0, 0, 0, 1)"> .build();
}</span> </pre>
</div>
<p><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(255, 0, 0, 1)"><strong>注意! </strong></span>base的网络地址 baseUrl不能为空,且强制要求必需以 / 斜杠结尾</span></p>
<h3>2.创建数据返回后的Bean类</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> LoginBean {
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> code;
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String message;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getCode() {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> code;
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setCode(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> code) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.code =<span style="color: rgba(0, 0, 0, 1)"> code;
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getMessage() {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> message;
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setMessage(String message) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.message =<span style="color: rgba(0, 0, 0, 1)"> message;
}
}</span></pre>
</div>
<h3>2.创建一个网络请求接口</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">interface</span><span style="color: rgba(0, 0, 0, 1)"> HttpList {
@FormUrlEncoded </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">注解表示from表单还有@Multipart 表单可供使用 当然你也可以不添加</span>
@POST("test/login_test") <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">网络请求路径</span>
Call<LoginBean> login(@Field("number") String number, @Field("password"<span style="color: rgba(0, 0, 0, 1)">) String password); <span style="color: rgba(0, 128, 0, 1)">//@Field("number") 为post值的的key</span>
}</span></pre>
</div>
<p>注意,这是一个接口类. LoginBean则是数据返回后的Bean类(<span style="color: rgba(0, 0, 0, 1)">Retrofit</span>会自动使用导入的Gson解析)</p>
<p><span style="color: rgba(255, 0, 0, 1)"><strong>注意! <span style="color: rgba(0, 0, 0, 1)">@POST("test/login_test") 这路径最前面不能加斜杠 / ,否则它会自动裁剪路径,这样会导致你的路径错误</span></strong></span></p>
<h3><span style="color: rgba(0, 128, 128, 1)"><span style="color: rgba(0, 0, 0, 1)">3.请求网络</span></span></h3>
<p><span style="color: rgba(0, 128, 128, 1)"><span style="color: rgba(0, 0, 0, 1)">这里的mRetrofit.create创建的接口服务,如果无改变<span style="color: rgba(0, 0, 0, 1)">Retrofit</span>,也可以用一个单例类保存在<span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 128, 128, 1)"><span style="color: rgba(0, 0, 0, 1)">Application</span></span></span>起来全局使用。</span></span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> postHttp(){
HttpList httpList </span>= mRetrofit.create(HttpList.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
Call</span><LoginBean> call = httpList.login("181234123", "123456"<span style="color: rgba(0, 0, 0, 1)">);
call.enqueue(</span><span style="color: rgba(0, 0, 255, 1)">new</span> Callback<LoginBean><span style="color: rgba(0, 0, 0, 1)">() {
@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> onResponse(Call<LoginBean> call, Response<LoginBean><span style="color: rgba(0, 0, 0, 1)"> response) {
LoginBean bean </span>=<span style="color: rgba(0, 0, 0, 1)"> response.body();
Log.e(TAG, </span>"onResponse: code="+<span style="color: rgba(0, 0, 0, 1)">bean.getCode());
Log.e(TAG, </span>"onResponse: message="+<span style="color: rgba(0, 0, 0, 1)">bean.getMessage());
}
@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> onFailure(Call<LoginBean><span style="color: rgba(0, 0, 0, 1)"> call, Throwable t) {
Log.e(TAG, </span>"onFailure: 网络请求失败="+<span style="color: rgba(0, 0, 0, 1)">t.getMessage());
}
});
}</span></pre>
</div>
<p> 这样,我们就完成了一个网络请求.是不是特别简单</p>
<h1><span style="color: rgba(0, 128, 128, 1)">同步请求</span></h1>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> postHttp2() {
HttpList httpList </span>= mRetrofit.create(HttpList.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">final</span> Call<LoginBean> call = httpList.login("181234123", "123456"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">new</span> Thread(<span style="color: rgba(0, 0, 255, 1)">new</span> Runnable() { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">Android主线程不能操作网络请求,所以new一个线程来操作</span>
<span style="color: rgba(0, 0, 0, 1)"> @Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> run() {
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
Response</span><LoginBean> response = call.execute();<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">同步请求网络</span>
LoginBean bean =<span style="color: rgba(0, 0, 0, 1)"> response.body();
Log.e(TAG, </span>"onResponse: code=" +<span style="color: rgba(0, 0, 0, 1)"> bean.getCode());
Log.e(TAG, </span>"onResponse: message=" +<span style="color: rgba(0, 0, 0, 1)"> bean.getMessage());
} </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) {
e.printStackTrace();
}
}
}).start();
}</span></pre>
</div>
<h1><span style="color: rgba(0, 128, 128, 1)">取消网络请求</span></h1>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> cancelHttp(){
HttpList httpList </span>= mRetrofit.create(HttpList.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">这里贴这部分代码是告诉call是哪里来的,关键点就是这个call,当然你也可以从回调里获取</span>
mCall = httpList.login("181234123", "123456"<span style="color: rgba(0, 0, 0, 1)">);
mCall.cancel(); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">取消请求</span>
}</pre>
</div>
<h1><span style="color: rgba(0, 128, 128, 1)">如何添加Header头</span></h1>
<p><span style="color: rgba(0, 0, 0, 1)">以固定数据的形式添加头信息</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">interface</span><span style="color: rgba(0, 0, 0, 1)"> HttpList {
@Headers({</span>"content1:one","content2:two"<span style="color: rgba(0, 0, 0, 1)">})
@POST(</span>"test/logout_test"<span style="color: rgba(0, 0, 0, 1)">)
Call</span><LoginBean><span style="color: rgba(0, 0, 0, 1)"> logout1();
}</span></pre>
</div>
<p>以非固定数据的形式添加头信息</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">interface</span><span style="color: rgba(0, 0, 0, 1)"> HttpList {
@POST(</span>"test/logout_test"<span style="color: rgba(0, 0, 0, 1)">)
Call</span><LoginBean> logout2(@Header("content"<span style="color: rgba(0, 0, 0, 1)">) String content);
}</span></pre>
</div>
<p><span style="color: rgba(0, 0, 0, 1)">批量设置head头</span></p>
<div>
<pre class="highlighter-hljs" data-dark-theme="true"><code>/**
* 获取帮助列表数据 AppGetQuestAndHelp
*/
@POST("jiaiot/api/app/smarthome/token")
suspend fun helpList(
@HeaderMap headers: Map<String, String>,
@Body requestBody: RequestBody?
): Response<Result<List<HelpBean>>></code></pre>
</div>
<h1><span style="color: rgba(0, 128, 128, 1)">Body配置</span></h1>
<p><span style="color: rgba(0, 0, 0, 1)">Body一般有4个种类</span></p>
<ul>
<li><span style="color: rgba(0, 0, 0, 1)"><strong>application/x-www-form-urlencoded 表单数据 </strong></span></li>
<li><span style="color: rgba(0, 0, 0, 1)"><strong>multipart/form-data 表单文件上传 </strong></span></li>
<li><span style="color: rgba(0, 0, 0, 1)"><strong>application/json 序列化JSON数据 </strong></span></li>
<li><span style="color: rgba(0, 0, 0, 1)"><strong>text/xml XML数据</strong></span></li>
</ul>
<p><span style="color: rgba(0, 0, 0, 1)">框架直接提供的2个Body</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">interface</span><span style="color: rgba(0, 0, 0, 1)"> HttpList {
@FormUrlEncoded </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">application/x-www-form-urlencoded表单body</span>
@POST("test/login_test"<span style="color: rgba(0, 0, 0, 1)">)
Call</span><LoginBean> login2(@Field("number") String number, @Field("password"<span style="color: rgba(0, 0, 0, 1)">) String password);
@Multipart </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">multipart/form-data此body支持文件上传与下载</span>
@POST("test/login_test"<span style="color: rgba(0, 0, 0, 1)">)
Call</span><LoginBean> login3(@Field("number") String number, @Field("password"<span style="color: rgba(0, 0, 0, 1)">) String password);
}</span></pre>
</div>
<h2><span style="color: rgba(0, 0, 0, 1)">自定义Body</span></h2>
<p><span style="color: rgba(0, 0, 0, 1)">其他2个就需要自定义创建了,下面举例Json Body的创建:</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)"> /**</span><span style="color: rgba(0, 128, 0, 1)">
*
* </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> string直接导入需要发送给服务器的JSON的String值
* </span><span style="color: rgba(128, 128, 128, 1)">@return</span>
<span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> RequestBody getRequestBody(String string) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> RequestBody.create(MediaType.parse("application/json; charset=utf-8"<span style="color: rgba(0, 0, 0, 1)">), string);
}</span></pre>
</div>
<p>在接口类参数需要设置为 @Body RequestBody requestBody</p>
<div class="cnblogs_code">
<pre> @POST("app/system/demo"<span style="color: rgba(0, 0, 0, 1)">)
Observable</span><UpdateInfo> demo(@Body RequestBody requestBody);</pre>
</div>
<h2><span style="color: rgba(0, 0, 0, 1)">表单带参上传文件的Body</span></h2>
<p><span style="color: rgba(0, 0, 0, 1)">http</span></p>
<div>
<pre class="highlighter-hljs" data-dark-theme="true"><code>/**
* 上传日志文件
* @return
*/
@Multipart
@POST("smarthome/upload_token")
suspend fun updateLogFile(
@HeaderMap headers: Map<String, String>,
@Part part: List<MultipartBody.Part>
): Response<Result<Any>></code></pre>
</div>
<p><span style="color: rgba(0, 0, 0, 1)">请求部分</span></p>
<div>
<div>
<pre class="highlighter-hljs" data-dark-theme="true"><code>val http = Http.getInstance().tokenUploadFile<HttpList>(HttpList::class.java)
val fileBody = zipFile.asRequestBody("multipart/form-data".toMediaTypeOrNull())
val multipartBody = MultipartBody.Builder()
.addFormDataPart("biz_id", "app-log")
.addFormDataPart("file_name", zipFile.getName())
.addFormDataPart("file", zipFile.getName(),fileBody)
.build().parts
http.updateLogFile(heads, multipartBody).apply {
"上传日志结果 = $isSuccessful".logE()
if (isSuccessful) {
"${body().toString()}".logE()
} else {
}
}</code></pre>
</div>
</div>
<h1><span style="color: rgba(0, 128, 128, 1)">手动解析Response请求返回</span></h1>
<p><span style="color: rgba(0, 0, 0, 1)">有时候我们不需要使用GsonConverterFactory帮我们解析body数据,我们希望自己能操作数据并且解析。比如获取下载数据的流,我们需要使用ResponseBody类(这个类是okhttp返回body类)。代码如下</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">interface</span><span style="color: rgba(0, 0, 0, 1)"> HttpList {
@GET(</span>"aaa/bbb/ccc/"<span style="color: rgba(0, 0, 0, 1)">)
Call</span><ResponseBody> post(@Query("token"<span style="color: rgba(0, 0, 0, 1)">) String token);
}</span></pre>
</div>
<p> </p>
<p><span style="color: rgba(0, 0, 0, 1)">请求后返回的ResponseBody使用方式请参考okhttp的博客 https://www.cnblogs.com/guanxinjing/p/9708575.html</span></p>
<h1><span style="color: rgba(0, 128, 128, 1)">添加配置的OkHttpClient(主要使用请求超时/拦截器等功能)</span></h1>
<p>上面说了retrofit是基于Okhttp开发的网络请求框架,所以它有一部分的功能依然需要使用Okhttp的方式来配置比如请求超时时间/设置拦截器等等,下面就展示一下如何添加</p>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> initHttpBase2() {
OkHttpClient okHttpClient </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> OkHttpClient.Builder()
.retryOnConnectionFailure(</span><span style="color: rgba(0, 0, 255, 1)">false</span>) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">在连接失败时重试</span>
.callTimeout(30, TimeUnit.SECONDS) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">呼叫超时,设置此参数为整体流程请求的超时时间</span>
.connectTimeout(20,TimeUnit.SECONDS)<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">连接超时</span>
.readTimeout(20,TimeUnit.SECONDS)<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">读取超时</span>
.writeTimeout(20,TimeUnit.SECONDS)<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">写入超时
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> .callTimeout()</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">呼叫超时,设置此参数为整体流程请求的超时时间
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> .addInterceptor() </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置拦截器
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> .authenticator() </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置认证器
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> .proxy()</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置代理</span>
<span style="color: rgba(0, 0, 0, 1)"> .build();
mRetrofit </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Retrofit.Builder()
.client(okHttpClient)
.baseUrl(</span>"http://doclever.cn:8090/mock/5c3c6da33dce46264b24452b/")<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">base的网络地址</span>
.addConverterFactory(GsonConverterFactory.create())<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">使用Gson解析</span>
<span style="color: rgba(0, 0, 0, 1)"> .callbackExecutor(Executors.newSingleThreadExecutor())
.build();
}</span></pre>
</div>
<h1><span style="color: rgba(0, 128, 128, 1)">部分路径动态的BaseUrl</span></h1>
<div class="cnblogs_code">
<pre> @POST("/article/query/{page}/json"<span style="color: rgba(0, 0, 0, 1)">)
@FormUrlEncoded
Observable</span><DataResponse<Article>> getSearchArticles(@Path("page") <span style="color: rgba(0, 0, 255, 1)">int</span> page, @Field("k") String k);</pre>
</div>
<h1><span style="color: rgba(0, 128, 128, 1)">实现Url路径传参数</span></h1>
<p><span style="color: rgba(0, 0, 0, 1)">@Query 有值的查询名称</span></p>
<div class="cnblogs_code">
<pre> @GET("app/data"<span style="color: rgba(0, 0, 0, 1)">)
Call</span><Result> getData(@Query("id") String id);</pre>
</div>
<div class="cnblogs_code">
<pre> @GET("app/data"<span style="color: rgba(0, 0, 0, 1)">)
Call</span><Result> getData(@Query("id") String... id);</pre>
</div>
<p>@QueryName 只有值没有key的传参</p>
<div class="cnblogs_code">
<pre> @GET("app/data"<span style="color: rgba(0, 0, 0, 1)">)
Call</span><Resul> getData(@QueryName String id);</pre>
</div>
<div class="cnblogs_code">
<pre> @GET("app/data"<span style="color: rgba(0, 0, 0, 1)">)
Call</span><Resul> getData(@QueryName String... id);</pre>
</div>
<p>@QueryMap 用哈希集合传值</p>
<div class="cnblogs_code">
<pre> @GET("app/data"<span style="color: rgba(0, 0, 0, 1)">)
Call</span><Result> getData(@QueryMap Map<String,String> map);</pre>
</div>
<h1><span style="color: rgba(0, 128, 128, 1)">自定义GsonConverterFactory</span></h1>
<p>下面这个自定义用于检查了token是否失效</p>
<p>bean</p>
<div class="cnblogs_code">
<pre>data <span style="color: rgba(0, 0, 255, 1)">class</span> BaseResult<T>(var code: Int, var msg: String?, var data: T?)</pre>
</div>
<p>GsonConverterFactory</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span> CheckTokenGsonConverterFactory <span style="color: rgba(0, 0, 255, 1)">extends</span><span style="color: rgba(0, 0, 0, 1)"> Converter.Factory {
</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
* Create an instance using a default {</span><span style="color: rgba(128, 128, 128, 1)">@link</span><span style="color: rgba(0, 128, 0, 1)"> Gson} instance for conversion. Encoding to JSON and
* decoding from JSON (when no charset is specified by a header) will use UTF-8.
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> CheckTokenGsonConverterFactory create() {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> create(<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Gson());
}
</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
* Create an instance using {</span><span style="color: rgba(128, 128, 128, 1)">@code</span><span style="color: rgba(0, 128, 0, 1)"> gson} for conversion. Encoding to JSON and decoding from JSON
* (when no charset is specified by a header) will use UTF-8.
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
@SuppressWarnings(</span>"ConstantConditions") <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Guarding public API nullability.</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> CheckTokenGsonConverterFactory create(Gson gson) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (gson == <span style="color: rgba(0, 0, 255, 1)">null</span>) <span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> NullPointerException("gson == null"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> CheckTokenGsonConverterFactory(gson);
}
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">final</span><span style="color: rgba(0, 0, 0, 1)"> Gson gson;
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> CheckTokenGsonConverterFactory(Gson gson) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.gson =<span style="color: rgba(0, 0, 0, 1)"> gson;
}
@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> Converter<ResponseBody, ?><span style="color: rgba(0, 0, 0, 1)"> responseBodyConverter(
Type type, Annotation[] annotations, Retrofit retrofit) {
TypeAdapter</span><?> adapter =<span style="color: rgba(0, 0, 0, 1)"> gson.getAdapter(TypeToken.get(type));
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span> MyGsonResponseBodyConverter<><span style="color: rgba(0, 0, 0, 1)">(gson, adapter);
}
@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> Converter<?, RequestBody><span style="color: rgba(0, 0, 0, 1)"> requestBodyConverter(
Type type,
Annotation[] parameterAnnotations,
Annotation[] methodAnnotations,
Retrofit retrofit) {
TypeAdapter</span><?> adapter =<span style="color: rgba(0, 0, 0, 1)"> gson.getAdapter(TypeToken.get(type));
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span> MyGsonRequestBodyConverter<><span style="color: rgba(0, 0, 0, 1)">(gson, adapter);
}
</span><span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> <span style="color: rgba(0, 0, 255, 1)">class</span> MyGsonRequestBodyConverter<T> <span style="color: rgba(0, 0, 255, 1)">implements</span> Converter<T, RequestBody><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> MediaType MEDIA_TYPE = MediaType.get("application/json; charset=UTF-8"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> Charset UTF_8 = Charset.forName("UTF-8"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">final</span><span style="color: rgba(0, 0, 0, 1)"> Gson gson;
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">final</span> TypeAdapter<T><span style="color: rgba(0, 0, 0, 1)"> adapter;
MyGsonRequestBodyConverter(Gson gson, TypeAdapter</span><T><span style="color: rgba(0, 0, 0, 1)"> adapter) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.gson =<span style="color: rgba(0, 0, 0, 1)"> gson;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.adapter =<span style="color: rgba(0, 0, 0, 1)"> adapter;
}
@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> RequestBody convert(T value) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> IOException {
Buffer buffer </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Buffer();
Writer writer </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> OutputStreamWriter(buffer.outputStream(), UTF_8);
JsonWriter jsonWriter </span>=<span style="color: rgba(0, 0, 0, 1)"> gson.newJsonWriter(writer);
adapter.write(jsonWriter, value);
jsonWriter.close();
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> RequestBody.create(MEDIA_TYPE, buffer.readByteString());
}
}
</span><span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> <span style="color: rgba(0, 0, 255, 1)">class</span> MyGsonResponseBodyConverter <T> <span style="color: rgba(0, 0, 255, 1)">implements</span> Converter<ResponseBody, T><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">final</span><span style="color: rgba(0, 0, 0, 1)"> Gson gson;
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">final</span> TypeAdapter<T><span style="color: rgba(0, 0, 0, 1)"> adapter;
MyGsonResponseBodyConverter(Gson gson, TypeAdapter</span><T><span style="color: rgba(0, 0, 0, 1)"> adapter) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.gson =<span style="color: rgba(0, 0, 0, 1)"> gson;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.adapter =<span style="color: rgba(0, 0, 0, 1)"> adapter;
}
@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> T convert(ResponseBody value) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> IOException {
String response </span>=<span style="color: rgba(0, 0, 0, 1)"> value.string();
BaseResult baseResult </span>= gson.fromJson(response, BaseResult.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (baseResult.getCode() ==<span style="color: rgba(0, 0, 0, 1)"> NetCode.REQUEST_SUCCESS){
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">token失效,请在这里处理token失效后返回登入页面的代码。</span>
<span style="color: rgba(0, 0, 0, 1)">
}
InputStream inputStream </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ByteArrayInputStream(response.getBytes());
MediaType contentType </span>=<span style="color: rgba(0, 0, 0, 1)"> value.contentType();
Charset charset </span>= contentType != <span style="color: rgba(0, 0, 255, 1)">null</span> ?<span style="color: rgba(0, 0, 0, 1)"> contentType.charset(UTF_8) : UTF_8;
Reader reader </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> InputStreamReader(inputStream, charset);
JsonReader jsonReader </span>=<span style="color: rgba(0, 0, 0, 1)"> gson.newJsonReader(reader);
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
T result </span>=<span style="color: rgba(0, 0, 0, 1)"> adapter.read(jsonReader);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (jsonReader.peek() !=<span style="color: rgba(0, 0, 0, 1)"> JsonToken.END_DOCUMENT) {
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> JsonIOException("JSON document was not fully consumed."<span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> result;
} </span><span style="color: rgba(0, 0, 255, 1)">finally</span><span style="color: rgba(0, 0, 0, 1)"> {
value.close();
}
}
}
}</span></pre>
</div>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p>end</p>
<pre class="highlighter-hljs" data-dark-theme="true"><code>Response</code></pre>
</div>
<div id="MySignature" role="contentinfo">
<div style="text-align: center">
<p style="color:orange;font-size:16px;" >本文来自博客园,作者:观心静 ,转载请注明原文链接:https://www.cnblogs.com/guanxinjing/p/11594249.html </p>
<div style="color:orange;font-size:16px;">本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。 </div>
</div><br><br>
来源:https://www.cnblogs.com/guanxinjing/p/11594249.html
頁:
[1]