HTTP Retrofit 网络传输
原文:https://www.jianshu.com/p/0fda3132cf98
Retrofit注解
- 请求方法
| 注解代码 | 请求格式 |
|---|---|
| @GET | GET请求 |
| @POST | POST请求 |
| @DELETE | DELETE请求 |
| @HEAD | HEAD请求 |
| @OPTIONS | OPTIONS请求 |
| @PATCH | PATCH请求 |
- 请求参数
| 注解代码 | 说明 |
|---|---|
| @Headers | 添加请求头 |
| @Path | 替换路径 |
| @Query | 替代参数值,通常是结合get请求的 |
| @FormUrlEncoded | 用表单数据提交 |
| @Field | 替换参数值,是结合post请求的 |
前提:
Android 系统上面默认所有Http的请求都被阻止了。
需要在androidmanifest.xml的 application标签上加入 android:usesCleartextTraffic="true"
首先引入依赖:Gson可以将Json和基本数据类型之间做转换;Okhtttp用来进行HTTP连接(Retrofit就是建立在OkHttp之上的);ReJava用来提供一个异步处理的操作。
//Gson库 implementation 'com.google.code.gson:gson:2.8.2' // Okhttp库 implementation 'com.squareup.okhttp3:okhttp:3.1.2' // Retrofit库 implementation 'com.squareup.retrofit2:retrofit:2.0.2' implementation 'com.squareup.retrofit2:converter-gson:2.0.2' //gson转化 implementation 'com.squareup.retrofit2:adapter-rxjava:2.0.2' //RxJava //RxJava库 implementation 'io.reactivex:rxandroid:1.0.1'
先看下服务端代码,其实就是接收到了连接后返回一个JSON格式的数据:
var http = require('http'); var url = require('url'); var util = require('util'); http.createServer(function(req, res){ res.writeHead(200, {'Content-Type': 'text/plain'}); // 解析 url 参数 var params = url.parse(req.url, true).query; console.log("有连接"); console.log(util.inspect(url.parse(req.url, true))); //发送JSON数据 var jsonobj = {time:0, code:1, data:{song_url:'yangzhilong_tem.mp3', msg:123}}; res.end(JSON.stringify(jsonobj)); }).listen(3000);
先定义一个Bean来表示从服务端获取到的东西:
import java.util.Map; public class User { private long time; private int code; private Map<String, String> data; public Map<String, String> getData() { return data; } public int getCode() { return code; } public long getTime() { return time; } }
定义一个接口来提供服务:
import retrofit2.http.GET; import retrofit2.http.Query; import rx.Observable; public interface GetAPI { //设置路径 @GET("create/original") Observable<User> getUser(@Query("author_id") String author_id, @Query("type") String type, @Query("info") String info); }
java代码:
package com.example.m_evolution; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import com.example.m_evolution.Bean.User; import com.example.m_evolution.HttpAPI.GetAPI; import java.util.concurrent.TimeUnit; import okhttp3.OkHttpClient; import retrofit2.Retrofit; import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; import retrofit2.converter.gson.GsonConverterFactory; import rx.Subscriber; import rx.android.schedulers.AndroidSchedulers; import rx.schedulers.Schedulers; public class TestActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test); OkHttpClient okHttpClient = new OkHttpClient().newBuilder() .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .writeTimeout(10, TimeUnit.SECONDS) .build(); Retrofit retrofit = new Retrofit.Builder() //设置数据解析器 .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) //设置网络请求的Url地址 .baseUrl("http://172.17.1.96:3000/") .client(okHttpClient) .build(); // 创建网络请求接口的实例 GetAPI mApi = retrofit.create(GetAPI.class); mApi.getUser("1", "10", "[嘻哈,兴奋]") .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<User>() { @Override public void onCompleted() { Log.d("TestActivity", "调用完成"); } @Override public void onError(Throwable e) { Log.d("TestActivity", "请求失败"+e.toString()); } @Override public void onNext(User user) { Log.d("TestActivity", "请求成功"); Log.d("TestActivity", "time:"+user.getTime()); Log.d("TestActivity", "code:"+user.getCode()); Log.d("TestActivity", "song_url:"+user.getData().get("song_url")+"; msg:"+user.getData().get("msg")); } }); } }
客户端结果:

服务端结果:

GET请求:
服务端提供的接口:

客户端:
//获取某用户的信息 @GET("/user/info") Observable<UserInfoHTTPResult> get_user_info(@Header("Authorization")String token, @Query("user_id")String user_id);
public class UserInfoHTTPResult { private long time; //服务器响应时间 private int code; //响应码 0表示正常 private String msg; //错误信息 private Map<String, String> data; public long getTime() { return time; } public int getCode() { return code; } public String getMsg() { return msg; } public String getUserName(){ return data.get("username"); } public String getGender(){ return data.get("gender"); } public String getAvatarUrl(){ return data.get("avatar"); } }
httpAPI.get_user_info(MyApp.token_pre+myApp.getUser_token(), user_id) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<UserInfoHTTPResult>() { @Override public void onCompleted() { Log.d(TAG, "onCompleted: "+"调用完成"); } @Override public void onError(Throwable e) { Log.d(TAG, "onError: "+"请求失败: "+e.toString()); myApp.MakeToast("网络出错"); } @Override public void onNext(UserInfoHTTPResult userInfoHTTPResult) { if(userInfoHTTPResult.getCode()==0){ //更新个人信息 myApp.setUser_nickname(userInfoHTTPResult.getUserName()); myApp.setUser_gender(userInfoHTTPResult.getGender()); myApp.setUser_head_url(userInfoHTTPResult.getAvatarUrl()); Log.d(TAG, "onNext: username: "+myApp.getUser_nickname()); Log.d(TAG, "onNext: gender: "+myApp.getUser_gender()); Log.d(TAG, "onNext: avatar: "+myApp.getUser_head_url()); editor.putString("user_nickname",myApp.getUser_nickname()); editor.putString("user_gender",myApp.getUser_gender()); editor.putString("user_head_url", myApp.getUser_head_url()); editor.commit(); //修改控件 tv_user_nickname.setText(userInfoHTTPResult.getUserName()); if(myApp.getUser_gender().equals("female")){ iv_user_gender.setImageResource(R.drawable.icon_user_gender_female); } else{ iv_user_gender.setImageResource(R.drawable.icon_user_gender_male); } ImageLoader.getInstance().displayImage(MyApp.baseUrl+myApp.getUser_head_url(),iv_user_head); } } });
POST请求:
服务端提供的接口:

注意,最后一个参数avatar表示头像,涉及到文件的上传;
//用户更新信息 @Multipart @POST("/update/user") Observable<UpdateUserHTTPResult> update_user(@Header("Authorization")String token, @Part("user_id") RequestBody user_id, @Part("username")RequestBody user_nickname, @Part("gender")RequestBody gender, @Part MultipartBody.Part part_head);
public class UpdateUserHTTPResult { private long time; //服务器响应时间 private int code; //响应码 0表示正常 private String msg; //错误信息 private Map<String, String> data; public long getTime() { return time; } public int getCode() { return code; } public String getMsg() { return msg; } public String getIsok(){ return data.get("isok"); } public String getAvatar_url(){ return data.get("avatar_url"); } }
RequestBody requestUserID = RequestBody.create(MediaType.parse("multipart/form-data"), user_id);
RequestBody requestUserNickname = RequestBody.create(MediaType.parse("multipart/form-data"), user_nickname);
RequestBody requestGender = RequestBody.create(MediaType.parse("multipart/form-data"), gender);
//将头像图片存储为图片
Bitmap bitmap = ((BitmapDrawable)iv_user_head.getDrawable()).getBitmap();
ImageUtils.saveImage(bitmap, "temp.png");
// 创建RequestBody,传入参数:"multipart/form-data",File
File imgFile = new File(Environment.getExternalStorageDirectory(),getString(R.string.app_name)+"/temp.png");
RequestBody fileRequestBody = RequestBody.create(MediaType.parse("multipart/form-data"), imgFile);
// 创建MultipartBody.Part,用于封装文件数据
MultipartBody.Part requestImgPart = MultipartBody.Part.createFormData("avatar", imgFile.getName(), fileRequestBody);
httpAPI.update_user("Bearer "+myApp.getUser_token(),requestUserID, requestUserNickname, requestGender, requestImgPart)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<UpdateUserHTTPResult>() {
@Override
public void onCompleted() {
Log.d(TAG, "onCompleted: ");
dialog_busying.dismiss();
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "onError: "+e.toString());
myApp.MakeToast("网络出错");
dialog_busying.dismiss();
}
@Override
public void onNext(UpdateUserHTTPResult updateUserHTTPResult) {
Log.d(TAG, "onNext: Time "+updateUserHTTPResult.getTime());
Log.d(TAG, "onNext: Code "+updateUserHTTPResult.getCode());
Log.d(TAG, "onNext: Msg "+updateUserHTTPResult.getMsg());
Log.d(TAG, "onNext: Isok "+updateUserHTTPResult.getIsok());
Log.d(TAG, "onNext: Avatar_url "+updateUserHTTPResult.getAvatar_url());
if(updateUserHTTPResult.getIsok().equals("true")){ //如果保存成功
//更新本地的用户昵称
String user_nickname = et_user_nickname.getText().toString();
myApp.setUser_nickname(user_nickname);
myApp.setUser_head_url(updateUserHTTPResult.getAvatar_url());
if (selector_gender == 0) myApp.setUser_gender("male");
else if (selector_gender == 1) myApp.setUser_gender("female");
editor.putString("user_nickname", myApp.getUser_nickname());
editor.putString("user_head_url", myApp.getUser_head_url());
editor.putString("user_gender",myApp.getUser_gender());
editor.commit();
myApp.MakeToast("保存成功");
Log.d(TAG, "onNext: 保存成功");
EventBus.getDefault().post("change_user_info");
}
else{
myApp.MakeToast("保存失败");
Log.d(TAG, "onNext: 保存失败");
}
dialog_busying.dismiss();
}
});
上面是表单上传数据,如果是要JSON上传数据,则:
interface APIStore { @Headers({"Content-Type: application/json","Accept: application/json"})//需要添加头 @POST ("vdyweb/ws/rest/Login") Call<ResponseBody>getMessage(@Body RequestBody info); // 请求体味RequestBody 类型
PS:这里的数据类型是@Body,与表单不同
public class Info { String account; String password; public Info(String account, String password) { this.account = account; this.password = password; } }
Info info=new Info("test","123456"); /*** 利用Gson 将对象转json字符串*/ Gson gson=new Gson(); String obj=gson.toJson(info); retrofit=new Retrofit.Builder().baseUrl(BASE_LOGIN_URL).build(); RequestBody body=RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"),obj);
浙公网安备 33010602011771号