retrofit 2.0 簡單使用

Retrofit與okhttp都是出於Square公司,Retrofit對okhttp做了一層包裝,把網絡請求都交給了okhttp(可以參考okhttp3使用),因此只需要簡單的配置,就能用Retrofit進行網絡請求。

一、引入retrofit 2.0

需要在項目下的build.gradle添加retrofit 2.0.2的引用

// retrofit 庫
compile 'com.squareup.retrofit2:retrofit:2.0.2'
// 使用gson解析數據內容
compile 'com.squareup.retrofit2:converter-gson:2.0.2'

這裏寫圖片描述

如上圖所示,引入retrofit 2.0.2後,會在External Libraries中看到retrofit-2.0.2okhttp-3.2.0okio-1.6.0,這是因爲retrofit 2.0.2封裝了okhttp-3.2.0,而okhttp-3.2.0又依賴於okio-1.6.0,因此引入一個retrofit庫,會自動添加其依賴的其他庫。

二、retrofit 2.0 基本使用

1、retrofit對象創建

Retrofit retrofit = new Retrofit.Builder()
                                // 設置基本url,通常是協議+IP地址+端口
                                .baseUrl(API_URL)
                                // 設置數據解析的格式,需要引入gson庫 
                                .addConverterFactory(GsonConverterFactory.create())
                                .build();

2、retrofit網絡請求接口

retrofit將Http Api使用Java接口表示;

public interface GitHub {
    @GET("/repos/{owner}/{repo}/contributors")
    Call<List<Contributor>> contributors(
            @Path("owner") String owner,
            @Path("repo") String repo);
}

每一個Call對象從GitHub接口裏的方法獲取,Call基於Http的同步/異步方法想服務端獲取請求結果。

Call<List<Contributor>> call = github.contributors("square", "retrofit");

3、動態設置url的Get方法

retrofit 2.0允許動態設置 URL,需要使用一對大括號{}將需要動態替換的URL內容括起來,對應的參數使用相同的字符串,同時使用@Path註解表示。

如,需要請求這個地址(https://api.github.com/repos/square/retrofit/contributors)的數據,可以添加請求接口:

public interface GitHub {
    @GET("/repos/{owner}/{repo}/contributors")
    Call<List<Contributor>> contributors(
            @Path("owner") String owner,
            @Path("repo") String repo);
}

在實際調用的時候,傳入正確的參數便可

Call<List<Contributor>> call = github.contributors("square", "retrofit");

這裏給出完整的動態設置Url的同步調用Get方法源碼;

/**
 * 同步方法
 */
private void btn_synchronous_dynamically_getMethod() {
    try {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    // Create a very simple REST adapter which points the GitHub API.
                    Retrofit retrofit = new Retrofit.Builder()
                            // 設置基本url,通常是協議+IP地址+端口
                            .baseUrl(API_URL)
                            // 設置數據解析的格式,需要引入gson庫
                            .addConverterFactory(GsonConverterFactory.create())
                            .build();

                    // Create an instance of our GitHub API interface.
                    GitHub github = retrofit.create(GitHub.class);

                    // Create a call instance for looking up Retrofit contributors.
                    Call<List<Contributor>> call = github.contributors("square", "retrofit");

                    // Fetch and print a list of the contributors to the library.
                    List<Contributor> contributors = call.execute().body();
                    final StringBuilder sb = new StringBuilder();
                    for (Contributor contributor : contributors) {
                        sb.append(contributor.getLogin() + " (" + contributor
                                .getContributions() + ")\n");
                    }
                    Log.i(TAG, "tht synchronous function run on thread id is " + Thread
                            .currentThread().getId());
                    Log.i(TAG, sb.toString());
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            mToast.setText(sb.toString());
                            mToast.show();
                        }
                    });

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

注:Android 4.0之後,不允許網絡請求在主線程中使用。

異步方法通過在Call的enqueue中添加結果回調來完成。如果需要獲取Http原始的Response對象,使用Response raw = response.raw();

/**
 * 異步方法
 */
private void btn_asynchronous_dynamically_getMethod() {
    // Create a very simple REST adapter which points the GitHub API.
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(API_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    // Create an instance of our GitHub API interface.
    GitHub github = retrofit.create(GitHub.class);

    // Create a call instance for looking up Retrofit contributors.
    Call<List<Contributor>> call = github.contributors("square", "retrofit");

    // Fetch and print a list of the contributors to the library.
    call.enqueue(new Callback<List<Contributor>>() {
        @Override
        public void onResponse(Call<List<Contributor>> call, Response<List<Contributor>>
                response) {
            try {
                // get raw response
                // Response raw = response.raw();
                Log.i(TAG, "tht callback function run on thread id is " + Thread
                        .currentThread().getId());
                StringBuilder sb = new StringBuilder();
                List<Contributor> contributors = response.body();
                for (Contributor contributor : contributors) {
                    sb.append(contributor.getLogin() + " (" + contributor
                            .getContributions() + ")\n");
                }
                mToast.setText(sb.toString());
                mToast.show();
                Log.i(TAG, sb.toString());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onFailure(Call<List<Contributor>> call, Throwable t) {

        }
    });
}

4、retrofit 查詢參數

4.1、一個參數查詢

如果只有一個查詢參數的Get/Post請求,可以使用Query註解;
比如針對鏈接(http://api.k780.com:88/?app=weather.future)請求,需要設置java請求接口爲:

    @POST("/")
    Call<WeatherList> getWeatherForAQuery(@Query("app") String queryParams);

注:參數查詢不能使用@POST(“/app={param}”),然後通過@Path註解動態傳遞數值。

4.2、多個參數查詢

如果查詢參數有多個,需要使用QueryMap註解,參數通過Map<String,String>對象傳遞。當然,也可以只使用Query註解,不過需要添加多個Query註解纔行;

public interface YourInterface {
    @GET("your-url")
    Call<responsebody> postcode(@Query("op") String op, @Query("postcode") String postcode);
}

下面演示對天氣Url(http://api.k780.com:88/?app=weather.future&weaid=1&&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json)數據請求;

定義請求天氣的Java接口,如果是用Get請求,需要將@POST改成@GET,需要用到的WeatherList對象,可以再文章的最後下載demo;

public interface WeatherApi {
    @POST("/")
    Call<WeatherList> getWeatherForQueryMap(@QueryMap Map<String,String> options);
}

注:註解括號內容不能爲空,即使baseUrl寫成http://api.k780.com:88/,註解也不能爲 @POST(“”),否則運行出錯。

最終調用方法;

private void btn_asynchronous_queryParamete_getMethod() {
    try {
        Retrofit retrofit = new Retrofit.Builder().baseUrl("http://api.k780.com:88/")
                .addConverterFactory(GsonConverterFactory.create()).build();

        Map<String, String> options = new HashMap<String, String>();
        options.put("app", "weather.future");
        options.put("weaid", "1");
        options.put("appkey", "10003");
        options.put("sign", "b59bc3ef6191eb9f747dd4e83c99f2a4");
        options.put("format", "json");
        Call<WeatherList> result = retrofit.create(WeatherApi.class).getWeather2(options);
        result.enqueue(new Callback<WeatherList>() {
            @Override
            public void onResponse(Call<WeatherList> call, Response<WeatherList> response) {
                Log.i("MainActivity", new Gson().toJson(response.body()));
            }

            @Override
            public void onFailure(Call<WeatherList> call, Throwable t) {

            }
        });
    } catch (Exception e) {
        e.printStackTrace();
    }
}
4.3、同名的多個查詢參數

有些情況下通過同名的多個參數請求,比如https://api.example.com/tasks?id=123&id=124&id=125 ,由於參數數據類型是一樣的,可以通過List<>組合多個參數;

public interface TaskService {  
    @GET("/tasks")
    Call<List<Task>> getTask(@Query("id") List<Long> taskIds);
}

5、發送json參數

當請求參數是個JSON字符串,可以使用@Body註解一個對象,Retrofit可以將一個對象轉化爲JSON字符串;

定義一個對象;

public class Task {  
    private long id;
    private String text;

    public Task(long id, String text) {
        this.id = id;
        this.text = text;
    }
}

聲明請求數據接口;

public interface TaskService {  
    @POST("/tasks")
    Call<Task> createTask(@Body Task task);
}

調用方法;

Task task = new Task(1, "my task title");  
Call<Task> call = taskService.createTask(task);  
call.enqueue(new Callback<Task>() {}); 

調用createTask方法,把task對象的屬性轉化爲JSON形式,對應的task參數實際爲

{
    "id": 1,
    "text": "my task title"
}

5、文件上傳

retrofit的文件上傳,需要使用@Multipart註解;

文件上傳接口定義;

public interface FileUploadService {
    public static final String BASE_URL = "http://your.api/endpoint/base-url";

    @Multipart
    @POST("/upload")
    void upload(@Part("myfile") TypedFile file,
                @Part("description") String description,
                Callback<String> cb);
}

定義call對象模板;

public class ServiceGenerator {

    public static final String API_BASE_URL = "http://your.api-base.url";

    private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();

    private static Retrofit.Builder builder =
            new Retrofit.Builder()
                    .baseUrl(API_BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create());

    public static <S> S createService(Class<S> serviceClass) {
        Retrofit retrofit = builder.client(httpClient.build()).build();
        return retrofit.create(serviceClass);
    }
}

實際調用;

FileUploadService service = ServiceGenerator.createService(FileUploadService.class, FileUploadService.BASE_URL);
TypedFile typedFile = new TypedFile("multipart/form-data", new File("path/to/your/file"));
String description = "hello, this is description speaking";

service.upload(typedFile, description, new Callback<String>() {
    @Override
    public void success(String s, Response response) {
        Log.e("Upload", "success");
    }

    @Override
    public void failure(RetrofitError error) {
        Log.e("Upload", "error");
    }
});

TypedFileRetrofit中定義,提供Filemime type兩個參數,這裏使用的mime type值爲multipart/form-data

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章