用到上面这几个工具包,Okhttp是发送网络请求的,Retrofit是基于okhttp,使用更方便,gson是用来解析json请求数据。
要先配置:
implementation("com.squareup.okhttp3:okhttp:4.1.0")
implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.5'
implementation 'com.squareup.retrofit2:retrofit:2.6.1' // 必要retrofit依赖
implementation 'com.squareup.retrofit2:converter-gson:2.6.1' // 必要依赖,解析json字符所用
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.6.1'// 必要依赖,和Rxjava结合必须用到,提一下,暂时不说这个
记得添加网络权限
1.获取okHttpClient对象
2.创建RequestBody(当使用post请求时需要这一步,get请求不需要)
3.构建Request对象
4.构建Call对象
5.通过Call.enqueue(callback)方法来提交异步请求;execute()方法实现同步请求
参数的设置:
1.formbody:是提交表单数据,post请求,不会拼在url中
2. requestBody:是作为消息正文发送,可以把字符串、xml、json转到body中发送
3. addHeader: 是在请求头中添加参数
public void okHttpTest(){
//创建对象
OkHttpClient client = new OkHttpClient();
//formbody是提交表单数据,post请求,不会拼在url中
FormBody formBody = new FormBody.Builder()
.add("Id","108820004")
.build();
//requestBody是作为消息正文发送,可以把字符串、xml、json转到body中发送
RequestBody requestBody = RequestBody.create(MediaType.parse("text/plain;charset=utf-8"),"108820004");
Request request = new Request.Builder()
//addHeader是在请求头中添加参数
.url("http://120.224.69.6:81/api/de/GetCountryList/") .addHeader("u","A6E95CE7366AD705996A6B4124EDAA8#ADAF8171A8552D5DCFA2EC374D638BA")
//这两个post是指定post请求,formbody和requestbody封装了需要传递的参数,如果使用get请求就换成.get()
.post(formBody)
.post(requestBody)
.build();
Call call = client.newCall(request);
//发送请求
call.enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {//请求失败
Log.d(TAG, "onFailure: ");
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
//请求成功
Log.d(TAG, "onResponse: "+response);
}
});
}
注意:请求是异步请求时,请求是在子线程中进行的,如果接下来的动作需要用到请求返回的数据,那就必须放在onResponse中进行,否则数据错乱。
参考:OkHttp详解
Retrofit 是一个 RESTful 的 HTTP 网络请求框架的封装。网络请求的工作本质上是 OkHttp 完成,而 Retrofit 仅负责 网络请求接口的封装
使用步骤:
这里提一下遇到的一个巨坑,后台有一个参数是作为正文发送,而且没有参数名,只有值,当时搞得贼蛋疼,这里就用到RequestBody的功能了,把这个参数值前面加上等号作为字符串交给RequestBody就解决了,但是要记得参数名不要等号也得要加。
@FormUrlEncoded
@Headers("Content-Type:application/x-www-form-urlencoded; charset=utf-8")
@POST("User/UserLoginP")
Call<Response<LoginBean>> getCall(@Field("account") String account, @Field("password") String password);
@Headers("Content-Type:application/x-www-form-urlencoded; charset=utf-8")
@POST("de/GetCountryList/")
Call<ArrayResponse<AreaBean>> getCountryList(@Header("u") String u, @Body RequestBody id);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(RequestInterface.HOST)
//设置json解析器
.addConverterFactory(GsonConverterFactory.create())
.build();
//创建网络请求接口实例
RequestInterface request = retrofit.create(RequestInterface.class);
案例:
/**
* 发送请求,获取某个镇里的所有村,镇的id为参数
*/
private void getVillageRequest(final Integer Id) {
Log.d(TAG, "getVillageRequest: 获取村数据列表请求");
//创建Retrofit对象
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(RequestInterface.HOST)
//设置json解析器
.addConverterFactory(GsonConverterFactory.create())
.build();
//创建网络请求接口实例
RequestInterface request = retrofit.create(RequestInterface.class);
//对发送请求进行封装,参数是镇的id,无参数名,但是要有等号
RequestBody id = RequestBody.create(MediaType.parse("application/x-www-form-urlencoded;charset=utf-8"), "=" + Id.toString());
Call<ArrayResponse<AreaBean>> call = request.getCountryList(SessionManager.getToken(), id);
//发送请求,异步
call.enqueue(new Callback<ArrayResponse<AreaBean>>() {
//请求成功时回调
@Override
public void onResponse(Call<ArrayResponse<AreaBean>> call, retrofit2.Response<ArrayResponse<AreaBean>> response) {
//处理返回的数据结果
Log.d(TAG, "onResponse: 返回结果:" + response);
Log.d(TAG, "onResponse: 村列表请求信息数据:" + response.body());
ArrayResponse<AreaBean> mResponse = response.body();
countryList = mResponse.getData();
/**
* 下面的村庄适配器的设置必须是村庄数据接收完成后才能进行,必须放在这一块代码中执行,之前放在TownClickListener的onItemSelected方法里请求下面,
* 这样会导致数据错误,有可能切换镇的时候村庄列表还是上一个镇的数据,因为请求是在子线程中进行的,在镇的监听器中是另一个线程,这是造成这个bug的原因
*/
loadVillage(countryList);
Log.d(TAG, "onResponse: 村列表:" + Arrays.toString(countryList));
Log.d(TAG, "onItemSelected: 设置村级列表适配器,村列表数量:" + villageList.size());
villageSpinnerAdapter = new SpinnerAdapter(VideoMonitorActivity.this, villageList, Id % 10000);
village.setAdapter(villageSpinnerAdapter);
}
//请求失败时回调
@Override
public void onFailure(Call<ArrayResponse<AreaBean>> call, Throwable t) {
Log.d(TAG, "onFailure: 连接失败原因:" + t.getMessage());
ToastUtil.showMsg(VideoMonitorActivity.this, "连接失败");
}
});
}