网络编程
安卓网路编程-http协议
https://www.sunofbeach.net/a/1197731399965200384
网络配置
https://developer.android.google.cn/training/articles/security-config?hl=zh-cn#manifest
一.URL使用Http的方式
示例:
package com.atian;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void loadJson(View view){
new Thread(new Runnable() {
@Override
public void run() {
try {
URL url = new URL("http://10.0.2.2:9102/get/text");
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
//设置请求头的参数
connection.setConnectTimeout(10000);
connection.setRequestMethod("GET");
connection.setRequestProperty("Accept-Language","zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6");
connection.setRequestProperty("Accept","*/*");
connection.connect();
int responseCode = connection.getResponseCode();
if(responseCode == 200){
Log.d(TAG, "loadJson: 请求成功!!");
//获取到响应头的参数
Map<String, List<String>> headerFields = connection.getHeaderFields();
Set<Map.Entry<String, List<String>>> entries = headerFields.entrySet();
for (Map.Entry<String,List<String>> entry : entries) {
Log.d(TAG, entry.getKey()+"==="+entry.getValue());
}
//读取到返回的信息
InputStream inputStream = connection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s = bufferedReader.readLine();
Log.d(TAG, "读出的信息为: "+s);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
1.Gson的使用
//读取到返回的信息
InputStream inputStream = connection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s = bufferedReader.readLine();
Log.d(TAG, "读出的信息为: "+s);
Gson gson = new Gson();
GetTextItem getTextItem = gson.fromJson(s, GetTextItem.class);
Log.d(TAG, "getTextItem: "+getTextItem.toString());
2.异步更新ui(runOnUiThread)
private void initView() {
result_list = (RecyclerView)this.findViewById(R.id.result_list);
result_list.setLayoutManager(new LinearLayoutManager(this));
this.resultAdapter = new ResultAdapter();
result_list.setAdapter(this.resultAdapter);
}
------------------------------------------------------------------------
private void updateUI(GetTextItem getTextItem) {
runOnUiThread(new Runnable() {
@Override
public void run() {
resultAdapter.setData(getTextItem);
}
});
}
-----------------------------------------------------------------------
public void setData(GetTextItem getTextItem) {
mData.clear();
mData.addAll(getTextItem.getData());
//更新ui界面
notifyDataSetChanged();
}
二.Glide(图像加载框架)
Glide是一个快速高效的开源媒体管理和图像加载框架,适用于Android,可以包装媒体 解码、内存和磁盘缓存以及资源池化到一个简单易用的界面中。
Glide 支持获取、解码和显示视频静止图像、图像和动画 GIF。Glide包含一个灵活的API 这允许开发人员插入几乎任何网络堆栈。默认情况下,Glide 使用基于自定义的 堆栈,但也包括插入Google的Volley项目或Square的OkHttp库的实用程序库。HttpUrlConnection
Glide的主要重点是使滚动任何类型的图像列表尽可能流畅和快速,但Glide是 对于需要获取、调整大小和显示远程图像的几乎任何情况也有效。
Download
Gradle:
repositories {
google()
mavenCentral()
}
dependencies {
implementation 'com.github.bumptech.glide:glide:4.14.2'
annotationProcessor 'com.github.bumptech.glide:compiler:4.14.2'
}
Maven:
<dependency>
<groupId>com.github.bumptech.glide</groupId>
<artifactId>glide</artifactId>
<version>4.14.2</version>
</dependency>
<dependency>
<groupId>com.github.bumptech.glide</groupId>
<artifactId>compiler</artifactId>
<version>4.14.2</version>
<optional>true</optional>
</dependency>
1.Glide的使用
//找到控件
ImageView image_view = (ImageView)itemView.findViewById(R.id.image_view);
Glide.with(image_view.getContext()).load("http://10.0.2.2:9102"+mData.get(position).getCover()).into(image_view);
mData.get(position).getCover()返回的是 /imgs/12.png
2.处理大图片的操作(计算采样率)
package com.atian;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
public class ImagesActivity extends AppCompatActivity {
private static final String TAG = "ImagesActivity";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.activity_images);
}
public void loadPic(View view){
//创建一個options
BitmapFactory.Options options = new BitmapFactory.Options();
//设置这個不存进内存
options.inJustDecodeBounds = true;
//拿到图片的大小
BitmapFactory.decodeResource(getResources(),R.mipmap.b13fae0d47bf1c9214b7d1aa5bb80f82,options);
// int outHeight = options.outHeight;
// int outWidth = options.outWidth;
// Log.d(TAG, "outHeight: "+outHeight);
// Log.d(TAG, "outWidth: "+outWidth);
//拿到控件尺寸
ImageView image_pic = this.findViewById(R.id.image_pic);
int measuredHeight = image_pic.getMeasuredHeight();
int measuredWidth = image_pic.getMeasuredWidth();
Log.d(TAG, "measuredHeight: "+measuredHeight);
Log.d(TAG, "measuredWidth: "+measuredWidth);
//计算采样率
options.inSampleSize = calculateInSampleSize(options,measuredWidth,measuredHeight);
//第二次读取,就需要写进内存了。
options.inJustDecodeBounds = false;
Log.d(TAG, "options.inSampleSize: "+options.inSampleSize);
//获取到计算采样率后的图片资源
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.b13fae0d47bf1c9214b7d1aa5bb80f82, options);
image_pic.setImageBitmap(bitmap);
}
public static int calculateInSampleSize(BitmapFactory.Options options, int maxWidth, int maxHeight) {
//这里其实是获取到默认的高度和宽度,也就是图片的实际高度和宽度
final int height = options.outHeight;
final int width = options.outWidth;
//默认采样率为1,也就是不变嘛。
int inSampleSize = 1;
//===============核心算法啦====================
if (width > maxWidth || height > maxHeight) {
if (width > height) {
inSampleSize = Math.round((float) height / (float) maxHeight);
} else {
inSampleSize = Math.round((float) width / (float) maxWidth);
}
final float totalPixels = width * height;
final float maxTotalPixels = maxWidth * maxHeight * 2;
while (totalPixels / (inSampleSize * inSampleSize) > maxTotalPixels) {
inSampleSize++;
}
}
//=============核心算法end================
return inSampleSize;
}
}
三.基本操作
1.post提交文本内容
package com.atian;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.atian.domain.CommentItem;
import com.google.gson.Gson;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
public class PostActivity extends AppCompatActivity {
private static final String TAG = "PostActivity";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_post);
}
public void post_message(View view){
new Thread(new Runnable() {
@Override
public void run() {
OutputStream outputStream = null;
InputStream inputStream = null;
try {
URL url = new URL("http://10.0.2.2:9102/post/comment");
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("POST");
connection.setConnectTimeout(10000);
connection.setRequestProperty("Content-Type","application/json");
connection.setRequestProperty("Accept-Language","zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6");
connection.setRequestProperty("Accept","*/*");
CommentItem commentItem = new CommentItem("1234", "您已经评论了!!");
Gson gson = new Gson();
String s = gson.toJson(commentItem);
byte[] bytes = s.getBytes(StandardCharsets.UTF_8);
//获取传输的长度
String len = String.valueOf(bytes.length);
//设置请求头中带内容长度
connection.setRequestProperty("Content-Length",len);
//连接
connection.connect();
//把数据给到服务
outputStream = connection.getOutputStream();
//写出数据
outputStream.write(bytes);
//刷出缓存
outputStream.flush();
//拿结果
int responseCode = connection.getResponseCode();
Log.d(TAG, "返回的状态码为: "+responseCode);
if(responseCode == 200){
inputStream = connection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String out_text = bufferedReader.readLine();
Log.d(TAG, "接收到的数据是: "+out_text);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
//关闭资源流
if(outputStream != null){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(inputStream != null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}).start();
}
}
2.url带参数的请求
public void get_message(View view){
//组装数据
HashMap<String, String> params = new HashMap<>();
params.put("keyword","这是我的关键字!!");
params.put("page","12");
params.put("order","0");
startRequest(params,"GET","/get/param");
}
private void startRequest(HashMap<String, String> params, String method, String api) {
new Thread(new Runnable() {
@Override
public void run() {
try {
//组装参数
StringBuilder sb = new StringBuilder();
if(params != null && params.size() > 0){
sb.append("?");
Iterator<Map.Entry<String, String>> iterator = params.entrySet().iterator();
while (iterator.hasNext()){
Map.Entry<String, String> next = iterator.next();
sb.append(next.getKey());
sb.append("=");
sb.append(next.getValue());
if(iterator.hasNext()){
sb.append("&");
}
}
Log.d(TAG, "sb-->: "+sb.toString());
}
String params = sb.toString();
URL url = null;
if(params!=null&& params.length()>0){
url = new URL(BASE_URL+api+params);
}else{
url = new URL(BASE_URL+api);
}
Log.d(TAG, "URL-->: "+url.toString());
//新建连接
HttpURLConnection connection = null;
connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod(method);
connection.setConnectTimeout(10000);
connection.setRequestProperty("Content-Type","application/json");
connection.setRequestProperty("Accept-Language","zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6");
connection.setRequestProperty("Accept","*/*");
connection.connect();
Log.d(TAG, "connection.getResponseCode(): "+connection.getResponseCode());
if(connection.getResponseCode() == 200){
InputStream inputStream = connection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s = bufferedReader.readLine();
Log.d(TAG, "输出的结果为:————>: "+s);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
3.单文件上传
换行:sb.append(“\r\n”)
https://www.bilibili.com/video/BV1ua4y1J7VV?p=11&vd_source=c6adc8d97c23aa879ed362864838ee07
4.多文件上传
https://www.bilibili.com/video/BV1ua4y1J7VV?p=12&vd_source=c6adc8d97c23aa879ed362864838ee07
5.文件下载
https://www.bilibili.com/video/BV1ua4y1J7VV?p=13&spm_id_from=pageDriver&vd_source=c6adc8d97c23aa879ed362864838ee07
文件下载的大概流程:
FileOutputStream fileOutputStream = null;
InputStream inputStreams = null;
try {
//从传来的源获取到图片名称
String filename = new String("001.jpg");
//获取存放图片的文件地址(重要)
File externalFilesDir = PostActivity.this.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
//路径不存在则,创建路径。
if(!externalFilesDir.exists()){
externalFilesDir.mkdirs();
}
//File.separator相当于”\“
File new_file = new File(externalFilesDir + File.separator + filename);
//文件不存在,则创建文件。
if(!new_file.exists()){
new_file.createNewFile();
}
//获取文件输出流
fileOutputStream = new FileOutputStream(new_file);
//获取连接输入流
inputStreams = connection.getInputStream();
//定义缓存数组
byte[] buffer = new byte[1024];
int len;
//读写操作
while ((len = inputStreams.read(buffer,0,buffer.length))!=-1){
fileOutputStream.write(buffer,0,len);
}
//刷新缓存区
fileOutputStream.flush();
} catch (Exception e) {
e.printStackTrace();
}finally {
if(fileOutputStream!=null){
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(inputStreams!=null){
try {
inputStreams.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
四.OKHTTP框架
https://github.com/square/okhttp
https://www.sunofbeach.net/a/1196018104614813696
1.添加依赖
implementation("com.squareup.okhttp3:okhttp:4.10.0")
2.基本示例代码
package com.atian;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.util.Log;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.util.concurrent.TimeUnit;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
public class okHttpActivity extends AppCompatActivity {
public static final String BASE_URL = "http://10.0.2.2:9102";
private static final String TAG = "okHttpActivity";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.activity_okhttp);
}
public void get_message01(View view){
//要有客户端,就类似于浏览器
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(10000, TimeUnit.MILLISECONDS)
.build();
//创建请求内容
final Request request = new Request.Builder()
.get()
.url(BASE_URL + "/get/text")
.build();
//用client去创建请求任务
Call task = okHttpClient.newCall(request);
//异步请求
task.enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
Log.d(TAG, "onFailure: "+e.toString());
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
int code = response.code();
if(code == HttpURLConnection.HTTP_OK){
ResponseBody body = response.body();
Log.d(TAG, "body: "+body.string());
}
}
});
}
}
3.post方式提交字符串
public void post_message01(View view){
//1.要有客户端,就类似于浏览器
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(10000, TimeUnit.MILLISECONDS)
.build();
//2.创建post提交的内容
CommentItem commentItem = new CommentItem("1234", "您已经评论了!!");
Gson gson = new Gson();
String s = gson.toJson(commentItem);
MediaType parse = MediaType.parse("application/json");
RequestBody requestBody = RequestBody.create(s, parse);
//3.创建请求内容
final Request request = new Request.Builder()
.post(requestBody)
.url(BASE_URL + "/post/comment")
.build();
//4.客户端创建任务
Call call = okHttpClient.newCall(request);
//5.客户端异步执行任务
call.enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
//如果出错,打印出错误信息!
Log.d(TAG, "onFailure: "+e.toString());
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
int code = response.code();
if(code == HttpURLConnection.HTTP_OK){
ResponseBody body = response.body();
Log.d(TAG, "body: "+body.string());
}
}
});
}
4.上传单个文件
1.引入相关的权限
静态声明权限
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
动态获取权限
private void checkPermission() {
//先判断有没有权限
int i = checkSelfPermission("android.permission.READ_EXTERNAL_STORAGE");
if(i != PackageManager.PERMISSION_GRANTED){
//没有权限
// 申请权限
// 定义需要申请的权限数组
String[] permission = new String[] {
Manifest.permission.READ_EXTERNAL_STORAGE
};
// 定义这次申请权限的唯一请求编码
int requestCode = 2023;
// 申请权限
requestPermissions(permission, requestCode);
}
}
/**
* 申请权限的回调方法
* @param requestCode 申请权限时的请求码
* @param permissions 所有权限的数组
* @param grantResults 返回获取权限的状态码数组(-1:获取失败----0:获取成功)
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(requestCode == 2023){
Log.d(TAG, "grantResults: "+grantResults[0]);
Log.d(TAG, "grantResults: "+grantResults.length);
if(grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
//有权限
Toast.makeText(this, "已经获得所有权限!", Toast.LENGTH_SHORT).show();
}else {
//没有权限
//根据交互数据
Toast.makeText(this, "没有获得权限!,程序将退出!", Toast.LENGTH_SHORT).show();
}
}
}
2.编写代码
public void post_fileOne(View view){
//新建客户端
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(10000,TimeUnit.MILLISECONDS)
.build();
//新建要传输的文件,指定文件路径
File file = new File("/storage/emulated/0/Download/3abc27abc474cdd4ebd7b2f3e83d05ef.jpeg");
//定义解析文件类型
MediaType parse = MediaType.parse("image/png");
RequestBody fileBody = RequestBody.create(file, parse);
//新建请求发送文件的body
RequestBody requestBody = new MultipartBody.Builder()
.addFormDataPart("file",file.getName(),fileBody)
.build();
//新建请求
Request request = new Request.Builder()
.url(BASE_URL+"/file/upload")
.post(requestBody)
.build();
//新建任务
Call call = okHttpClient.newCall(request);
//异步执行任务
call.enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
//打印错误信息!
Log.d(TAG, "onFailure: "+e.toString());
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
if(response.code() == HttpURLConnection.HTTP_OK){
ResponseBody body = response.body();
//打印返回的值
Log.d(TAG, "body: "+body.string());
// todo 需要动态申请权限
}
}
});
}
5.上传多个文件
public void post_files(View view){
//新建客户端
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(10000,TimeUnit.MILLISECONDS)
.build();
//新建要传输的文件,指定文件路径
File fileOne = new File("/storage/emulated/0/Download/3abc27abc474cdd4ebd7b2f3e83d05ef.jpeg");
File fileTwo = new File("/storage/emulated/0/Download/75d1968dd23c9c74c2c702b5a5dbf874.jpeg");
File fileThree = new File("/storage/emulated/0/Download/b9040d67938b047f0493e3c8c0f22ab6.jpeg");
File fileFour = new File("/storage/emulated/0/Download/f67b5abd3aed142c74f070a60d320c7f.jpeg");
//定义解析文件类型
MediaType parse = MediaType.parse("image/png");
RequestBody fileBodyOne = RequestBody.create(fileOne, parse);
RequestBody fileBodyTwo = RequestBody.create(fileTwo, parse);
RequestBody fileBodyThree = RequestBody.create(fileThree, parse);
RequestBody fileBodyFour = RequestBody.create(fileFour, parse);
//新建请求发送文件的body
RequestBody requestBody = new MultipartBody.Builder()
.addFormDataPart("files",fileOne.getName(),fileBodyOne)
.addFormDataPart("files",fileTwo.getName(),fileBodyTwo)
.addFormDataPart("files",fileThree.getName(),fileBodyThree)
.addFormDataPart("files",fileFour.getName(),fileBodyFour)
.build();
//新建请求
Request request = new Request.Builder()
.url(BASE_URL + "/files/upload")
.post(requestBody)
.build();
//新建任务
Call call = okHttpClient.newCall(request);
//异步执行任务
call.enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
//打印错误信息!
Log.d(TAG, "onFailure: "+e.toString());
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
if(response.code() == HttpURLConnection.HTTP_OK){
ResponseBody body = response.body();
//打印返回的值
Log.d(TAG, "body: "+body.string());
// todo 需要动态申请权限
}
}
});
}
6.下载文件
public void post_files(View view){
//新建客户端
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(10000,TimeUnit.MILLISECONDS)
.build();
//新建要传输的文件,指定文件路径
File fileOne = new File("/storage/emulated/0/Download/3abc27abc474cdd4ebd7b2f3e83d05ef.jpeg");
File fileTwo = new File("/storage/emulated/0/Download/75d1968dd23c9c74c2c702b5a5dbf874.jpeg");
File fileThree = new File("/storage/emulated/0/Download/b9040d67938b047f0493e3c8c0f22ab6.jpeg");
File fileFour = new File("/storage/emulated/0/Download/f67b5abd3aed142c74f070a60d320c7f.jpeg");
//定义解析文件类型
MediaType parse = MediaType.parse("image/png");
RequestBody fileBodyOne = RequestBody.create(fileOne, parse);
RequestBody fileBodyTwo = RequestBody.create(fileTwo, parse);
RequestBody fileBodyThree = RequestBody.create(fileThree, parse);
RequestBody fileBodyFour = RequestBody.create(fileFour, parse);
//新建请求发送文件的body
RequestBody requestBody = new MultipartBody.Builder()
.addFormDataPart("files",fileOne.getName(),fileBodyOne)
.addFormDataPart("files",fileTwo.getName(),fileBodyTwo)
.addFormDataPart("files",fileThree.getName(),fileBodyThree)
.addFormDataPart("files",fileFour.getName(),fileBodyFour)
.build();
//新建请求
Request request = new Request.Builder()
.url(BASE_URL + "/files/upload")
.post(requestBody)
.build();
//新建任务
Call call = okHttpClient.newCall(request);
//异步执行任务
call.enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
//打印错误信息!
Log.d(TAG, "onFailure: "+e.toString());
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
if(response.code() == HttpURLConnection.HTTP_OK){
ResponseBody body = response.body();
//打印返回的值
Log.d(TAG, "body: "+body.string());
// todo 需要动态申请权限
}
}
});
}
public void downFile(View view){
//新建客户端
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(10000,TimeUnit.MILLISECONDS)
.build();
//新建请求
Request request = new Request.Builder()
.get()
.url(BASE_URL + "/download/2")
.build();
//创建任务
Call call = okHttpClient.newCall(request);
//异步执行任务
call.enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
Log.d(TAG, "onFailure: "+e.toString());
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
FileOutputStream fileOutputStream = null;
InputStream inputStreams = null;
int code = response.code();
try {
if (code == HttpURLConnection.HTTP_OK) {
Iterator<Pair<String, String>> iterator = response.headers().iterator();
while (iterator.hasNext()) {
Pair<String, String> next = iterator.next();
String first = next.getFirst();
String second = next.getSecond();
Log.d(TAG, "key: " + first + " value: " + second);
}
String disposition = response.header("Content-disposition");
String fileName = disposition.replace("attachment; filename=", "");
//获取存放图片的文件地址(重要)
File externalFilesDir = okHttpActivity.this.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
//路径不存在则,创建路径。
if (!externalFilesDir.exists()) {
externalFilesDir.mkdirs();
}
//File.separator相当于”\“
File new_file = new File(externalFilesDir + File.separator + fileName);
Log.d(TAG, "new_file: "+new_file);
//文件不存在,则创建文件。
if (!new_file.exists()) {
new_file.createNewFile();
}
//获取文件输出流
fileOutputStream = new FileOutputStream(new_file);
//获取连接输入流
inputStreams = response.body().byteStream();
//定义缓存数组
byte[] buffer = new byte[1024];
int len;
//读写操作
while ((len = inputStreams.read(buffer, 0, buffer.length)) != -1) {
fileOutputStream.write(buffer, 0, len);
}
//刷新缓存区
fileOutputStream.flush();
}
} catch(Exception e){
e.printStackTrace();
}finally{
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inputStreams != null) {
try {
inputStreams.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
});
}
五.Retrofit框架
github地址:https://github.com/square/retrofit
官网地址:https://square.github.io/retrofit/
1.例子
导入框架:
implementation 'com.squareup.retrofit2:retrofit:2.7.0'
创建接口
package com.atian;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.GET;
public interface API {
@GET("/get/text")
Call<ResponseBody> getJson();
}
编写代码
public void getAll(View view){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://10.0.2.2:9102")
.build();
API api = retrofit.create(API.class);
Call<ResponseBody> task = api.getJson();
task.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
int code = response.code();
if(code == 200){
ResponseBody body = response.body();
try {
Log.d(TAG, "body: "+body.string());
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d(TAG, "onFailure: "+t.getMessage());
}
});
}
2.请求数据并展示
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:layout_width="match_parent"
android:text="get请求"
android:textAllCaps="false"
android:onClick="getAll"
android:layout_height="wrap_content"/>
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:id="@+id/resultList"
android:layout_height="wrap_content">
</androidx.recyclerview.widget.RecyclerView>
</LinearLayout>
MainActivity.java
package com.atian;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import com.atian.Adapters.ListViewAdapter;
import com.atian.domain.jsonResult;
import com.google.gson.Gson;
import java.io.IOException;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
RecyclerView resultList;
ListViewAdapter listViewAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
checkPermission();
initView();
}
private void initView() {
resultList = this.findViewById(R.id.resultList);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
//设置设置布局管理器到进去
resultList.setLayoutManager(linearLayoutManager);
//创建适配器,把数据通过构造方法存进去。
listViewAdapter = new ListViewAdapter();
//设置适配器到Recycler里头
resultList.setAdapter(listViewAdapter);
listViewAdapter.setRecyclerItemClickListener(new ListViewAdapter.OnRecyclerItemClickListener() {
@Override
public void onRecyclerItemClick(int position) {
//这里会返回是哪条的信息,获取到哪条就,可以处理相应的逻辑了。
//注意这里写逻辑
Log.d(TAG, "点击了: "+position+"条信息");
}
});
}
private void checkPermission() {
//先判断有没有权限
int i = checkSelfPermission("android.permission.READ_EXTERNAL_STORAGE");
if(i != PackageManager.PERMISSION_GRANTED){
//没有权限
// 申请权限
// 定义需要申请的权限数组
String[] permission = new String[] {
Manifest.permission.READ_EXTERNAL_STORAGE
};
// 定义这次申请权限的唯一请求编码
int requestCode = 2023;
// 申请权限
requestPermissions(permission, requestCode);
}
}
/**
* 申请权限的回调方法
* @param requestCode 申请权限时的请求码
* @param permissions 所有权限的数组
* @param grantResults 返回获取权限的状态码数组(-1:获取失败----0:获取成功)
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(requestCode == 2023){
Log.d(TAG, "grantResults: "+grantResults[0]);
Log.d(TAG, "grantResults: "+grantResults.length);
if(grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
//有权限
Toast.makeText(this, "已经获得所有权限!", Toast.LENGTH_SHORT).show();
}else {
//没有权限
//根据交互数据
Toast.makeText(this, "没有获得权限!,程序将退出!", Toast.LENGTH_SHORT).show();
}
}
}
public void getAll(View view){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://10.0.2.2:9102")
.build();
API api = retrofit.create(API.class);
Call<ResponseBody> task = api.getJson();
task.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
int code = response.code();
if(code == 200){
ResponseBody body = response.body();
try {
String result = body.string();//只能调用一次,相当于是从箱子里拿东西出来,只能拿一次。拿出来之后再调用就拿不到了。
Gson gson = new Gson();
Log.d(TAG, "result: "+result);
jsonResult jsonResult = gson.fromJson(result,com.atian.domain.jsonResult.class);
if(jsonResult==null){
return;
}
String s = jsonResult.getData().toString();
Log.d(TAG, "s: "+s);
//更新界面
updateList(jsonResult);
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d(TAG, "onFailure: "+t.getMessage());
}
});
}
private void updateList(jsonResult jsonResult) {
listViewAdapter.setData(jsonResult);
}
}
API.java
package com.atian;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.GET;
public interface API {
@GET("/get/text")
Call<ResponseBody> getJson();
}
jsonResult.java
package com.atian.domain;
import java.util.List;
public class jsonResult {
private boolean success;
private int code;
private String message;
private List<DataDTO> data;
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public List<DataDTO> getData() {
return data;
}
public void setData(List<DataDTO> data) {
this.data = data;
}
@Override
public String toString() {
return "jsonResult{" +
"success=" + success +
", code=" + code +
", message='" + message + '\'' +
", data=" + data +
'}';
}
public static class DataDTO {
private String id;
private String title;
private int viewCount;
private int commentCount;
private String publishTime;
private String userName;
private String cover;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getViewCount() {
return viewCount;
}
public void setViewCount(int viewCount) {
this.viewCount = viewCount;
}
public int getCommentCount() {
return commentCount;
}
public void setCommentCount(int commentCount) {
this.commentCount = commentCount;
}
public String getPublishTime() {
return publishTime;
}
public void setPublishTime(String publishTime) {
this.publishTime = publishTime;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getCover() {
return cover;
}
public void setCover(String cover) {
this.cover = cover;
}
@Override
public String toString() {
return "DataDTO{" +
"id='" + id + '\'' +
", title='" + title + '\'' +
", viewCount=" + viewCount +
", commentCount=" + commentCount +
", publishTime='" + publishTime + '\'' +
", userName='" + userName + '\'' +
", cover='" + cover + '\'' +
'}';
}
}
}
ListViewAdapter.java
package com.atian.Adapters;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.atian.R;
import com.atian.domain.jsonResult;
import com.bumptech.glide.Glide;
import java.util.ArrayList;
import java.util.List;
public class ListViewAdapter extends RecyclerView.Adapter<ListViewAdapter.Holder> {
private List<com.atian.domain.jsonResult.DataDTO> data = new ArrayList<com.atian.domain.jsonResult.DataDTO>();
@NonNull
@Override
public Holder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = View.inflate(parent.getContext(), R.layout.item_json_result, null);
return new Holder(view);
}
@Override
public void onBindViewHolder(@NonNull Holder holder, int position) {
//在这里设置数据
holder.setData(data.get(position));
//设置条目监听
holder.setListener(position);
}
@Override
public int getItemCount() {
return data.size();
}
public void setData(jsonResult jsonResult) {
//先清除掉数组里的元素
data.clear();
//设置元素
data = jsonResult.getData();
//刷新ui
notifyDataSetChanged();
}
public class Holder extends RecyclerView.ViewHolder{
ImageView image_name;
TextView author_name;
TextView book_name;
TextView count ;
public Holder(@NonNull View itemView) {
super(itemView);
image_name = (ImageView)itemView.findViewById(R.id.image_name);
author_name = (TextView)itemView.findViewById(R.id.author_name);
book_name = (TextView)itemView.findViewById(R.id.book_name);
count = (TextView)itemView.findViewById(R.id.count);
}
public void setData(jsonResult.DataDTO dataDTO) {
//处理图像的工具
Glide.with(image_name.getContext()).load("http://10.0.2.2:9102"+dataDTO.getCover()).into(image_name);
author_name.setText("作者名:"+dataDTO.getUserName());
book_name.setText("书名:"+dataDTO.getTitle());
count.setText("访问数:"+dataDTO.getViewCount());
}
/**
* 这个方法用于设置监听事件
* position 哪个条目
*/
public void setListener(int position){
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO 这里回调自定义的点击事件
if (itemClickListener != null) {
// getAdapterPosition()方法已经过时了,建议我们去调用
// itemClickListener.onRecyclerItemClick(getAdapterPosition());
//----------------------------------------------------------------------------------------------
// itemClickListener.onRecyclerItemClick(getAbsoluteAdapterPosition());
itemClickListener.onRecyclerItemClick(position);
}
}
});
}
}
/** 创建自定义监听接口 */
public interface OnRecyclerItemClickListener {
void onRecyclerItemClick(int position);
}
/** 创建自定义的监听对象 */
private OnRecyclerItemClickListener itemClickListener;
/** 这个就是提供给外部进行设置监听对象的 */
public void setRecyclerItemClickListener(OnRecyclerItemClickListener listener) {
this.itemClickListener = listener;
}
}
item_json_result.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="80dp"
android:layout_margin="10dp"
android:id="@+id/image_name"
android:src="@mipmap/ic_launcher"
android:scaleType="centerInside"
android:layout_height="80dp">
</ImageView>
<LinearLayout
android:layout_width="wrap_content"
android:orientation="vertical"
android:layout_marginTop="10dp"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:text="书名:"
android:id="@+id/book_name"
android:textSize="20sp"
android:ellipsize="end"
android:lines="1"
android:layout_height="wrap_content">
</TextView>
<TextView
android:layout_width="match_parent"
android:text="作者:"
android:id="@+id/author_name"
android:textSize="20sp"
android:layout_height="wrap_content">
</TextView>
<TextView
android:layout_width="match_parent"
android:text="访问数:"
android:id="@+id/count"
android:textSize="20sp"
android:layout_height="wrap_content">
</TextView>
</LinearLayout>
</LinearLayout>
3.转换器(请求回来的信息直接转成bean类)
1.添加相关的依赖
implementation 'com.squareup.retrofit2:converter-gson:2.7.0'
2.修改接口返回对象
package com.atian;
import com.atian.domain.jsonResult;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.GET;
public interface API {
@GET("/get/text")
Call<jsonResult> getJson();
}
3.使用代码
添加.addConverterFactory(GsonConverterFactory.create())
public void getAll(View view){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://10.0.2.2:9102")
.addConverterFactory(GsonConverterFactory.create())
.build();
API api = retrofit.create(API.class);
Call<jsonResult> task = api.getJson();
task.enqueue(new Callback<jsonResult>() {
@Override
public void onResponse(Call<jsonResult> call, Response<jsonResult> response) {
int code = response.code();
if(code == 200){
jsonResult jsonResult = response.body();
updateList(jsonResult);
}
}
@Override
public void onFailure(Call<jsonResult> call, Throwable t) {
Log.d(TAG, "onFailure: "+t.getMessage());
}
});
}
新建RetrofitUtil工具类
package com.atian.utils;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class RetrofitUtil {
private static Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://10.0.2.2:9102")
.addConverterFactory(GsonConverterFactory.create())
.build();
public static Retrofit getRetrofit(){
return retrofit;
}
}
4.–@Query注解
相当于在url路径后拼接参数进行传递
@GET("/get/param")//相当于url路径上拼接了key value的值
Call<GetWithParamsResult> getWithParams(@Query("keyword")String keyword,
@Query("page")int page,
@Query("order")int order);
5.–@QueryMap注解
相当于url路径上拼接了key value的值(使用的是map集合的方法)
@GET("/get/param")//相当于url路径上拼接了key value的值(使用的是map集合的方法)
Call<GetWithParamsResult> getWithParamsMap(@QueryMap HashMap<String,String> params);
使用:
public void getParamsMap(View view){
Retrofit retrofit = RetrofitUtil.getRetrofit();
API api = retrofit.create(API.class);
HashMap<String, String> objectObjectHashMap = new HashMap<>();
objectObjectHashMap.put("keyword","你好啊!");
objectObjectHashMap.put("page","10");
objectObjectHashMap.put("order","1");
Call<GetWithParamsResult> call = api.getWithParamsMap(objectObjectHashMap);
call.enqueue(new Callback<GetWithParamsResult>() {
@Override
public void onResponse(Call<GetWithParamsResult> call, Response<GetWithParamsResult> response) {
int code = response.code();
if(code == 200){
GetWithParamsResult body = response.body();
String s = body.toString();
Log.d(TAG, "s: "+s);
}
}
@Override
public void onFailure(Call<GetWithParamsResult> call, Throwable t) {
Log.d(TAG, "onFailure: "+t.toString());
}
});
}
6.–@Post注解
相当于url路径上拼接了key value的值,post的url上也可以传值。
@POST("/post/string")//相当于url路径上拼接了key value的值
Call<GetWithParamsResult> postWithParams(@Query("string")String string);
7.–@Url注解
可以连请求路径和参数一起传过去
@POST
Call<GetWithParamsResult> postWithUrl(@Url String url);
使用:
public void postWithUrl(View view){
API api = RetrofitUtil.getRetrofit().create(API.class);
Call<GetWithParamsResult> call = api.postWithUrl("/post/string?string=内容测试内容");
call.enqueue(new Callback<GetWithParamsResult>() {
@Override
public void onResponse(Call<GetWithParamsResult> call, Response<GetWithParamsResult> response) {
int code = response.code();
if(code == HttpsURLConnection.HTTP_OK){
GetWithParamsResult body = response.body();
Log.d(TAG, "body: "+body.toString());
}
}
@Override
public void onFailure(Call<GetWithParamsResult> call, Throwable t) {
Log.d(TAG, "onFailure: "+t.toString());
}
});
}
8.–@Body注解
Body中请求参数(自定义对象)
@POST("/post/comment")
Call<GetWithParamsResult> postWithBody(@Body CommentItem commentItem);
代码:
public void postWithBody(View view){
API api = RetrofitUtil.getRetrofit().create(API.class);
CommentItem commentItem = new CommentItem();
commentItem.setArticleId("12345");
commentItem.setCommentContent("xasjdkdhas");
Call<GetWithParamsResult> call = api.postWithBody(commentItem);
call.enqueue(new Callback<GetWithParamsResult>() {
@Override
public void onResponse(Call<GetWithParamsResult> call, Response<GetWithParamsResult> response) {
int code = response.code();
if(code == HttpsURLConnection.HTTP_OK){
GetWithParamsResult body = response.body();
Log.d(TAG, "body: "+body.toString());
}
}
@Override
public void onFailure(Call<GetWithParamsResult> call, Throwable t) {
Log.d(TAG, "onFailure: "+t.toString());
}
});
}
9.–@Part注解和@Multipart注解
@Multipart
@POST("/file/upload")//上传单个文件
Call<PostFileResult> postWithUpload(@Part MultipartBody.Part part);
代码:
public void postWithUpload(View view){
API api = RetrofitUtil.getRetrofit().create(API.class);
File file = new File("/storage/emulated/0/Download/3abc27abc474cdd4ebd7b2f3e83d05ef.jpeg");
RequestBody requestBody = RequestBody.create(MediaType.parse("image/jpeg"),file);
MultipartBody.Part part = MultipartBody.Part.createFormData("file", file.getName(), requestBody);
Call<PostFileResult> call = api.postWithUpload(part);
call.enqueue(new Callback<PostFileResult>() {
@Override
public void onResponse(Call<PostFileResult> call, Response<PostFileResult> response) {
int code = response.code();
if(code == HttpsURLConnection.HTTP_OK){
PostFileResult body = response.body();
Log.d(TAG, "body: "+body.toString());
}
}
@Override
public void onFailure(Call<PostFileResult> call, Throwable t) {
Log.d(TAG, "onFailure: "+t.toString());
}
});
}
10.–上传多文件
@Multipart
@POST("/files/upload")//上传单个文件
Call<PostFileResult> postWithUploads(@Part List<MultipartBody.Part> parts);
代码:
/**
* 提取公共方法
* @param filename
* @param files
* @return
*/
private MultipartBody.Part createPartByPathAndKey(String filename, String files){
File file = new File(filename);
RequestBody requestBody = RequestBody.create(MediaType.parse("image/jpeg"),file);
MultipartBody.Part part = MultipartBody.Part.createFormData(files, file.getName(), requestBody);
return part;
}
/**
* 上传多个文件
* @param view
*/
public void postWithUploads(View view){
API api = RetrofitUtil.getRetrofit().create(API.class);
ArrayList<MultipartBody.Part> parts = new ArrayList<>();
MultipartBody.Part files0 = createPartByPathAndKey("/storage/emulated/0/Download/3abc27abc474cdd4ebd7b2f3e83d05ef.jpeg", "files");
MultipartBody.Part files1 = createPartByPathAndKey("/storage/emulated/0/Download/75d1968dd23c9c74c2c702b5a5dbf874.jpeg", "files");
MultipartBody.Part files2 = createPartByPathAndKey("/storage/emulated/0/Download/b9040d67938b047f0493e3c8c0f22ab6.jpeg", "files");
MultipartBody.Part files3 = createPartByPathAndKey("/storage/emulated/0/Download/f67b5abd3aed142c74f070a60d320c7f.jpeg", "files");
parts.add(files0);
parts.add(files1);
parts.add(files2);
parts.add(files3);
Call<PostFileResult> postFileResultCall = api.postWithUploads(parts);
postFileResultCall.enqueue(new Callback<PostFileResult>() {
@Override
public void onResponse(Call<PostFileResult> call, Response<PostFileResult> response) {
int code = response.code();
if(code == 200){
PostFileResult body = response.body();
String s = body.toString();
Log.d(TAG, "s: "+s);
}
}
@Override
public void onFailure(Call<PostFileResult> call, Throwable t) {
Log.d(TAG, "onFailure: "+t.toString());
}
});
}
11.–上传文件并传参
@Multipart
@POST("/file/params/upload")//上传单个文件,并携带参数
Call<PostFileResult> postWithUploadParams(@Part MultipartBody.Part part, @PartMap Map<String,String> map);
/**
* 上传文件带参数
* @param view
*/
public void postWithUploadParams(View view){
API api = RetrofitUtil.getRetrofit().create(API.class);
File file = new File("/storage/emulated/0/Download/3abc27abc474cdd4ebd7b2f3e83d05ef.jpeg");
RequestBody requestBody = RequestBody.create(MediaType.parse("image/jpeg"),file);
MultipartBody.Part part = MultipartBody.Part.createFormData("file", file.getName(), requestBody);
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("description","这是一张头像文件");
hashMap.put("isFree","true");
Call<PostFileResult> postFileResultCall = api.postWithUploadParams(part, hashMap);
postFileResultCall.enqueue(new Callback<PostFileResult>() {
@Override
public void onResponse(Call<PostFileResult> call, Response<PostFileResult> response) {
int code = response.code();
if(code == 200){
PostFileResult body = response.body();
Log.d(TAG, "body: "+body);
}
}
@Override
public void onFailure(Call<PostFileResult> call, Throwable t) {
Log.d(TAG, "onFailure: "+t.toString());
}
});
}
12.–表单提交(@Field和@FieldMap)
@FormUrlEncoded//提交表单
@POST("/login")
Call<loginResult> login(@Field("userName")String username,@Field("password")String password);
代码:
public void login(View view){
API api = RetrofitUtil.getRetrofit().create(API.class);
Call<loginResult> login = api.login("123", "123");
login.enqueue(new Callback<loginResult>() {
@Override
public void onResponse(Call<loginResult> call, Response<loginResult> response) {
int code = response.code();
if(code == 200){
loginResult body = response.body();
Log.d(TAG, "body: "+body);
}
}
@Override
public void onFailure(Call<loginResult> call, Throwable t) {
Log.e(TAG, "onFailure: "+t.toString());
}
});
}
13.–文件下载(@Streaming)
@Streaming
@GET
Call<ResponseBody> downFile(@Url String url);
代码:
ailure(Call<ResponseBody> call,Throwable t) {
Log.d(TAG,"onFailure -- > " + t.toString());
}
});
}
/**
* 文件操作不能在主线程里操作,所以创建了一个新的线程。
* @param response
* @param headers
*/
private void writeFile2Sd(Response<ResponseBody> response, Headers headers) {
new Thread(new Runnable() {
@Override
public void run() {
String disposition = headers.get("Content-disposition");
if(disposition != null) {
int fileNameIndex = disposition.indexOf("filename=");
Log.d(TAG,"fileNameIndex -- > " + fileNameIndex);
String fileName = disposition.substring(fileNameIndex + "filename=".length());
Log.d(TAG,"fileName -- > " + fileName);
File picFilePath = GetParamsActivity.this.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
Log.d(TAG,"picFilePath --> " + picFilePath);
File file = new File(picFilePath + File.separator + fileName);
Log.d(TAG,"file -- > " + file);
FileOutputStream fos = null;
try {
if(!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
if(!file.exists()) {
file.createNewFile();
}
fos = new FileOutputStream(file);
InputStream inputStream = response.body().byteStream();
byte[] buf = new byte[1024];
int len;
while((len = inputStream.read(buf,0,buf.length)) != -1) {
fos.write(buf,0,len);
}
} catch(Exception e) {
e.printStackTrace();
} finally {
if(fos != null) {
try {
fos.close();
} catch(IOException e) {
e.printStackTrace();
}
}
}
}
}
}).start();
}
14.–@header注解
@Multipart
@POST("/file/upload")
Call<FileUploadResult> postFile(@Part MultipartBody.Part file,@Header("token") String token);
@Multipart
@POST("/files/upload")
Call<FileUploadResult> postFiles(@Part List<MultipartBody.Part> files,@HeaderMap Map<String,String> headers);
@Headers({"token:231231","version:1.0","client:android"})
@Multipart
@POST("/file/params/upload")
Call<FileUploadResult> postFileWithParams(@PartMap Map<String,Object> params,@Part MultipartBody.Part file);
想要在用户验证,携带token的话,每个类上加会很麻烦。
Okhttp是支持拦截器的,我们直接在每次请求的时候,在头部加上token就可以了。
private void createRetrofit() {
//设置一下okHttp的参数
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(CONNECT_TIME_OUT,TimeUnit.MILLISECONDS)
.addInterceptor(mHeaderInterceptor)
.build();
mRetrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)//设置BaseUrl
.client(okHttpClient)//设置请求的client
.addConverterFactory(GsonConverterFactory.create())//设置转换器
.build();
}
private Interceptor mHeaderInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request().newBuilder()
.addHeader("token","204391jawslejqowejqwi")
.addHeader("version","1.2.0")
.addHeader("client","android铂金版")
.build();
return chain.proceed(request);
}
};
注解里写的可以覆盖拦截器的内容。