2016-06-02 2 views
2

다음 시나리오를 생각해 볼 수 있습니다.Retrofit2 서비스 인터페이스 구현

내 API 클라이언트로 Retrofit을 사용하고 있으며 SQLite 데이터베이스에서 로컬로 응답을 유지하기 위해 캐싱 메커니즘을 사용하려고합니다. 따라서 일부 데이터는 한 번만 얻을 수 있습니다. 네트워크를 사용할 수 없을 때 로컬 데이터베이스에서 데이터를 가져 오는 다음 인터페이스에 대한 사용자 지정 구현을 만드는 것이 완벽한 경우입니다.

public interface CommentsService { 
    @GET("posts/{postId}/comments") 
    Call<List<Comment>> getCommentsOfPost(@Path("postId") int id); 
} 

문제는 개조 이전 버전의 같은 매개 변수로 콜백을 통과하는 것을 방지하기 때문에 retrofit2의 모든 서비스 메소드가하는 Call 객체로 포장해야한다는 것입니다.

이 인터페이스의 사용자 지정 구현을 만드는 것이 좋은지 알고 싶습니다. 그렇다면 호출 개체를 어떻게 처리할까요?

답변

0

retrofit2에서는 Call.enqueue(Callback)을 사용하여 콜백을 지정할 수 있습니다. 예 :

getCommentsService.getCommentsOfPost(myInt).enqueue(new Callback() { 
    @Override 
    public void onResponse(Call call, Response response) { 
     // do something with the response 
    } 
} 

동기 실행을 원하면 Call.execute()을 사용하십시오.

+0

죄송합니다. 질문이 정확하지 않습니다. –

0

RxJava를 사용해 본 경험이 있다면 데이터를 가져 오는 동안 여러 작업을 결합하여 가능한 한 빨리 보여줄 수 있기 때문에 더 쉽게 될 것입니다. 그래서, 당신이해야 할 첫 번째 일은 데이터베이스에 API 결과를 저장하는 것입니다. 다음에 데이터를 표시하려면 concat 메소드를 호출하여 여러 소스 요청 (캐시, 디스크 또는 서버)을 연결하여 가능한 한 빨리 데이터를 검색하십시오.

여기에 대한 설명이 있습니다.

http://blog.danlew.net/2015/06/22/loading-data-from-multiple-sources-with-rxjava/ https://medium.com/@murki/chaining-multiple-sources-with-rxjava-20eb6850e5d9#.2u8zssice

+0

문제는 이미 개조 작업 중 일부 코드가 있다는 것입니다. 그래서 개조 인터페이스를 구현할 수있는 솔루션을 찾고 있습니다. –

+0

예, 이해합니다. RxJava로 개조 서비스를 구현하기 만하면됩니다. http://randomdotnext.com/retrofit-rxjava/ – ikhsan

0

네트워크를 사용할 수없는 경우에만 로컬 데이터베이스를 확인하고자하기 때문에, 당신은 또한 콜백 인터페이스를 구현하고 개조를하고 함수에 매개 변수로 전달 무엇을 할 수 요구. 이 방법을 사용하면 함수를 무효로 만들 수 있고 개조 호출의 onResonse 또는 onFailure 메서드 내부에서 성공적 응답 (onResponse) 또는 로컬 데이터베이스 (onFailure)에서로드할지 여부를 결정할 수 있습니다. 즉, 사용자 정의 인터페이스의 필수 기능을 호출하십시오. 이렇게하면 비동기 호출에서 개조 호출의 동기 동작을 모방하는 동시에 부적절한 응답을받을 때도 의사 결정을 내릴 수있는 유연성을 제공합니다.

1

만약 당신의 질문을 이해한다면, 네트워크 연결이없는 경우를 대비하여 SQLite로부터 데이터를 가져오고 싶습니다.

public interface GetCommentsService { 
    void getComments(int id, CommentsServiceResultListener listener); 
} 

CommentsServiceResultListener가 있습니다 :

public interface CommentsService { 
    @GET("posts/{postId}/comments") 
    Call<List<Comment>> getCommentsOfPost(@Path("postId") int id); 
} 

그런 다음 당신은 당신이 응용 프로그램의 다른 부분에서 사용하는 다른 인터페이스를 가지고해야합니다

당신은 당신이 당신의 엔드 포인트를 정의하는이 인터페이스를 가지고 리스너를 사용하여 이전 인터페이스의 구현으로 전달합니다. 다음과 같이 현실을 정의 할 수 있습니다 :

public interface CommentsServiceResultListener { 

    void onResponse(List<Comment> response); 

    void onError(String errorMessage); 
} 

, 당신은 실제로 데이터를 얻기 위해, 당신의 GetCommensService 인터페이스를 구현해야합니다.다음과 같이 할 수 있습니다.

public class GetCommensServiceImpl implemens GetCommensService { 
    private static final String TAG = BuildingsBaseServiceImpl.class.getSimpleName(); 

    @Override 
    public void getComments(int id, CommentsServiceResultListener listener) { 
     CommentsService service = getService(); 
     Call<List<Comment>> request = service.getCommentsOfPost(id); 
     request.enqueue(new Callback<List<Comment>>(){ 

      @Override //if this method is executed, the actual call has been made 
      public void onResponse(Call<List<Comment>> call, Response<List<Comment>> response) { 
       if (response.isSuccessful()) { 
        listener.onResponse(response.body()); 
       } else { 
        //TODO check here if the call wans't successful because a network problem. In that case, fetch from your SQLite 
        //Default unsuccessful call management 
        Log.e(TAG, response.code() + ": " + response.message()); 
        listener.onError(response.message()); 
       } 
      } 

      @Override //maybe the call couldn't be made because of lack of connection. 
      public void onFailure(Call<List<Comment>> call, Throwable t) { 
       //TODO check the failure cause, then decide if there's need to fetch from your SQLite. 
       //Default failure management 
       Log.e(TAG, t.getMessage() + "", t); 
       listener.onError(t.getMessage() + ""); 
      } 
     }); 
    } 

    private CommentsService getService() { 
     Retrofit retrofit = new Retrofit.Builder() 
       .baseUrl("http://your.base.url/") 
       .addConverterFactory(GsonConverterFactory.create()) //assuming JSON 
       .build(); 
     return retrofit.create(CommentsService.class); 
    } 
} 

희망이 있습니다.

0

그럼, Retrofit이 메커니즘 (예 : DB에서 오류로드시 특수 콜백을 전달)을 제공한다고 상상해보십시오. 때문에, 매우 구체적인 것 : 나는 보안 데이터

  • 를 들어, 토큰 업데이트하려면

    • 내가 특별한 데이터를 표시하려는 경우 연결을 수동으로
    • 을 다시 확인하려면
    • ...

    Retrofit을 사용하는 주된 작업은 연결 및 작업 상태에서 결과를 얻습니다. 그리고 그게 전부입니다.

    또한 질문에 대답하십시오. 네트 연결이없는 경우에 대비하여 고유 한 동작을 제공하고 onDataBaseLoadIfError()를 호출 할 수 있습니다. 오버라이드 된 Retrofit 클래스 - 전화하기.

    public interface CommentsServiceListener { 
    
        void onResponse(List<Comment> response); 
    
        void onError(String errorMessage); 
    
        void onDataBaseLoadIfError(String errorMessage); 
    } 
    
  • 4

    내 프로젝트 중 하나에서 비슷한 문제가있어서 RxJava를 사용할 수 없습니다. 명령 패턴을 사용하여이 문제를 해결했습니다.

    먼저, 사용자 정의 콜백 클래스를 명확한 API로 작성했습니다. 그렇게하면 HTTP 코드를보다 간결하게 처리 할 수 ​​있습니다 (예 : 400 또는 500). 대신 당신이 명령 인터페이스를 구현하고 그와 함께 작동합니다 개조 객체와 직접 작업,

    public interface Command { 
    
        // New network hit 
        void fresh(RestCallback callback); 
    
        // First cached if available then fresh 
        void all(RestCallback callback); 
    
        // Cached response only 
        void cached(RestCallback callback); 
    
        // If cache exists return it, otherwise return a fresh response 
        void get(RestCallback callback); 
    
        // Cancel the request 
        void cancel(); 
    
    } 
    

    이 방법 :

    public abstract class RestCallback<T> implements Callback<T> { 
    
        @Override 
        public void onResponse(Response<T> response, Retrofit retrofit) { 
         if (response != null) { 
          if (response.isSuccess()) { 
           onSuccess(response, retrofit); 
          } else { 
           onError(response, retrofit); 
          } 
         } else { 
          onFailure(null); 
         } 
        } 
    
        abstract public void onSuccess(Response<T> response, Retrofit retrofit); 
    
        abstract public void onError(Response<T> response, Retrofit retrofit); 
    
        abstract public void onFailure(Throwable t); 
    
    } 
    

    그때 나는 명령 인터페이스를 만들었습니다. 예를 들어 GetCommentsOfPostCommand를 만들고 요청 로직을 캡슐화하여 Retrofit Call 개체를 처리 할 수 ​​있습니다.

    Android Retrofit Command Pattern

    당신이 원하는대로 사용할 수 있습니다이 방법; 캐시, 요청, 취소 등을 구현하는 동시에 잘 정의 된 인터페이스를 제공합니다.

    희망이 도움이됩니다.

    +1

    아주 좋은 해결책을 가져 주셔서 감사합니다. 그러나이 솔루션의 단점은 내가 많은 여분의 접착제 코드를 얻게된다는 것입니다. 어떻게 든 프록시를 갱신하기 위해 이미 정의한 인터페이스를 구현할 수 있다면 구현 간을 쉽게 전환 할 수 있으므로 좋을 것입니다. –