2015-12-14 4 views
3

Я хочу взаимодействовать с веб-сервисом RESTful, который отвечает только в JSON. Любой успешный ответ от сервера имеет следующий синтаксис:Клиент Volley REST с использованием JSON

{ 
    "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; 
    } 
} 

Для успешного ответа я сделал общий, потому что я не хочу анализировать данные JSON на переопределенном parseNetworkResponse:

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 и хотя делать что-то подобное.

В принципе, я хочу создать новый класс (VolleyRestClient), который имеет методы GET, POST, DELETE и API, и с этим классом делать все запросы, которые мне нужно сделать.

Методы этого класса должны создавать новый пользовательский запрос и анализировать ответы на новые объекты, такие как SuccessfulEntity и ErrorEntity, а затем анализировать данные в сервисе/потоке, которые вызывают вызов VolleyRestClient.

Как я могу это сделать?

+0

почему не '' Entity который будет иметь все реквизиты из '' SuccessfulEntity и 'ErrorEntity' ... и создавать реквизиты, которые не являются обычными в этих классах, необязательно ... и для проверки ошибок вы должны использовать' entity.getError()! = Null' – Selvin

+0

@Selvin и как мне получить класс > пройти к пользовательскому запросу для разбора GSON? –

+0

так же, как вы хотите сделать с SuccessfulEntity ... так что вы должны знать тип T перед созданием пользовательского запроса – Selvin

ответ

0

После долгой битвы с дженериками и стиранием стилей я, наконец, сделал это.
Итак, я публикую это для тех, кто имеет такую ​​же проблему, как я, и нуждается в решении, не волнуясь.

Мои 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()); 
       } 
      } 
     }; 
    } 
} 

Это очень зависит от моих потребностей, но я объясню общую концепцию.

Итак, у меня есть пользовательский запрос, как объяснялось в моем вопросе, и я хочу проанализировать его на правильный тип данных.

Чтобы быть более конкретным, я мог бы иметь данные JSONArray только для запросов GET (разбитые на страницы элементы и т. Д.), Поэтому мне нужно найти способ различать эти два случая (конечно, я знаю, в каких случаях Я получу список или объект).

Мы не можем просто создать POJO из Json в универсальном классе, используя его тип (поскольку Java Type Erasure), поэтому нам нужен тип объекта upfront.
Но что мы можем сделать, это:

  • в нашем пользовательском запросе, на 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 аргумент;

  • makeSuccessfulListener и makeSuccessfulListener2 построить Response.Listener из RepositoryListener, который имеет 3 метода переопределять: onSuccessfulResponse для данных объектов, onSuccessfulResponse2 для списка данных объектов, onErrorResponse для 4XX/Ошибки 5XX;

    • Наш объект/список данных будет анализироваться на более универсальный тип (список и объект), а затем передан нашему пользовательскому ресепозитору ListenerListener.

Полный пример такого подхода:

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 объект, который выполняет запрос POST на этот адрес с типом построенного Gson TypeToken (помните, наш организм - это SuccessfulEntity).

Поскольку у нас будет объект данных, конечно, мы будем просто переопределить onSuccessfulResponse, литая объект данных к тому же типа Т SuccessfulEntity, используемого в TypeToken, и сделать нашу грязную работу.

Я не знаю, был ли я ясно, этот подход работает, если некоторые из вас нуждается в некотором уточнении, просто спросить :)

Смежные вопросы