如何使用 moshi、retrofit 和 java 处理包装数据?
how can I work with wrapped data using moshi, retrofit and java?
我正在使用 API,其中所有数据都包含在自定义 object 中(见下文),因此我无法使用 moshi 将改造体直接转换为我的模型。在这种情况下,使用 moshi 的最佳方式是什么?
#COLLECTIONS ENDPOINT
{
"status": 200,
"data": [
{
"id": 28122,
"name": "Abandonei",
"counts": {
"books": 3
}
},
{
"id": 21091,
"name": "Lendo",
"counts": {
"books": 6
}
},
],
"errors": [],
"pagination": {
"after": 2,
"hasNextPage": true
}
}
所有api端点使用相同的json结构,默认字段为:
{
"status": 200,
"data": [],
"errors": [],
"pagination": {
"after": 1,
"hasNextPage": true
}
}
我的Collection模特:
public class BookCollection {
public long id;
public String name;
public ArrayList<Book> books;
public BookCollection(long id, String name) {
this.id = id;
this.name = name;
}
}
您将需要设置 gson/moshi 以使用您为 json 对象映射创建的 类。这是 java 类 的示例。您也可以在 kotlin 中使用数据 类。对于 moshi,您必须创建适配器以帮助 json 到对象映射。
publci class CollectionResponse {
public int status;
public List<BookCollection> data;
public List<Error> errors;
public Pagination pagination;
}
public class Pagination {
public int after;
public boolean hasNextPage;
}
public class BookCollection {
public long id;
public String name;
public Count counts;
}
public Count {
public int books;
}
public class Error {
}
为了避免为每个模型创建一个父 class,我实现了一种使用 class 接收通用类型的方法。
为了让它工作,我将 Moshi class 更改为 Gson。
我的模特:
public class BookCollection {
public long id;
public String name;
public ArrayList<Book> books;
public BookCollection(long id, String name) {
this.id = id;
this.name = name;
}
}
用于解包 json 数据的包装器 class:
public class ApiWrapper<T> {
public final int status;
public final T data;
public final List<ApiError> errors = new ArrayList<>();
public ApiWrapper(int status, T data, List<ApiError> errors) {
this.status = status;
this.data = data;
this.errors.addAll(errors);
}
}
上面 class 中引用的错误 class:
public class ApiError {
public int code;
public String message;
public String error;
}
用法:
public interface NetAPI {
@GET("me/collections")
Call<ResponseBody> getCollections(@Header("Authorization") String auth);
}
public class CollectionViewModel extends ViewModel {
private final MutableLiveData<List<Collection>> collections = new MutableLiveData<>();
private final MutableLiveData<Boolean> loading = new MutableLiveData<>();
private final MutableLiveData<Boolean> collectionError = new MutableLiveData<>();
private Call<ResponseBody> call;
private void fetchCollections() {
loading.setValue(true);
call = Api.getInstance().getCollections(TOKEN);
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
try {
collectionError.setValue(false);
//THE SECRET
Gson gson = new Gson();
ApiWrapper<List<Collection>> apiResponse = null;
apiResponse = gson.fromJson(response.body().string(), new TypeToken<ApiWrapper<List<Collection>>>(){}.getType());
collections.setValue(apiResponse.data);
loading.setValue(false);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.e(getClass().getSimpleName(), "Error loading data", t);
collectionError.setValue(true);
loading.setValue(false);
}
});
}
}
通过这种方式,我可以将我的 ApiWrapper class 重新用于任何模型(图书、用户、登录等)。
谢谢。
我正在使用 API,其中所有数据都包含在自定义 object 中(见下文),因此我无法使用 moshi 将改造体直接转换为我的模型。在这种情况下,使用 moshi 的最佳方式是什么?
#COLLECTIONS ENDPOINT
{
"status": 200,
"data": [
{
"id": 28122,
"name": "Abandonei",
"counts": {
"books": 3
}
},
{
"id": 21091,
"name": "Lendo",
"counts": {
"books": 6
}
},
],
"errors": [],
"pagination": {
"after": 2,
"hasNextPage": true
}
}
所有api端点使用相同的json结构,默认字段为:
{
"status": 200,
"data": [],
"errors": [],
"pagination": {
"after": 1,
"hasNextPage": true
}
}
我的Collection模特:
public class BookCollection {
public long id;
public String name;
public ArrayList<Book> books;
public BookCollection(long id, String name) {
this.id = id;
this.name = name;
}
}
您将需要设置 gson/moshi 以使用您为 json 对象映射创建的 类。这是 java 类 的示例。您也可以在 kotlin 中使用数据 类。对于 moshi,您必须创建适配器以帮助 json 到对象映射。
publci class CollectionResponse {
public int status;
public List<BookCollection> data;
public List<Error> errors;
public Pagination pagination;
}
public class Pagination {
public int after;
public boolean hasNextPage;
}
public class BookCollection {
public long id;
public String name;
public Count counts;
}
public Count {
public int books;
}
public class Error {
}
为了避免为每个模型创建一个父 class,我实现了一种使用 class 接收通用类型的方法。
为了让它工作,我将 Moshi class 更改为 Gson。
我的模特:
public class BookCollection {
public long id;
public String name;
public ArrayList<Book> books;
public BookCollection(long id, String name) {
this.id = id;
this.name = name;
}
}
用于解包 json 数据的包装器 class:
public class ApiWrapper<T> {
public final int status;
public final T data;
public final List<ApiError> errors = new ArrayList<>();
public ApiWrapper(int status, T data, List<ApiError> errors) {
this.status = status;
this.data = data;
this.errors.addAll(errors);
}
}
上面 class 中引用的错误 class:
public class ApiError {
public int code;
public String message;
public String error;
}
用法:
public interface NetAPI {
@GET("me/collections")
Call<ResponseBody> getCollections(@Header("Authorization") String auth);
}
public class CollectionViewModel extends ViewModel {
private final MutableLiveData<List<Collection>> collections = new MutableLiveData<>();
private final MutableLiveData<Boolean> loading = new MutableLiveData<>();
private final MutableLiveData<Boolean> collectionError = new MutableLiveData<>();
private Call<ResponseBody> call;
private void fetchCollections() {
loading.setValue(true);
call = Api.getInstance().getCollections(TOKEN);
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
try {
collectionError.setValue(false);
//THE SECRET
Gson gson = new Gson();
ApiWrapper<List<Collection>> apiResponse = null;
apiResponse = gson.fromJson(response.body().string(), new TypeToken<ApiWrapper<List<Collection>>>(){}.getType());
collections.setValue(apiResponse.data);
loading.setValue(false);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.e(getClass().getSimpleName(), "Error loading data", t);
collectionError.setValue(true);
loading.setValue(false);
}
});
}
}
通过这种方式,我可以将我的 ApiWrapper class 重新用于任何模型(图书、用户、登录等)。
谢谢。