Retrofit 基本使用教程

原文地址:

https://futurestud.io/blog/retrofit-getting-started-and-android-client#

部分内容,根据自己的理解添加或者修改

URL拼接

Retrofit 在初始化的时候,需要指定一个baseUrl:

 private static Retrofit.Builder mBuilder = new Retrofit.Builder()
            .baseUrl("http://192.168.0.102/")
            .addConverterFactory(GsonConverterFactory.create());

在我们定义请求的接口时,会传入具体的接口的地址(Endpoint):

 @GET("index.php?c=User&m=getUser")
    Call<List<User>> getUser();

Retrofit会帮我们完成拼接,最后的URL是:

http://192.168.0.102/index.php?c=User&m=getUser

需要注意的是baseUrl必须以”/”结尾

正确的写法:

Base URL: http://example.com/api/
Endpoint: foo/bar/
Result: http://example.com/api/foo/bar/

错误写法:

Base URL: http://example.com/api
Endpoint: foo/bar/
Result: http://example.com/foo/bar/

Endpoint可以为完整的URL:

  Base URL: http://example.com/
  Endpoint: https://github.com/square/retrofit/
  Result: https://github.com/square/retrofit/

当我们需要请求不同服务器上的API时,这就非常有用了。

另外,Retrofit还支持我们在调用时,传入URL:

@GET
Call<List<User>> getUser2(@Url String url);
Call<List<User>> call=userClient.getUser2("http://www.jiangxu.online/index.php?c=User&m=getUser");

Get查询参数

查询参数是一种很常见的客户端往服务端传递数据的方式,比如我们需要传一个id给服务端,那么URL可能是这样的:

https://api.example.com/tasks?id=123

Retrofit 定义实现查询参数:

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

方法getTask需要传入taskId,这个参数会被映射到@Query(“id”)中的id中,最后的URL会变成这样:

/tasks?id=<taskId>

有时我们需要对于一个id参数传入多个值,比如这样:

https://api.example.com/tasks?id=123&id=124&id=125  

对于这样的需求,Retrofit 通过传入一个List来实现:

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

这样,拼接后的URL就是我们需要的那样。

有时,我们在给服务端传递数据时,有些参数是可选的,比如下面的URL:

https://your.api.com/tasks?sort=value-of-order-parameter

sort参数是可选的,有些情况下可能不需要传入。

接口的定义:

public interface TaskService {  
    @GET("/tasks")
    Call<List<Task>> getTasks(@Query("sort") String order);
}

那么,在我们不想添加排序控制的时候,我们可以传入null,Retrofit 会忽略值为null的参数。

service.getTasks(null);  

需要注意的是,可忽略参数的参数类型不能是int, float, long这些基本类型,应该用Integer, Float, Long来代替。

Post 提交参数

Retrofit Post方式提交表单形式的参数需要添加标记@FormUrlEncoded,通过@Field注释添加键值对。
接口定义:

public interface UserClient {
    @FormUrlEncoded
    @POST("/index.php?c=User&m=login")
    Call<List<User>> login(@Field("phone") String phone, @Field("password") String password);
}

客户端调用:

 private void login() {
        UserClient userClient = ServiceGenerator.createService(UserClient.class);
        Call<List<User>> call = userClient.login("13695378745","123456");
        call.enqueue(new Callback<List<User>>() {

        });
    }

Post 提交JSON数据

有时提交的数据量比较大时,用键值对的方式提交参数不太方便,Retrofit可以通过@Body注释,直接传递一个对象给请求主体,Retrofit通过JSON转化器,把对象映射成JSON数据。

接口定义:

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

传递实体需要有Model:

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

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

客户端调用:

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

这样,服务端得到的是JOSN数据:

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

文件下载

接口定义:

 @Streaming
    @GET
    Call<ResponseBody> downloadFile(@Url String fileUrl);

在下载的时候,是在子线程中工作运行的,有时需要显示下载的进度,同时支持多个下载并发进行,这样需要封装一下,使用起来方便:

public class DownFileManager {

    private final static String TAG = "DownFileManager";
    private static DownFileManager sDownFileManager;
    private CallBack mCallBack;
    private final Handler mHandler = new Handler(Looper.getMainLooper());
    private ExecutorService executorService;

    public interface CallBack {

        void onSuccess(String path);

        void inProgress(int progress);

        void onFail();
    }

    public static DownFileManager getInstance() {
        if (sDownFileManager == null) {
            sDownFileManager = new DownFileManager();
        }
        return sDownFileManager;
    }

    public synchronized ExecutorService executorService() {
        if (executorService == null) {
            executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), Util.threadFactory("DownFileManager", false));
        }
        return executorService;
    }

    public void download(final String path, final String filePath, CallBack callBack) {
        mCallBack = callBack;
        executorService();
        executorService.submit(new Runnable() {
            boolean isSuccess;

            @Override
            public void run() {
                DownloadService service = ServiceGenerator.createService(DownloadService.class);
                Call<ResponseBody> call = service.downloadFile(path);
                try {
                    isSuccess = writeResponseBodyToDisk(filePath, call.execute().body());
                } catch (Exception e) {
                    e.printStackTrace();
                }
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        if (isSuccess) {
                            mCallBack.onSuccess(filePath);
                        } else {
                            mCallBack.onFail();
                        }
                    }
                });
            }
        });
    }

    private boolean writeResponseBodyToDisk(String path, ResponseBody body) {
        try {
            File futureStudioIconFile = new File(path);
            InputStream inputStream = null;
            OutputStream outputStream = null;
            try {
                byte[] fileReader = new byte[4096];

                long fileSize = body.contentLength();
                long fileSizeDownloaded = 0;

                inputStream = body.byteStream();
                outputStream = new FileOutputStream(futureStudioIconFile);
                int oldProgress = 0;
                while (true) {
                    int read = inputStream.read(fileReader);

                    if (read == -1) {
                        break;
                    }
                    outputStream.write(fileReader, 0, read);
                    fileSizeDownloaded += read;
                    final int progress = (int) ((fileSizeDownloaded * 1.0 / fileSize) * 100);
                    if (oldProgress != progress) {
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                mCallBack.inProgress(progress);
                            }
                        });
                    }
                    oldProgress = progress;
                }
                outputStream.flush();
                return true;
            } catch (IOException e) {
                return false;
            } finally {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (outputStream != null) {
                    outputStream.close();
                }
            }
        } catch (IOException e) {
            return false;
        }
    }

}

使用:

 DownFileManager.getInstance().download(downloadUrl, filePath, new DownFileManager.CallBack() {
            @Override
            public void onSuccess(String path) {
                //下载文件的路径
            }

            @Override
            public void inProgress(int progress) {
                //下载的进度
                Trace.i("DownFileManager","progress  ="+progress);
            }

            @Override
            public void onFail() {
            }
        });

文件上传

Retrofit 支持 Multipart 请求,所以我们可以用它来实现文件上传,对于要实现文件上传的接口,需要添加@Multipart注释。
接口定义:

public interface FileUploadService {
    @Multipart
    @POST("index.php?c=Upload&m=doUpload")
    Call<Msg> upload(
            @Part("file\"; filename=\"image.png\" ") RequestBody file,
            @Part("description") RequestBody description);
}

对于要上传的文件,我们需要把它包装成RequestBody 对象:

 private void uploadFile( File file) {
        FileUploadService service =
                ServiceGenerator.createService(FileUploadService.class);

        String descriptionString = "hello, this is description speaking";
        RequestBody description =
                RequestBody.create(MediaType.parse("multipart/form-data"), descriptionString);
        RequestBody requestBody =
                RequestBody.create(MediaType.parse("multipart/form-data"), file);

        Call<Msg> call = service.upload(requestBody, description);
        call.enqueue(new Callback<Msg>() {
            @Override
            public void onResponse(Call<Msg> call, Response<Msg> response) {
                Log.v("Upload", "success");
            }

            @Override
            public void onFailure(Call<Msg> call, Throwable t) {
                Log.e("Upload", t.getMessage());
            }
        });
    }

同步请求和异步请求

同步的请求会在同一个线程中执行,在Android中必须另开线程,否则在主线程中执行会抛出异常。
同步和异步请求的接口都是一样的,只是调用的时候会不一样:

public interface TaskService {  
    @GET("/tasks")
    Call<List<Task>> getTasks();
}

同步请求调用:

TaskService taskService = ServiceGenerator.createService(TaskService.class);  
Call<List<Task>> call = taskService.getTasks();  
List<Task>> tasks = call.execute().body(); 

异步请求调用:

TaskService taskService = ServiceGenerator.createService(TaskService.class);  
Call<List<Task>> call = taskService.getTasks();  
call.enqueue(new Callback<List<Task>>() {  
    @Override
    public void onResponse(Call<List<Task>> call, Response<List<Task>> response) {
        if (response.isSuccess()) {
            // tasks available
        } else {
            // error response, no access to resource?
        }
    }

    @Override
    public void onFailure(Call<List<Task>> call, Throwable t) {
        // something went completely south (like no internet connection)
        Log.d("Error", t.getMessage());
    }
}

异步请求实现了一个CallBack,包含了两个回调方法:onResponse和 onFailure,在onResponse中我们可以拿到我们需要的实体数据,在onFailure中,可以拿到错误的Log。

Demo地址:

http://download.csdn.net/detail/jiangxuqaz/9452369

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 15
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值