学习Retrofit

转载请标明出处: http://blog.csdn.net/long117long/article/details/78257923


    Retrofit是什么?做过Android开发的想必都知道,它是GitHub上java语言中star (24.3k,20171013 )最多的网络请求库之一。
    网上有很多优秀的文章介绍如何使用Retrofit,这里我只想将我自己一开始学习使用Retrofit的过程记录下来。
1. 如何将Retrofit引用到工程中?
    Retrofit目前有Retrofit1 和 Retrofit2 之分,在这里我们使用Retrofit2。
    引用到Android Studio中:
1
compile 'com.squareup.retrofit2:retrofit:2.3.0'
2. 如何使用Retrofit请求http://www.baidu.com?
    使用Retrofit,我第一个想到的是如何得到 http://www.baidu.com 的结果,就像看网络通不通,使用 ping   www.baidu.com 一样。
    网络请求的地址在Retrofit中分为了两部分,一部分是baseUrl,一部分是后缀,而后缀的部分使用的注解。
    先写注解部分的代码:
1
public interface ApiService {
2
    //因为我们请求的http://www.baidu.com 没有后缀,所以注解部分这么写。
3
    @GET("/")
4
    Call<ResponseBody> get();
5
}
    因为需要上网,所以需要在AndroidMenifest.xml中申请权限:
1
:name="android.permission.INTERNET" />
    先写请求之前的代码:
1
Retrofit retrofit = new Retrofit.Builder()
2
                .client(new OkHttpClient())
3
                .baseUrl("http://www.baidu.com/")
4
                .build();
5
ApiService api = retrofit.create(ApiService.class);
6
Call<ResponseBody> call = api.get();
    请求的写法可以是同步的,也可以是异步的。
    以下异步的写法,
    需要注意的是,call.enqueue可以写在主线程,也可以在子线程。而回调是在主线程的,因此可以更新界面。
1
 call.enqueue(new Callback<ResponseBody>() {
2
            @Override
3
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
4
                try {
5
                    Log.v("testRetrofit",call.request().url().toString());
6
                    Log.v("testRetrofit",response.body().string());
7
                    // 回调是在主线程的,因此可以更新界面
8
                    Toast.makeText(getApplicationContext(),"onResponse",Toast.LENGTH_SHORT).show();
9
                }catch (IOException e) {
10
                    e.printStackTrace();
11
                }
12
            }
13
            @Override
14
            public void onFailure(Call<ResponseBody> call, Throwable throwable) {
15
                Log.v("testRetrofit",throwable.toString());
16
            }
17
        });
    以下是同步的写法,
    需要注意的,call.execute()是需要写在子线程的,如果写在主线程会抛出android.os.NetworkOnMainThreadException的异常。
1
  Retrofit retrofit = new Retrofit.Builder()
2
      .client(new OkHttpClient())
3
          .baseUrl("http://www.baidu.com/")
4
          .build();
5
6
  ApiService api = retrofit.create(ApiService.class);
7
  Call<ResponseBody> call = api.get();
8
  try {
9
      Response<ResponseBody> response = call.execute();
10
      Log.v("testRetrofit",response.body().string());
11
  } catch (IOException e) {
12
      e.printStackTrace();
13
  } 
     注意,在baseUrl中写的是: http://www.baidu.com/ 。
     到底要不要最后的 /,参看网上的说明大致意思是在Retrofit2中最好添加。
     参看: http://blog.csdn.net/zxc123e/article/details/51722323  中的 “六、新的URL定义方式”

3. 想要使用"GET"、“POST”等请求数据怎么办?
     上面的例子没有携带任何数据请求远端,而我们跟后台交互一般都会是请求一些数据,比如:查询存储在远端的某个关键字信息,提交一些本地数据到远端等等。
    Retrofit已经封装了HTTP协议的请求方法(GET,POST,HEAD等),比如,要进行如下请求:
1
https://api.github.com/users/{user}/repos
    那么在创建Retrofit时的baseUrl应该写成:
1
final Retrofit retrofit = new Retrofit.Builder()
2
                .client(new OkHttpClient())
3
                .baseUrl("https://api.github.com/")
4
                .build();
       而注解应该写成这样:
1
 @GET("users/{user}/repos")
2
 Call<ResponseBody> getRepos(@Path("user") String user);
    里面的注解“@Path”,是用于替换Url路径中的变量字符。
    Retrofit封装一些常用的Url路径处理注解,有:@Path、@Query、@QueryMap、 @Body、 @Field等,可以自己查一下。
    
4. 处理Json字符串
    我们从远端得到的数据通常是Json字符串的格式,我们可以使用其提供的Converter来做转换,比如:
1
Gson: com.squareup.retrofit2:converter-gson
2
Jackson: com.squareup.retrofit2:converter-jackson
3
Moshi: com.squareup.retrofit2:converter-moshi
4
Protobuf: com.squareup.retrofit2:converter-protobuf
5
Wire: com.squareup.retrofit2:converter-wire
6
Simple XML: com.squareup.retrofit2:converter-simplexml
7
Scalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars
    甚至我们可以自定义converter。
    那如何使用converter-gson呢?
    首先,需要在工程中引入jar包:
1
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
    在代码创建Retrofit时,添加gson的converter: .addConverterFactory(GsonConverterFactory.create()), 整体代码如下:
1
final Retrofit retrofit = new Retrofit.Builder()
2
                .client(new OkHttpClient())
3
                .baseUrl("http://www.weather.com.cn/")
4
                .addConverterFactory(GsonConverterFactory.create())
5
                .build();
        本例中查询返回的结果大致如下:
1
{"weatherinfo":{"city":"北京","cityid":"101010100","temp":"10","WD":"东南风","WS":"2级","SD":"26%","WSE":"2","time":"10:25","isRadar":"1","Radar":"JC_RADAR_AZ9010_JB","njd":"暂无实况","qy":"1012"}}
    创建相关的bean:
1
public class WeatherJson {
2
    //注意,将声明的变量 和 结果中的 完全一致
3
    private Weatherinfo weatherinfo;
4
    public Weatherinfo getWeatherinfo() {
5
        return weatherinfo;
6
    }
7
    public void setWeatherinfo(Weatherinfo weatherinfo) {
8
        this.weatherinfo = weatherinfo;
9
    }
10
     public class Weatherinfo {
11
        private String city;
12
        private String cityid;
13
        private String temp;
14
        private String WD;
15
        private String WS;
16
        private String SD;
17
        private String WSE;
18
        private String time;
19
        private String isRadar;
20
        private String Radar;
21
        private String njd;
22
        private String qy;
23
        // 要添加对应的 get 和 set,实例中省去
24
     }
25
}
    接口声明:
1
@GET("adat/sk/{cityId}.html")
2
Call<WeatherJson> getWeatherJson(@Path("cityId") String cityId);
    调用时的代码如下:
1
        ApiService apiService = retrofit.create(ApiService.class);
2
        Call<WeatherJson> call = apiService.getWeatherJson("101010100");
3
        call.enqueue(new Callback<WeatherJson>() {
4
             @Override
5
            public void onResponse(Call<WeatherJson> call, Response<WeatherJson> response) {
6
                WeatherJson json = response.body();
7
                StringBuffer sb = new StringBuffer();
8
                sb.append("city:");
9
                sb.append(json.getWeatherinfo().getCity());
10
                sb.append(" Temp:");
11
                sb.append(json.getWeatherinfo().getTemp());
12
                sb.append("℃");
13
                Log.v("testRetrofit",sb.toString());
14
            }
15
            @Override
16
            public void onFailure(Call<WeatherJson> call, Throwable throwable) {
17
                Log.v("testRetrofit",throwable.toString());
18
19
            }
20
        });
    调用结果如下:
1
V/testRetrofit: city:北京 Temp:10
    5. 能不能使用动态的Url?
    我在刚开始接触Retrofit时,就有个疑问:请求的Url是在编码时以注解的形式写好的,那能不能在使用Retrofit时不提前写好,也就是说在代码调用时我再准备好我想请求的Url? 这个是可以的。
    需要将注解这么写:
1
 @GET
2
 Call<ResponseBody> useUrl(@Url String url);
    而调用代码如下:
1
final Retrofit retrofit = new Retrofit.Builder()
2
                .client(new OkHttpClient())
3
                .baseUrl("http://www.baidu.com/")//baseUrl不能少,也不能为"",否则出错
4
                .addConverterFactory(GsonConverterFactory.create())
5
                .build();
6
String url = "http://www.weather.com.cn/adat/sk/101010100.html";
7
        ApiService apiService = retrofit.create(ApiService.class);
8
        apiService.useUrl(url)
9
                .enqueue(new Callback<ResponseBody>() {
10
                    @Override
11
                    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
12
                        try {
13
                            Log.v("testRetrofit",response.body().string());
14
                        } catch (IOException e) {
15
                             e.printStackTrace();
16
                        }
17
                    }
18
                    @Override
19
                    public void onFailure(Call<ResponseBody> call, Throwable throwable) {
20
                    }
21
                });



你可能感兴趣的:(android)