okhttp框架
一.okhttp介绍
okhttp是一个第三方类库,用于android中请求网络。
这是一个开源项目,是安卓端最火热的轻量级框架,由移动支付Square公司贡献(该公司还贡献了Picasso和LeakCanary) 。
用于替代HttpUrlConnection和Apache HttpClient(android API23里已移除HttpClient)。
二.okhttp使用
1.依赖
使用okhttp要导入依赖
implementation 'com.squareup.okhttp3:okhttp:3.12.1'//okhttp依赖
2.okhttp做get请求json
使用时分为四步
- 获取client客户端对象
- 完成request请求
- client发送requset获取call对象
- call调用enqueue获取响应结果
其中enqueue方法参数为一个Callback对象
onFailure为请求失败时的方法
onResponse为请求成功时的方法
//1.获取client对象
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(60 * 1000, TimeUnit.SECONDS)//连接超时时间
.readTimeout(60 * 1000, TimeUnit.SECONDS)//读取超时时间
.writeTimeout(60 * 1000, TimeUnit.SECONDS)//写入超时时间
.build();
//2.request请求
Request request = new Request.Builder()
.url("http://www.qubaobei.com/ios/cf/dish_list.php?stage_id=1&limit=20&page=1")//请求地址
.get()//请求方式
.build();
//3.client发起request请求 -> call连接
Call call = client.newCall(request);
//4.加入队列 ->获取响应
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, final IOException e) {//请求失败
handler.post(new Runnable() {
@Override
public void run() {
String message = e.getMessage();
Toast.makeText(MainActivity.this, "请求失败" + message, Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onResponse(Call call, Response response) throws IOException {//请求成功
final String string = response.body().string();//将响应体转换为string格式
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "" + string, Toast.LENGTH_SHORT).show();
}
});
}
});
3.okhttp做网络下载MP4
在写入SD卡的时候需要动态请求权限
requestPermissions(new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
},101);
//1.获取client对象
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(60 * 1000, TimeUnit.SECONDS)//连接超时时间
.readTimeout(60 * 1000, TimeUnit.SECONDS)//读取超时时间
.writeTimeout(60 * 1000, TimeUnit.SECONDS)//写入超时时间
.build();
//2.request请求
Request request = new Request.Builder()
.url("http://uvideo.spriteapp.cn/video/2019/0512/56488d0a-7465-11e9-b91b-1866daeb0df1_wpd.mp4")//请求地址
.get()//请求方式
.build();
//3.client发起request请求 -> call连接
Call call = client.newCall(request);
//4.加入队列 ->获取响应
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, final IOException e) {//请求失败
handler.post(new Runnable() {
@Override
public void run() {
String message = e.getMessage();
Toast.makeText(MainActivity.this, "请求失败" + message, Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onResponse(Call call, Response response) throws IOException {//请求成功
InputStream is = response.body().byteStream();//将response转化为输入流
FileOutputStream fos = new FileOutputStream("/sdcard/Download/houzi.mp4");
byte[] bys = new byte[1024];
int len = 0;
int count = 0;//记录下载的总量
long l = response.body().contentLength();//获取需要下载的总量
while ((len = is.read(bys)) != -1) {
fos.write(bys, 0, len);
count += len;
final int progress = (int) (count * 100 / l);//获取百分比
handler.post(new Runnable() {
@Override
public void run() {
pb.setProgress(progress);
}
});
}
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "下载成功", Toast.LENGTH_SHORT).show();
}
});
}
});
4.okhttp做post请求参数为form格式
(1).post说明
这里边post方法需要一个请求体
RequestBody是一个抽象类
public abstract class RequestBody
所以我们需要用它的实现子类或调用 .create方法
public final class FormBody extends RequestBody
请求体有两种形式
- form
FormBody formBody = new FormBody.Builder()
.add("username", "xiabei")
.add("password", "123456")
.add("repassword", "123456")
.build();
- json
HashMap<String, String> map = new HashMap<>();
map.put("phoneNum", "17696945424");
map.put("userPassWord", "123456");
String s = new Gson().toJson(map);
RequestBody body = RequestBody.create(MediaType.parse("application/json"), s);//请求体
(2).form
1>注册
//1.获取client对象
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(60 * 1000, TimeUnit.SECONDS)//连接超时时间
.readTimeout(60 * 1000, TimeUnit.SECONDS)//读取超时时间
.writeTimeout(60 * 1000, TimeUnit.SECONDS)//写入超时时间
.build();
//POST
//参数:username,password,repassword
FormBody formBody = new FormBody.Builder()
.add("username", "xiabei")
.add("password", "123456")
.add("repassword", "123456")
.build();
//2.request请求
Request request = new Request.Builder()
.url("https://www.wanandroid.com/user/register")//请求地址
.post(formBody)
.build();
//3.client发起request请求 -> call连接
Call call = client.newCall(request);
//4.加入队列 ->获取响应
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, final IOException e) {//请求失败
handler.post(new Runnable() {
@Override
public void run() {
String message = e.getMessage();
Toast.makeText(MainActivity.this, "请求失败" + message, Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onResponse(Call call, Response response) throws IOException {//请求成功
final String string = response.body().string();//将响应体转换为string格式
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "" + string, Toast.LENGTH_SHORT).show();
}
});
}
});
2>登陆
//1.获取client对象
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(60 * 1000, TimeUnit.SECONDS)//连接超时时间
.readTimeout(60 * 1000, TimeUnit.SECONDS)//读取超时时间
.writeTimeout(60 * 1000, TimeUnit.SECONDS)//写入超时时间
.build();
//POST
//参数:username,password
FormBody formBody = new FormBody.Builder()//请求体
.add("username", "xiabei")
.add("password", "123456")
.build();
//2.request请求
Request request = new Request.Builder()
.url("https://www.wanandroid.com/user/login")//请求地址
.post(formBody)
.build();
//3.client发起request请求 -> call连接
Call call = client.newCall(request);
//4.加入队列 ->获取响应
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, final IOException e) {//请求失败
handler.post(new Runnable() {
@Override
public void run() {
String message = e.getMessage();
Toast.makeText(MainActivity.this, "请求失败" + message, Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onResponse(Call call, Response response) throws IOException {//请求成功
final String string = response.body().string();//将响应体转换为string格式
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "" + string, Toast.LENGTH_SHORT).show();
}
});
}
});
(3).json
1>.注册
//1.获取client对象
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(60 * 1000, TimeUnit.SECONDS)//连接超时时间
.readTimeout(60 * 1000, TimeUnit.SECONDS)//读取超时时间
.writeTimeout(60 * 1000, TimeUnit.SECONDS)//写入超时时间
.build();
//POST
// {
// "phoneNum": 0,
// "userPassWord": "string"
//}
HashMap<String, String> map = new HashMap<>();
map.put("phoneNum", "17696945424");
map.put("userPassWord", "123456");
String s = new Gson().toJson(map);
RequestBody body = RequestBody.create(MediaType.parse("application/json"), s);//请求体
Toast.makeText(this, "" + s, Toast.LENGTH_SHORT).show();
//2.request请求
Request request = new Request.Builder()
.url("http://172.81.227.127:8055//videouser/register")//请求地址
.post(body)
.build();
//3.client发起request请求 -> call连接
Call call = client.newCall(request);
//4.加入队列 ->获取响应
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, final IOException e) {//请求失败
handler.post(new Runnable() {
@Override
public void run() {
String message = e.getMessage();
Toast.makeText(MainActivity.this, "请求失败" + message, Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onResponse(Call call, Response response) throws IOException {//请求成功
final String string = response.body().string();//将响应体转换为string格式
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "" + string, Toast.LENGTH_SHORT).show();
}
});
}
});
2>.登陆
//1.获取client对象
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(60 * 1000, TimeUnit.SECONDS)//连接超时时间
.readTimeout(60 * 1000, TimeUnit.SECONDS)//读取超时时间
.writeTimeout(60 * 1000, TimeUnit.SECONDS)//写入超时时间
.build();
//POST
// {
// "phoneNum": 0,
// "userPassWord": "string"
//}
HashMap<String, String> map = new HashMap<>();
map.put("phoneNum", "17696945424");
map.put("userPassWord", "123456");
String s = new Gson().toJson(map);
RequestBody body = RequestBody.create(MediaType.parse("application/json"), s);//请求体
Toast.makeText(this, "" + s, Toast.LENGTH_SHORT).show();
//2.request请求
Request request = new Request.Builder()
.url("http://172.81.227.127:8055//videouser/login")//请求地址
.post(body)
.build();
//3.client发起request请求 -> call连接
Call call = client.newCall(request);
//4.加入队列 ->获取响应
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, final IOException e) {//请求失败
handler.post(new Runnable() {
@Override
public void run() {
String message = e.getMessage();
Toast.makeText(MainActivity.this, "请求失败" + message, Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onResponse(Call call, Response response) throws IOException {//请求成功
final String string = response.body().string();//将响应体转换为string格式
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "" + string, Toast.LENGTH_SHORT).show();
}
});
}
});
三.小案例
- 利用okHttp实现登陆
- 登陆后获取短视频用列表展示
- 点击item实现跳转播放短视频
- 可下载到本地
首先是登陆界面
<?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:gravity="center"
android:orientation="vertical"
android:padding="20dp"
tools:context=".LoginActivity">
<EditText
android:id="@+id/et_username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入用户名" />
<EditText
android:id="@+id/et_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入密码" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:id="@+id/but_login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="登陆" />
<Button
android:id="@+id/but_register"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="注册" />
</LinearLayout>
</LinearLayout>
然后登陆的Activity代码
public class LoginActivity extends AppCompatActivity {
private EditText etUsername;
private EditText etPassword;
private Button butLogin;
private Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_login);
initViews();
}
private void initViews() {
etUsername = (EditText) findViewById(R.id.et_username);
etPassword = (EditText) findViewById(R.id.et_password);
butLogin = (Button) findViewById(R.id.but_login);
butLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//1.获取client对象
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(60 * 1000, TimeUnit.SECONDS)//连接超时时间
.readTimeout(60 * 1000, TimeUnit.SECONDS)//读取超时时间
.writeTimeout(60 * 1000, TimeUnit.SECONDS)//写入超时时间
.build();
//POST
//参数:username,password
FormBody formBody = new FormBody.Builder()//请求体
.add("username", etUsername.getText().toString())
.add("password", etPassword.getText().toString())
.build();
//2.request请求
Request request = new Request.Builder()
.url("https://www.wanandroid.com/user/login")//请求地址
.post(formBody)
.build();
//3.client发起request请求 -> call连接
Call call = client.newCall(request);
//4.加入队列 ->获取响应
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, final IOException e) {//请求失败
handler.post(new Runnable() {
@Override
public void run() {
String message = e.getMessage();
Toast.makeText(LoginActivity.this, "请求失败" + message, Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onResponse(Call call, Response response) throws IOException {//请求成功
final String string = response.body().string();//将响应体转换为string格式
handler.post(new Runnable() {
@Override
public void run() {
if (string.indexOf("0") != -1) {
Toast.makeText(LoginActivity.this, "登陆成功", Toast.LENGTH_SHORT).show();
startActivity(new Intent(LoginActivity.this, VideoActivity.class));
} else {
Toast.makeText(LoginActivity.this, "登陆失败,用户名或密码不正确", Toast.LENGTH_SHORT).show();
}
}
});
}
});
}
});
}
}
然后第二个界面需要获取短视频
封装一个短视频实体类
public class VideoEntity {
/**
* vedioUrl : http://172.81.227.127:8088/fileDownload?fileName=VID_20191217_070408.mp4
* vedioId : 1
* userId : 949
* coverImg : http://172.81.227.127:8088/fileDownload?fileName=VID_20191217_070408.mp4
*/
private String vedioUrl;
private int vedioId;
private int userId;
private String coverImg;
@Override
public String toString() {
return "VideoEntity{" +
"vedioUrl='" + vedioUrl + '\'' +
", vedioId=" + vedioId +
", userId=" + userId +
", coverImg='" + coverImg + '\'' +
'}';
}
public String getVedioUrl() {
return vedioUrl;
}
public void setVedioUrl(String vedioUrl) {
this.vedioUrl = vedioUrl;
}
public int getVedioId() {
return vedioId;
}
public void setVedioId(int vedioId) {
this.vedioId = vedioId;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getCoverImg() {
return coverImg;
}
public void setCoverImg(String coverImg) {
this.coverImg = coverImg;
}
}
适配器
public class MyAdapter extends BaseAdapter {
private List<VideoEntity> datas;
private Context context;
private LayoutInflater layoutInflater;
public MyAdapter(List<VideoEntity> datas, Context context) {
this.datas = datas;
this.context = context;
this.layoutInflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return datas.size();
}
@Override
public Object getItem(int position) {
return datas.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.item, null);
viewHolder = new ViewHolder();
viewHolder.imgShow = convertView.findViewById(R.id.img_show);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
Glide.with(context)
.load(datas.get(position).getCoverImg())
.into(viewHolder.imgShow);
return convertView;
}
class ViewHolder {
private ImageView imgShow;
}
}
item中仅有一个imageView做展示
视频列表的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"
tools:context=".VideoActivity">
<GridView
android:numColumns="2"
android:id="@+id/gv_show"
android:layout_width="match_parent"
android:layout_height="match_parent">
</GridView>
</LinearLayout>
视频列表的Activity代码
public class VideoActivity extends AppCompatActivity {
private GridView gvShow;
private Handler handler = new Handler();
private List<VideoEntity> datas = new ArrayList<>();
private MyAdapter myAdapter;
private static final String TAG = "VideoActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_video);
initViews();
initDatas();
}
private void initDatas() {
OkHttpClient client = new OkHttpClient.Builder().build();
HashMap<String, String> map = new HashMap<>();
map.put("page", "0");
map.put("userId", "0");
final String s = new Gson().toJson(map);
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), s);
Request request = new Request.Builder()
.url("http://172.81.227.127:8055/videovalues/selrecommendvideos")
.post(requestBody)
.build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(VideoActivity.this, "请求失败", Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onResponse(Call call, Response response) throws IOException {
final String string = response.body().string();
final List<VideoEntity> list = new Gson().fromJson(string, new TypeToken<ArrayList<VideoEntity>>() {
}.getType());
datas.addAll(list);
handler.post(new Runnable() {
@Override
public void run() {
myAdapter.notifyDataSetChanged();
}
});
}
});
}
private void initViews() {
gvShow = (GridView) findViewById(R.id.gv_show);
myAdapter = new MyAdapter(datas, this);
gvShow.setAdapter(myAdapter);
gvShow.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent = new Intent(VideoActivity.this, PlayActivity.class);
intent.putExtra("Url", datas.get(position).getVedioUrl());
startActivity(intent);
}
});
}
}
最后是播放界面的布局文件及Activity代码
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
tools:context=".PlayActivity">
<VideoView
android:id="@+id/vv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<Button
android:id="@+id/but_down"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_marginRight="80dp"
android:layout_marginBottom="80dp"
android:text="下载" />
</RelativeLayout>
public class PlayActivity extends AppCompatActivity {
private VideoView vv;
private Button butDown;
private String Url;
private int index = 0;
private Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_play);
requestPermissions(new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
}, 101);
initDatas();
initViews();
}
private void initDatas() {
Url = getIntent().getStringExtra("Url");
}
private void initViews() {
vv = (VideoView) findViewById(R.id.vv);
butDown = (Button) findViewById(R.id.but_down);
vv.setVideoPath(Url);
vv.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
vv.start();
}
});
butDown.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//1.获取client对象
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(60 * 1000, TimeUnit.SECONDS)//连接超时时间
.readTimeout(60 * 1000, TimeUnit.SECONDS)//读取超时时间
.writeTimeout(60 * 1000, TimeUnit.SECONDS)//写入超时时间
.build();
//2.request请求
Request request = new Request.Builder()
.url("http://uvideo.spriteapp.cn/video/2019/0512/56488d0a-7465-11e9-b91b-1866daeb0df1_wpd.mp4")//请求地址
.get()//请求方式
.build();
//3.client发起request请求 -> call连接
Call call = client.newCall(request);
//4.加入队列 ->获取响应
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, final IOException e) {//请求失败
handler.post(new Runnable() {
@Override
public void run() {
String message = e.getMessage();
Toast.makeText(PlayActivity.this, "请求失败" + message, Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onResponse(Call call, Response response) throws IOException {//请求成功
InputStream is = response.body().byteStream();//将response转化为输入流
FileOutputStream fos = new FileOutputStream("/sdcard/Download/video"+(index++)+".mp4");
byte[] bys = new byte[1024];
int len = 0;
while ((len = is.read(bys)) != -1) {
fos.write(bys, 0, len);
}
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(PlayActivity.this, "下载成功", Toast.LENGTH_SHORT).show();
}
});
}
});
}
});
}
}
记得加SD卡权限和动态获取权限!!
效果展示
要开心加油