转载请注意:http://blog.youkuaiyun.com/wjzj000/article/details/52806822
本菜开源的一个自己写的Demo,希望能给Androider们有所帮助,水平有限,见谅见谅...
https://github.com/zhiaixinyang/MyFirstApp
服务器绑定了域名
因此以前URL前面部分:http://120.27.4.196:8080/
需要更换成http://www.ohonor.xyz/
今天在研究Retrofit,但是我不得不说很多大神们的博客不考虑我们是新手的问题,在尝试他们简单的应用时,也充满了坎坷。所以在这里记录一下这俩天自己走进的一些坑。
(后文有补充:动态访问,post,retrofit的封装等)
现在先只记录最简单的Get方法请求获取json格式并且直接以String类型打印出来。
首先是gradle:
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
compile 'com.squareup.retrofit2:converter-scalars:2.0.2'
首先是构建一个接口:
PS:本Url可以正常访问,返回值为[{"temperature":"123","humidity":"41234"}],如果出现404,可以稍等片刻,换个姿势再来一次。
public interface IRetrofitTest {
String URL = "http://120.27.4.196:8080/test/servlet/";
@GET("ShowServlet")
Call<String> getString();
}
这里必须要记录一下,因为我在这栽了很多跟头。这里的URL会在Retrofit中的baseUrl()里使用,(而且必须要有,结尾必须有/)一会就能看到它的使用。而@GET("SHowServlet")中的内容,最终会和URL拼接成真正的url然后进行访问。如果单单是访问固定的url,它和下面的这种写法是相同的:
public interface IRetrofitTest {
String URL = "http://120.27.4.196:8080/";
@GET("http://120.27.4.196:8080/test/servlet/ShowServlet")
Call<String> getString();
}
在这里,@GET中的内容是真实访问的url,而定义的URL只要满足以/结尾即可。
当然我们也可以动态的去访问我们的url,那样的话,我们要这样写这个接口:
@GET("serlvet/{path}") Call<List<WS>> getWS(@Path("path") String path);我们在调用它的时候会传入一个String类型的值,这个值会替换{path}的path,然后把直接中替换过的值与baseUrl进行拼接然后访问。(这里有个小问题,就是我在测试的时候如果@GET注解中只存在{xxx}这样的值,那么网络请求的返回结果会是空,但不报错!)
PS:看了一些开源项目,发现好多人习惯把这个类叫做:XXXApi。
构建完接口之后就要进行下一步了。也就是:
Retrofit retrofit=new Retrofit.Builder()
.baseUrl(IRetrofitTest.URL)
.addConverterFactory(ScalarsConverterFactory.create())
.build();
IRetrofitTest iRetrofitTest=retrofit.create(IRetrofitTest.class);
Call<String> call=iRetrofitTest.getString();
call.enqueue(new Callback<String>() {
@Override
public void onResponse(Call<String> call, Response<String> response) {
Log.d("aaaa",response.body()+"");
}
@Override
public void onFailure(Call<String> call, Throwable t) {
}
});
response.body()就可以拿到服务器传回来的String类型的json数据。当然它也可以直接将json转换为javabean返回回来。
addConverterFactory(ScalarsConverterFactory.create())
也可以使用Gson直接解析,那么这就是现在博客中最常见的方式:
addConverterFactory(GsonConverterFactory.create())
接下来我们来看一下PSOT方法,最开始肯定还是构建Call对象:
@POST("servlet/SendServlet")
@FormUrlEncoded
Call<String> login(@Field("username") String username, @Field("password") String password);
注解@POST中依然是我们要与baseUrl拼接后访问的地址。@FormUrlEncoded的意思是我们要发送表单数据(表单,可以简单理解成一种发送数据的模式)。@Field的值和参数,则对应表单项中的键值对(key-value),这个链接在浏览器中访问的情况是这样的:http://120.27.4.196:8080/test/servlet/SendServlet?username=111&password=111
对应的请求方法就比较简单了,我这里类中也导入了OkHttp的Call类,所以Retorfit的Call的写法是retrofit2.Call。然后通过call异步请求就可以了。
Retrofit retrofit=new Retrofit.Builder()
.baseUrl(TestApis.HOST)
.addConverterFactory(ScalarsConverterFactory.create())
.build();
TestApis testApis=retrofit.create(TestApis.class);
retrofit2.Call<String> call=testApis.login("111","111");
返回值是String类型的:Success,I get data is:111!111!
表单过后还有文件和数据同时上传,这里需要另一个注解方式:Multipart,可以同时上传文件和文字信息。不过这里我的服务器关于这个测试的程序还没写,就先缓一缓....
在这里引用一下其他博客的一些知识点的梳理:
Url 配置
1
2
|
@GET ( "users/{user}/repos" ) Call<List<Repo>>
listRepos( @Path ( "user" )
String user); |
-
path 是相对路径,baseUrl 是目录形式:
path = "apath",baseUrl = "http://host:port/a/b/"
Url = "http://host:port/a/b/apath" -
path 是完整的 Url:
path = "http://host:port/aa/apath",baseUrl = "http://host:port/a/b"
Url = "http://host:port/aa/apath"
@GET("{xxx}")
也就是说不能让{xxx}独自存在于注解中,可以改成这样:@GET("xxx/{xxx}")
private void init() {
initOkHttp();
zhiHuApis=getZhiHuApi();
}
public RetrofitHelper() {
init();
}
private static void initOkHttp() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
File cacheFile = new File(ConstantURL.PATH_CACHE);
Cache cache = new Cache(cacheFile, 1024 * 1024 * 50);
Interceptor cacheInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!SystemUtil.isNetworkConnected()) {
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)
.build();
}
Response response = chain.proceed(request);
if (SystemUtil.isNetworkConnected()) {
int maxAge = 0;
// 有网络时, 不缓存, 最大保存时长为0
response.newBuilder()
.header("Cache-Control", "public, max-age=" + maxAge)
.removeHeader("Pragma")
.build();
} else {
// 无网络时,设置超时为4周
int maxStale = 60 * 60 * 24 * 28;
response.newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.removeHeader("Pragma")
.build();
}
return response;
}
};
//设置缓存
builder.addNetworkInterceptor(cacheInterceptor);
builder.addInterceptor(cacheInterceptor);
builder.cache(cache);
//设置超时
builder.connectTimeout(10, TimeUnit.SECONDS);
builder.readTimeout(20, TimeUnit.SECONDS);
builder.writeTimeout(20, TimeUnit.SECONDS);
//错误重连
builder.retryOnConnectionFailure(true);
okHttpClient = builder.build();
}
private static ZhiHuApis getZhiHuApi() {
Retrofit zhiHuRetrofit = new Retrofit.Builder()
.baseUrl(ZhiHuApis.ZHI_HU_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build();
return zhiHuRetrofit.create(ZhiHuApis.class);
}
public Call<ZhihuDetailBean> getZhiHuDetailFromId(int id) {
return zhiHuApis.getZhiHuThemeDetail(id);
}
public interface ZhiHuApis {
String ZHI_HU_URL="http://news-at.zhihu.com/api/4/";
/**
* 详细文章的id
*/
@GET("news/{id}")
Call<ZhihuDetailBean> getZhiHuThemeDetail(@Path("id") int id);