【问题标题】:Volley REST client using JSON使用 JSON 的 Volley REST 客户端
【发布时间】:2016-03-20 03:53:03
【问题描述】:

我想与仅以 JSON 响应的 RESTful Web 服务进行交互。 来自服务器的任何成功响应都具有以下语法:

{
    "code": int code,
    "data": object or list of objects
}

在错误响应时:

{
    "code": int code,
    "error": string,
    "details": string
}

所以我在我的 Android 项目中创建了两个这样的类(用于 GSON 反射):

public class ErrorEntity {
    private String details;
    private String error;
    private int    code;

    public ErrorEntity() {
        // Stub constructor
    }

    public String getDetails() {
        return details;
    }

    public String getError() {
        return error;
    }

    public int getCode() {
        return code;
    }
}

对于一个成功的响应,我做了一个通用的,因为我不想在覆盖的 parseNetworkResponse 上解析 JSON 数据:

public class SuccessfulEntity<T> {

    private T   data;
    private int code;

    public SuccessfulEntity() {
        // Stub content
    }

    public T getData() {
        return data;
    }

    public int getCode() {
        return code;
    }
}

现在,因为我的 RESTful 服务器需要一些自定义标头,所以我需要创建一个 Request 子类,但我不知道我需要从哪个类继承。
我看到了这个问题:Send POST request with JSON data using Volley,虽然做了类似的事情。

基本上,我想创建一个具有 GET、POST、DELETE 方法和 API 路由的新类 (VolleyRestClient),并通过该类发出我需要做的所有请求。

该类的方法需要发出一个新的自定义请求并解析新的对象响应,如 SuccessEntity 和 ErrorEntity,然后解析调用 VolleyRestClient 的服务/线程中的数据。

我该怎么做?

【问题讨论】:

  • 为什么不Entity&lt;T&gt; 拥有来自SuccessfulEntity&lt;T&gt;ErrorEntity 的所有道具......并使这些类中不常见的道具可选......并且用于错误检查entity.getError() != null
  • @Selvin 以及如何让 Class> 传递给 GSON 解析的自定义请求?
  • 以与您对 SuccessEntity 相同的方式...所以显然您应该在创建自定义请求之前知道 T 类型
  • 解决了创建 2 个单独的类,“SuccessfulObjEntity”和“SuccessfulListEntity”继承自 Entity 类,但是数据 obj/list 已经被 Gson 解析了,对吗?我只需要转换为适当的类型吗?

标签: java android json rest android-volley


【解决方案1】:

经过与泛型和类型擦除的长期斗争,我终于做到了。
所以我把这篇文章发给和我一样有同样问题并且需要解决方案的人。

我的ErrorEntity和我的SuccessfulEntity还是一样的,但是我新建了一个叫RepositoryListener的接口,像这样:

public interface RepositoryListener {
    public abstract void onErrorResponse(int code, String details);
    public abstract void onSuccessfulResponse(int code, Object obj);
    public abstract void onSuccessfulResponse2(int code, List<Object> obj);
}

然后我创建了一个类 VolleyRestClient,如下所示:

public class VolleyRestClient extends RestClient {

    private final DefaultRetryPolicy mRetryPolicy;
    private final RequestQueue       mQueue;
    private final Gson               gson = new Gson();

    public VolleyRestClient(Context context) {
        // Default retry policy
        mRetryPolicy = new DefaultRetryPolicy(2000, 3, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
        mQueue       = Volley.newRequestQueue(context);
    }

    public RequestQueue getQueue() {
        // Method to push requests for image download
        return mQueue;
    }

    @Override
    public void GET(boolean obj, boolean needAuth, String url, Type type,
                    RepositoryListener listener) {
        // Choose which listener to construct
        Response.Listener<myResponse> mListener = obj ?
                // This uses objects
                makeSuccessfulListener(listener, type) :
                // This uses list of objects
                makeSuccessfulListener2(listener, type);

        myRequest mRequest =
                new myRequest(Request.Method.GET, needAuth, url,
                        mListener, makeErrorListener(listener));

        mRequest.setRetryPolicy(mRetryPolicy);
        mQueue.add(mRequest);
    }

    @Override
    public void POST(boolean needAuth, String url, String body, Type type, RepositoryListener listener) {
        myRequest mRequest = new myRequest(Request.Method.POST, needAuth, url, body,
                        makeSuccessfulListener(listener, type), makeErrorListener(listener));

        mRequest.setRetryPolicy(mRetryPolicy);
        mQueue.add(mRequest);
    }

    @Override
    public void DELETE(boolean needAuth, String url, Type type, RepositoryListener listener) {
        myRequest mRequest =
                new myRequest(Request.Method.DELETE, needAuth, url,
                        makeSuccessfulListener(listener, type), makeErrorListener(listener));

        mRequest.setRetryPolicy(mRetryPolicy);
        mQueue.add(mRequest);
    }

    private Response.Listener<myRequest> makeSuccessfulListener
            (final RepositoryListener listener, final Type type) {
        // TODO: test this method and implement lists
        if (listener == null) {
            return null;
        } else {
            return new Response.Listener<myRequest>() {
                @Override
                public void onResponse(myRequest response) {
                    SuccessfulEntity<Object> obj = gson.fromJson(response.getBody(), type);
                    listener.onSuccessfulResponse(response.getCode(), obj.getData());
                }
            };
        }
    }

    private Response.Listener<myRequest> makeSuccessfulListener2
            (final RepositoryListener listener, final Type type) {
        // TODO: test lists
        if (listener == null) {
            return null;
        } else {
            return new Response.Listener<myRequest>() {
                @Override
                public void onResponse(myReqyest response) {
                    SuccessfulEntity<List<Object>> obj = gson.fromJson(response.getBody(), type);
                    listener.onSuccessfulResponse2(response.getCode(), obj.getData());
                }
            };
        }
    }

    private Response.ErrorListener makeErrorListener(final RepositoryListener listener) {
        return new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                try {
                    String jError = new String(error.networkResponse.data);
                    ErrorEntity mError = gson.fromJson(jError, ErrorEntity.class);
                    // Invoke listener closure
                    listener.onErrorResponse(error.networkResponse.statusCode, mError.getDetails());
                } catch (Exception e) {
                    listener.onErrorResponse(404, e.getMessage());
                }
            }
        };
    }
}

这取决于我的需要,但我会解释一般概念。

所以我有一个自定义请求,如我的问题中所述,我想将其解析为正确的数据类型。

更具体地说,我只能在 GET 请求(分页元素等)上拥有 JSONArray 数据,因此我需要找到一种方法来区分这两种情况(当然,我知道在哪些情况下我'会得到一个列表或一个对象)。

我们不能简单地在泛型类中使用其类型从 Json 创建 POJO(因为 Java 类型擦除),所以我们需要对象类型 预先
但我们能做的是:

  • 在我们的自定义请求中,在 parseNetworkResponse 上,执行以下操作:

    @Override
    protected Response<myResponse> parseNetworkResponse(NetworkResponse response) {
        try {
            // Using server charset
            myResponse mResponse = new myResponse();
    
            mResponse.setCode(response.statusCode);
            mResponse.setBody(new String(response.data,
                    HttpHeaderParser.parseCharset(response.headers)));
    
            // Return new response
            return Response.success(mResponse, HttpHeaderParser.parseCacheHeaders(response));
        } catch (UnsupportedEncodingException e) {
            // Normally use 'utf-8'
            return Response.error(new ParseError(e));
        }
    }
    

    换句话说,将原始字符串响应体复制到一个新对象myResponse

  • 响应正文最终将在 VolleyRestClient 中解析,并使用作为 GET/DELETE/POST 参数传递的适当类型;

  • makeSuccessfulListenermakeSuccessfulListener2 从 RepositoryListener 构造一个 Response.Listener,它有 3 个方法可以覆盖:onSuccessfulResponse 用于对象数据,onSuccessfulResponse2 用于对象数据列表,onErrorResponse 用于 4XX/5XX 错误;

    • 我们的数据对象/列表将被解析为更多的泛型类型(列表和对象),然后传递给我们的自定义侦听器 RepositoryListener。

此方法的完整示例:

public void getNewLogin(String nickname, String password,
                            final TextView author, final TextView title, final TextView text) {

        String json =
                (new StringBuilder()
                        .append("{ \"nickname\": \"")
                        .append(nickname)
                        .append("\", \"password\": \"")
                        .append(password)
                        .append("\" }")).toString();

        mRest.POST(false, "http://192.168.0.104:8000/api/session", json,
                new TypeToken<SuccessfulEntity<Login>>(){}.getType(),
                    new RepositoryListener() {
                        @Override
                        public void onSuccessfulResponse2(int code, List<Object> obj) {
                            // Nothing happens here
                        }

                        @Override
                        public void onSuccessfulResponse(int code, Object obj) {
                            UserSession mInstance = UserSession.getInstance(null);
                            Login newLogin = (Login) obj;

                            title.setText(newLogin.getToken());
                            mInstance.setToken(newLogin.getToken());

                            Log.i("onSuccessfulResponse", mInstance.getToken());
                            Log.i("onSuccessfulResponse", mInstance.getmAuthorizationToken());

                            if (newLogin.getUser() != null) {
                                author.setText(newLogin.getUser().getNickname());
                                text.setText(newLogin.getUser().getUniversity());
                            }
                        }

                        @Override
                        public void onErrorResponse(int code, String error) {
                            Log.i("onErrorResponse", error);
                        }
                    });

mRest 是一个 VolleyRestClient 对象,它使用由 Gson TypeToken 构造的 Type 向该地址执行 POST 请求(请记住,我们的主体是一个成功实体)。

由于我们肯定会有一个 Object 数据,我们只需覆盖 onSuccessfulResponse,将数据对象转换为 TypeToken 中使用的 SuccessEntity 的相同类型 T,然后完成我们的繁琐工作。 p>

我不知道我是否清楚,这种方法有效,如果你们中的一些人需要澄清,请问:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-18
    • 1970-01-01
    • 1970-01-01
    • 2021-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多