Retrofit的简单实用(get post 下载文件)
程序员文章站
2022-07-12 18:52:53
...
最近工作用到 Retrofit,以前的知识有些忘记了,又去网上查,觉得挺麻烦的,就自己写篇博客记录一下,方便自己以后查看。这里主要写Retrofit的使用。
Retrofit的使用步骤。 1.添加Retrofit库的依赖和网络权限: compile 'com.squareup.retrofit2:retrofit:2.2.0'// Retrofit库 compile 'com.squareup.retrofit2:converter-gson:2.3.0' <uses-permission android:name="android.permission.INTERNET" /> 2.创建 用于描述网络请求 的接口 Retrofit将 Http请求 抽象成 Java接口:采用 注解 描述网络请求参数 和配置网络请求参数 3.创建Retrofit实例(这里可以设置回调代码运行的线程,默认回调代码运行在主线程,可以自己设置运行在主线程或者子线程。) 4.将服务器返回的数据封装成一个bean类,用于接收服务器返回的数据。 5.发送请求 请求分为同步请求和异步请求
主要就分为这几部,下面来具体介绍:
1.添加Retrofit库的依赖和网络权限(只需要网络权限,本文中用到了本地存储下载的文件,所以加的存储读写权限):
compile 'com.squareup.retrofit2:retrofit:2.2.0'// Retrofit库
compile 'com.squareup.retrofit2:converter-gson:2.3.0'//返回的数据是json的,用到了gson解析
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
2.创建 用于描述网络请求 的接口,Retrofit将 Http请求 抽象成 Java接口:采用 注解 描述网络请求参数 和配置网络请求参数
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Query;
import retrofit2.http.Streaming;
import retrofit2.http.Url;
/**
* 创建 用于描述网络请求 的接口
* Retrofit将 Http请求 抽象成 Java接口:采用 注解 描述网络请求参数 和配置网络请求参数
*/
public interface ApiService {
//测试 get
@GET("ajax.php?a=fy&f=auto&t=auto&w=hello")
Call<ResponseInfo> testGet();
//测试 post
@POST("ajax.php?a=fy&f=auto&t=auto")
Call<ResponseInfo> testPost(@Query("w") String w);
//测试 下载文件
@Streaming
@GET
Call<ResponseBody> testDownload(@Url String fileUrl);
}
3.创建Retrofit实例(这里可以设置回调代码运行的线程,默认回调代码运行在主线程,可以自己设置运行在主线程或者子线程。)
get 请求和 post请求 创建的 Retrofit实例(不指定回调运行的线程,默认运行在主线程)
// 创建Retrofit实例时需要通过Retrofit.Builder,并调用baseUrl方法设置URL。
//Retrofit2的baseUlr 必须以 /(斜线)结束,不然会抛出一个IllegalArgumentException
retrofit = new Retrofit.Builder()
.baseUrl("http://fy.iciba.com/") // 设置 网络请求 Url
.addConverterFactory(GsonConverterFactory.create()) //设置使用Gson解析(记得加入依赖)
.build();
文件下载 的 Retrofit 实例 (指定回调运行的线程,指定运行在子线程中,因为受到文件之后要做io流的操作)
Retrofit retrofitLoaddown = new Retrofit.Builder()
.baseUrl("http://imtt.dd.qq.com/")
//通过线程池获取一个线程,指定callback在子线程中运行。
.callbackExecutor(Executors.newSingleThreadExecutor())
.build();
4.将服务器返回的数据封装成一个bean类,用于接收服务器返回的数据。
/**
* 讲服务器返回的数据封装成一个bean类
*/
public class ResponseInfo {
public Content content;
public int status;
public ResponseInfo() {
}
public ResponseInfo(Content content, int status) {
this.content = content;
this.status = status;
}
@Override
public String toString() {
return "ResponseInfo{" +
"content=" + content +
", status=" + status +
'}';
}
class Content {
public String ph_am;
public String ph_am_mp3;
public String ph_en_mp3;
public String ph_tts_mp3;
public List<String> word_mean;
public Content() {
}
public Content(String ph_am, String ph_am_mp3, String ph_en_mp3, String ph_tts_mp3, List<String> word_mean) {
this.ph_am = ph_am;
this.ph_am_mp3 = ph_am_mp3;
this.ph_en_mp3 = ph_en_mp3;
this.ph_tts_mp3 = ph_tts_mp3;
this.word_mean = word_mean;
}
@Override
public String toString() {
return "Content{" +
"ph_am='" + ph_am + '\'' +
", ph_am_mp3='" + ph_am_mp3 + '\'' +
", ph_en_mp3='" + ph_en_mp3 + '\'' +
", ph_tts_mp3='" + ph_tts_mp3 + '\'' +
", word_mean=" + word_mean +
'}';
}
}
}
5.发送请求 。请求分为同步请求和异步请求
同步请求的代码
ApiService request = retrofit.create(ApiService.class);
Call<ResponseInfo> call = request.testGet();// 封装请求
try {
Response<ResponseInfo> execute = call.execute();
} catch (IOException e) {
e.printStackTrace();
}
同步请求比较简单,我这里主要讲异步请求。
下面分别是get请求post请求和下载文件的代码
public void testGet() {
ApiService request = retrofit.create(ApiService.class);
Call<ResponseInfo> call = request.testGet();// 封装请求
try {
Response<ResponseInfo> execute = call.execute();
} catch (IOException e) {
e.printStackTrace();
}
call.enqueue(new Callback<ResponseInfo>() {// 发送网络请求(异步)
@Override
public void onResponse(Call<ResponseInfo> call, Response<ResponseInfo> response) {//主线程中调用
ResponseInfo body = response.body();
Log.i("gao", "测试 get body = " + body + " 线程名字 = " + Thread.currentThread().getName());
Toast.makeText(MainActivity.this, "测试GET= " + body.content.word_mean.get(0), Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(Call<ResponseInfo> call, Throwable t) {//主线程中调用
Log.i("gao", " testGet onFailure " + " 线程名字 = " + Thread.currentThread().getName());
Toast.makeText(MainActivity.this, " testGet onFailure ", Toast.LENGTH_SHORT).show();
}
});
}
public void testPost(String string) {
ApiService request = retrofit.create(ApiService.class);
Call<ResponseInfo> call = request.testPost(string);// 封装请求
call.enqueue(new Callback<ResponseInfo>() {// 发送网络请求(异步)
@Override
public void onResponse(Call<ResponseInfo> call, Response<ResponseInfo> response) {
ResponseInfo body = response.body();
Log.i("gao", "测试 post body = " + body + " 线程名字 = " + Thread.currentThread().getName());
Toast.makeText(MainActivity.this, "测试 post body = " + body, Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(Call<ResponseInfo> call, Throwable t) {
Log.i("gao", "testPost onFailure " + " 线程名字 = " + Thread.currentThread().getName());
Toast.makeText(MainActivity.this, "testPost onFailure ", Toast.LENGTH_SHORT).show();
}
});
}
public void testLoaddown(final String path, String url) {
Retrofit retrofitLoaddown = new Retrofit.Builder()
.baseUrl("http://imtt.dd.qq.com/")
//通过线程池获取一个线程,指定callback在子线程中运行。
.callbackExecutor(Executors.newSingleThreadExecutor())
.build();
ApiService request = retrofitLoaddown.create(ApiService.class);
Call<ResponseBody> call = request.testDownload(url);//当你填进去的url是完整url的时候,设置的baseurl是无效的
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(@NonNull Call<ResponseBody> call, @NonNull final Response<ResponseBody> response) {
Log.i("gao", "测试 线程名字 = " + Thread.currentThread().getName());
//将Response写入到从磁盘中,详见下面分析 注意,这个方法是运行在子线程中的
writeResponseToDisk(path, response);
}
@Override
public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable throwable) {
Log.i("gao", "testLoaddown 网络错误~ " + " 线程名字 = " + Thread.currentThread().getName());
Toast.makeText(MainActivity.this, "testLoaddown 网络错误~ ", Toast.LENGTH_SHORT).show();
}
});
}
好了,主要就是这几部,下面在发一下代码中的MainActivity的代码。
import android.app.Activity;
import android.os.Environment;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.Executors;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
/**
* Retrofit的使用步骤。
* 1.添加Retrofit库的依赖和网络权限:
* compile 'com.squareup.retrofit2:retrofit:2.2.0'// Retrofit库
* compile 'com.squareup.retrofit2:converter-gson:2.3.0'
* <uses-permission android:name="android.permission.INTERNET" />
*
* 2.创建 用于描述网络请求 的接口
* Retrofit将 Http请求 抽象成 Java接口:采用 注解 描述网络请求参数 和配置网络请求参数
*
* 3.创建Retrofit实例(回调默认的线程是主线程,可以自己设置运行在主线程或者子线程。)
*
* 4.将服务器返回的数据封装成一个bean类,用于接收服务器返回的数据。
*
* 5.发送请求
* 请求分为同步请求和异步请求
*
*
*/
public class MainActivity extends Activity implements View.OnClickListener {
Retrofit retrofit;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.testGet).setOnClickListener(this);
findViewById(R.id.testPost).setOnClickListener(this);
findViewById(R.id.testLoaddown).setOnClickListener(this);
// 创建Retrofit实例时需要通过Retrofit.Builder,并调用baseUrl方法设置URL。Retrofit2的baseUlr 必须以 /(斜线)结束,不然会抛出一个IllegalArgumentException
retrofit = new Retrofit.Builder()
.baseUrl("http://fy.iciba.com/") // 设置 网络请求 Url
.addConverterFactory(GsonConverterFactory.create()) //设置使用Gson解析(记得加入依赖)
.build();
//动态获取权限
AppPermission.isGrantExternalRW(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.testGet:
testGet();
break;
case R.id.testPost:
testPost("hello");
break;
case R.id.testLoaddown:
if (AppPermission.isGrantExternalRW(this)) {
String url = "http://imtt.dd.qq.com/16891/89E1C87A75EB3E1221F2CDE47A60824A.apk?fsname=com.snda.wifilocating_4.2.62_3192.apk&csr=1bbd";
testLoaddown(Environment.getExternalStorageDirectory() + "/ceshi.apk", url);
}
break;
}
}
public void testGet() {
ApiService request = retrofit.create(ApiService.class);
Call<ResponseInfo> call = request.testGet();// 封装请求
try {
Response<ResponseInfo> execute = call.execute();
} catch (IOException e) {
e.printStackTrace();
}
call.enqueue(new Callback<ResponseInfo>() {// 发送网络请求(异步)
@Override
public void onResponse(Call<ResponseInfo> call, Response<ResponseInfo> response) {//主线程中调用
ResponseInfo body = response.body();
Log.i("gao", "测试 get body = " + body + " 线程名字 = " + Thread.currentThread().getName());
Toast.makeText(MainActivity.this, "测试GET= " + body.content.word_mean.get(0), Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(Call<ResponseInfo> call, Throwable t) {//主线程中调用
Log.i("gao", " testGet onFailure " + " 线程名字 = " + Thread.currentThread().getName());
Toast.makeText(MainActivity.this, " testGet onFailure ", Toast.LENGTH_SHORT).show();
}
});
}
public void testPost(String string) {
ApiService request = retrofit.create(ApiService.class);
Call<ResponseInfo> call = request.testPost(string);// 封装请求
call.enqueue(new Callback<ResponseInfo>() {// 发送网络请求(异步)
@Override
public void onResponse(Call<ResponseInfo> call, Response<ResponseInfo> response) {
ResponseInfo body = response.body();
Log.i("gao", "测试 post body = " + body + " 线程名字 = " + Thread.currentThread().getName());
Toast.makeText(MainActivity.this, "测试 post body = " + body, Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(Call<ResponseInfo> call, Throwable t) {
Log.i("gao", "testPost onFailure " + " 线程名字 = " + Thread.currentThread().getName());
Toast.makeText(MainActivity.this, "testPost onFailure ", Toast.LENGTH_SHORT).show();
}
});
}
public void testLoaddown(final String path, String url) {
Retrofit retrofitLoaddown = new Retrofit.Builder()
.baseUrl("http://imtt.dd.qq.com/")
//通过线程池获取一个线程,指定callback在子线程中运行。
.callbackExecutor(Executors.newSingleThreadExecutor())
.build();
ApiService request = retrofitLoaddown.create(ApiService.class);
Call<ResponseBody> call = request.testDownload(url);//当你填进去的url是完整url的时候,设置的baseurl是无效的
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(@NonNull Call<ResponseBody> call, @NonNull final Response<ResponseBody> response) {
Log.i("gao", "测试 线程名字 = " + Thread.currentThread().getName());
//将Response写入到从磁盘中,详见下面分析 注意,这个方法是运行在子线程中的
writeResponseToDisk(path, response);
}
@Override
public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable throwable) {
Log.i("gao", "testLoaddown 网络错误~ " + " 线程名字 = " + Thread.currentThread().getName());
Toast.makeText(MainActivity.this, "testLoaddown 网络错误~ ", Toast.LENGTH_SHORT).show();
}
});
}
private void writeResponseToDisk(String path, Response<ResponseBody> response) {
//从response获取输入流以及总大小
writeFileFromIS(new File(path), response.body().byteStream(), response.body().contentLength());
}
private static int sBufferSize = 8192;
//将输入流写入文件
private void writeFileFromIS(File file, InputStream is, long totalLength) {
//创建文件
if (!file.exists()) {
if (!file.getParentFile().exists())
file.getParentFile().mkdir();
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
Log.i("gao", "创建文件错误~ " + " 线程名字 = " + Thread.currentThread().getName());
}
}
OutputStream os = null;
long currentLength = 0;
try {
os = new BufferedOutputStream(new FileOutputStream(file));
byte data[] = new byte[sBufferSize];
int len;
while ((len = is.read(data, 0, sBufferSize)) != -1) {
os.write(data, 0, len);
currentLength += len;
//计算当前下载进度
Log.i("gao", "下载 进度 = " + (int) (100 * currentLength / totalLength));
}
//下载完成,并返回保存的文件路径
Log.i("gao","下载完成 file.getAbsolutePath() = "+file.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
Log.i("gao","下载失败");
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (os != null) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
主要的内容就是这些,需要源代码的朋友可以下载 文中例子的 源码
下一篇我们将 Retrofit 和Rxjava的结合。
如果对 Rxjava 不懂的朋友可以看一下上篇博客: Rxjava的使用_1