关于Retrofit网络请求方式和自己的一点理解

Retrofit简介:

Retrofit是Square公司开发的一款针对Android网络请求的框架,Retrofit2底层基于OkHttp实现的,Okhttp现在已经得到Google官方认可,大量的app都采用OkHttp做网络请求


1.要使用Retrofit首先得添加gradle依赖

compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'


2.新建一个Retrofit对象

mRetrofit = new Retrofit.Builder()
.baseUrl("http://192.168.0.102/")
.client(configClient())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();

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


3.新建一个Interface,需要请求的接口服务类

public interface Api {
@GET("index.php?c=User&m=getUser")
Call> getUser();
}

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

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

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

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

Endpoint可以为完整的URL:

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

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


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


Retrofit中一些参数注解:
@Path:所有在网址中的参数(URL的问号前面),如:
http://102.10.10.132/api/Accounts/{accountId}
@Query:URL问号后面的参数,如:
http://102.10.10.132/api/Comments?access_token={access_token}
@QueryMap:相当于多个@Query
@Field:用于POST请求,提交单个数据
@Body:相当于多个@Field,以对象的形式提交

@Path和@Query的区别;

example:www.app.net/api/searchtypes/862189/filters?Type=6&SearchText=School

@GET("/api/searchtypes/{Id}/filters")
void getFilterList(@Path("Id") long customerId,
@Query("Type") String responseType,
@Query("SearchText") String searchText,
Callback filterResponse);

url拼接:www.app.net/api/searchtypes/{Path}/filters?Type={Query}&SearchText={Query}

 

Get查询参数

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

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

Retrofit 定义实现查询参数:

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

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

/tasks?id=

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

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

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

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

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

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

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

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

接口的定义:

public interface TaskService {  
    @GET("/tasks")
    Call> 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> login(@Field("phone") String phone, @Field("password") String password);
}

客户端调用:

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

        });
    }

Post 提交JSON数据

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

接口定义:

public interface TaskService {  
    @POST("/tasks")
    Call 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 call = taskService.createTask(task);  
call.enqueue(new Callback() {}); 

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

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

文件下载

接口定义:

 @Streaming
    @GET
    Call 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(), 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 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 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 call = service.upload(requestBody, description);
        call.enqueue(new Callback() {
            @Override
            public void onResponse(Call call, Response response) {
                Log.v("Upload", "success");
            }

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

同步请求和异步请求

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

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

同步请求调用:

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

异步请求调用:

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

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

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

原文地址:http://blog.csdn.net/jiangxuqaz/article/details/50759239

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

Demo地址:

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

你可能感兴趣的:(关于Retrofit网络请求方式和自己的一点理解)