Android杂谈(18)Retrofit实践

本文详细介绍Retrofit的基本使用方法,包括GET和POST请求的实现,并分享了动态访问和POST请求的实践心得,适合初学者快速上手。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 


转载请注意: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())
这个方法非常的重要,它的意思以什么样的方式返回从服务器那到的数值。这里是指直接将服务器返回的数据以String类型的方式返回过来。

也可以使用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 配置

Retrofit 支持的协议包括 GET/POST/PUT/DELETE/HEAD/PATCH,当然你也可以直接用 HTTP 来自定义请求。这些协议均以注解的形式进行配置,比如我们已经见过 GET 的用法:

1
2
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
这些注解都有一个参数 value,用来配置其路径,比如示例中的 users/{user}/repos,我们还注意到在构造 Retrofit 之时我们还传入了一个 baseUrl("https://api.github.com/"),请求的完整 Url 就是通过 baseUrl 与注解的 value(下面称 “path“ ) 整合起来的,具体整合的规则如下:
  • 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"


2016年11月20日补充:(!!这里有踩到坑了)
在使用@Path时:!
如果直接这样写,注解里只有{xxx},无论怎么拼接url,都有问题!
   不是出错,而是没有返回值!!!   
@GET("{xxx}")
也就是说不能让{xxx}独自存在于注解中,可以改成这样:
@GET("xxx/{xxx}")


2016年11月19日补充:
这里记录在一个开源项目中看到的封装,这个类的名字叫:RetrofitHelper。以下是构造方法,以及相关的初始化。
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();
}


然后是封装Retrofit的请求:
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);


最终使用时,调用getZhiHuDetailFromId方法,传入id。接下来就会调用对应的URL接口中的getZhiHuThemeDetail方法,去拼接URL,拿到Call<ZhihuDetailBean>对象,调用enqueue方法,完成最终的网络请求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值