2017-07-03 1 views
1

を呼び出します。レトロフィットRxAndroidは、APIのラッパーを作る私は共通の場所で&ハンドル共通の応答をProgressDialogを表示することができるように改造してAPI呼び出しのためのラッパーを作成したい

私は上記のコードでこの

public static <T> Observable<T> callApiWrapper(final Context context, 
                final boolean shouldShowProgress, 
                final String message, 
                final Observable<T> source) { 

     final ProgressDialog progressDialog = new ProgressDialog(context); 
     if (shouldShowProgress) { 
      if (!TextUtils.isEmpty(message)) 
       progressDialog.setMessage(message); 
      else 
       progressDialog.setMessage(context.getString(R.string.please_wait)); 
     } 


     return source.lift(new Observable.Operator<T, T>() { 
      @Override 
      public Subscriber<? super T> call(final Subscriber<? super T> child) { 
       return new Subscriber<T>() { 
        @Override 
        public void onStart() { 
         super.onStart(); 

         if (shouldShowProgress) { 
          new Handler(Looper.getMainLooper()).post(new Runnable() { 
           @Override 
           public void run() { 
            progressDialog.show(); 
           } 
          }); 
         } 

         child.onStart(); 
        } 

        @Override 
        public void onCompleted() { 
         if (shouldShowProgress && progressDialog.isShowing()) 
          progressDialog.dismiss(); 
         child.onCompleted(); 
        } 

        @Override 
        public void onError(Throwable e) { 
         if (shouldShowProgress && progressDialog.isShowing()) 
          progressDialog.dismiss(); 
         child.onError(e); 
        } 

        @Override 
        public void onNext(T t) { 

         /* 
          Handle Invalid API response 
         */ 

         if (((BaseResponse) t).getStatus() == RestParams.Codes.INVALID_API_KEY) { 
          mCommonDataModel.setApiKey(""); 
          getCommonApiService().getApiKey() 
            .subscribeOn(Schedulers.newThread()) 
            .observeOn(AndroidSchedulers.mainThread()) 
            .subscribe(new Subscriber<ResponseBody>() { 
             @Override 
             public void onCompleted() { 

             } 

             @Override 
             public void onError(Throwable e) { 

             } 

             @Override 
             public void onNext(ResponseBody responseBody) { 

              try { 
               String response = responseBody.string(); 
               JSONObject jsonObject = new JSONObject(response); 
               String key = jsonObject.optString("KEY"); 

               if (!TextUtils.isEmpty(key)) 
                mCommonDataModel.setApiKey(key); 

               callApiWrapper(context, shouldShowProgress, 
                 message, source) 
                 .subscribeOn(Schedulers.newThread()) 
                 .observeOn(AndroidSchedulers.mainThread()) 
                 .subscribe(); 
              } catch (Exception e) { 
               e.printStackTrace(); 
              } 
             } 
            }); 
         } else { 
          if (shouldShowProgress && progressDialog.isShowing()) 
           progressDialog.dismiss(); 


          child.onNext(t); 
         } 

        } 
       }; 
      } 
     }); 

    } 

のようなラッパーを作成することによって、これを達成し、私は、無効なAPI KEYのような特定のステータスコードを取得する場合、私は新しいAPIキーを取得するためのAPIを呼び出していますことを確認してください元の加入者に直接ステータスを与えるのではなく、

私は成功した新しいAPIキーを取得したら、私は再帰的にラッパーを呼び出す&元加入者への応答を与えることを試みます。しかし、問題は、オリジナル加入者は、私がここで行方不明です何onNextコールバック

を取得していないのですか?私がやろうとしていることを達成する他の方法はありますか?あなたは、サブスクリプションを開始したときに、それを閉じたときに副作用がすなわちプログレスバーを有効に追加するには

source.flatMap(
    t -> 
    { 
     if (((BaseResponse) t).getStatus() == RestParams.Codes.INVALID_API_KEY) { 
      return Observable.error(new InvalidKeyException("The key is not valid")); 
     } 
     else { 
      return Observable.just(t); 
     } 
    } 
) 
.retryWhen(
    errors -> 
     errors.flatMap(error -> { 

      if (error instanceof InvalidKeyException()) { 
       return getCommonApiService().getApiKey()           
              .flatMap(
               responseBody -> { 
                String response = responseBody.string(); 
                JSONObject jsonObject = new JSONObject(response); 
                String key = jsonObject.optString("KEY"); 

                if (TextUtils.isEmpty(key)) 
                 return Observable.error(); 
               else { 
                return Observable.just(key); 
               }}) 
              .doOnNext(key -> mCommonDataModel.setApiKey(key)); 
      } 
      // For anything else, don't retry 
      return Observable.error(error); 
     })) 
.subscribe(/* do what you need to do with the results*/)   

のようなものので、無効なキーの失敗を取得した場合に、いくつかの再試行ロジックを追加する必要が

+0

は思えます。 1つはあなたの副作用で、もう1つは最初のAPIキーが無効な場合に新しいAPIキーを取得しています。どちらにもラッパーは必要ありません。 – JohnWowUs

+0

それは無効である可能性がありますが、私はこの方法でそれを処理するために求められますので、APIが開発される方法を制御できません。すべてのAPIレスポンスで検証を繰り返すのではなく、一般的なラッパーが意味を成す他のバリデーションもあります。副作用に関しては、私はあなたを得ていませんでした。これがより良い方法でどのように行われるのか説明してください。感謝:) –

答えて

0

のようなものを終えまし。この種のラッパーは、多くの場合に便利です。私はこのラッパーを実装&物事を理解するために助けた彼の答えのための@JohnWowUsに感謝します。ここで

は、作業コードは、これは通常のように同じです使用して

private static final int MAX_RETRIES = 2; 
private static int sCurrentRetryAttempt = 0; 

/** 
    * Common Wrapper for calling API. 
    * 
    * @param context   context for showing progress dialog 
    * @param shouldShowProgress boolean which indicated if progress dialog should be shown or not 
    * @param message   message to be shown in progress dialog. if null passed, then "Please wait..." will be shown 
    * @param source    original observable 
    * @return observable to which observer can subscribe 
    */ 
    public static <T> Observable<T> callApiWrapper(final Context context, 
                 final boolean shouldShowProgress, 
                 final String message, 
                 final Observable<T> source) { 

     // Progress Dialog 
     final ProgressDialog progressDialog = setupProgressDialog(context, shouldShowProgress, message); 
     if (progressDialog != null) progressDialog.show(); 

     return source 
       .subscribeOn(Schedulers.newThread()) 
       .observeOn(AndroidSchedulers.mainThread()) 
       .flatMap(new Func1<T, Observable<T>>() { 
        @Override 
        public Observable<T> call(T t) { 

         /* 
         * Check if the response contains invalid key status code. 
         */ 

         if (t instanceof BaseResponse) { 
          if (((BaseResponse) t).getStatus() == RestParams.Codes.INVALID_API_KEY) { 
           return Observable.error(new InvalidKeyException("Invalid key")); 
          } 
         } 

         /* 
         * We are here, that means, there wasn't invalid key status code. 
         * So we wouldn't like to handle it so just return to original subscriber 
         */ 
         if (progressDialog != null && progressDialog.isShowing()) 
          progressDialog.dismiss(); 

         return Observable.just(t); 
        } 
       }).retryWhen(new Func1<Observable<? extends Throwable>, Observable<?>>() { 
        @Override 
        public Observable<?> call(Observable<? extends Throwable> observable) { 

         return observable.flatMap(new Func1<Throwable, Observable<?>>() { 
          @Override 
          public Observable<?> call(final Throwable throwable) { 
           if (throwable instanceof InvalidKeyException) { 
            /* 
            * Check for retry limit. if we already have retried enough, then 
            * we should tell the original subscriber about the error as it 
            * doesn't seems recoverable. 
            */ 
            if (sCurrentRetryAttempt >= MAX_RETRIES) { 
             if (progressDialog != null && progressDialog.isShowing()) 
              progressDialog.dismiss(); 

             //Resetting the attempts to 0 
             sCurrentRetryAttempt = 0; 
             return Observable.error(throwable); 
            } 

            //Increase the attempt counter 
            sCurrentRetryAttempt += 1; 
            return getCommonApiService().getApiKey() 
              .subscribeOn(Schedulers.newThread()) 
              .observeOn(AndroidSchedulers.mainThread()) 
              .flatMap(new Func1<ResponseBody, Observable<?>>() { 
               @Override 
               public Observable<?> call(ResponseBody responseBody) { 
                try { 
                 /* 
                 * Check if we succeed in our attempt to handle 
                 * invalid key 
                 */ 
                 if (processApiKey(responseBody)) { 

                  /* 
                  * We succeeded in our attempts to handle 
                  * invalid api key, so we will return the 
                  * original subscriber what it wanted. 
                  */ 
                  return callApiWrapper(context, 
                    shouldShowProgress, message, source); 
                 } else 
                  return Observable.just(throwable); 
                } catch (Exception e) { 
                 /* 
                 * We are here that means something went wrong, 
                 * so we will retry silently. 
                 */ 
                 return Observable.just(throwable); 
                } 
               } 
              }); 
           } else { 
            /* 
            * For any other error, we are not going to handle right now, 
            * so just return 
            */ 
            return Observable.error(throwable); 
           } 

          } 
         }); 
        } 
       }); 
    } 

&です:あなたは二つの別々の問題を持っているよう

RestClient.callApiWrapper(mContext, true, null, 
       RestClient.getAuthenticationApiService().socialLogIn(name, email, singInVia, mobile, "android", deviceToken)) 
       .subscribeOn(Schedulers.newThread()) 
       .observeOn(AndroidSchedulers.mainThread()) 
       .subscribe(new Subscriber<BaseResponse<RegistrationResponse>>() { 
//... 
} 
1

「最後に、私は私のために無効なキーAPIレスポンスの場合の一般的なプログレスバー&再試行ロジックを処理するラッパーを作成するために管理

modifiedSource.doOnSubscribe(/* progress bar show logic */) 
       .doOnTerminate(/* progress bar dismiss logic */) 
+0

はい、私はこのように私はどこにでもコードを繰り返し記述する必要がありますので、無効なキーの例外を取得することができ、この方法ではなく、任意のAPIとして、これを行うことができます。そのため、私はラッパーを作成したいのです。 –

関連する問題