web-dev-qa-db-ja.com

改造と一元化されたエラー処理

サーバーへのリクエストごとにerror_code。 AsyncTaskを使用していたときにこれらのエラーを1か所で処理したい

public abstract class BaseAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {

    protected Context context;
    private ProgressDialog progressDialog;
    private Result result;

    protected BaseAsyncTask(Context context, ProgressDialog progressDialog) {
        this.context = context;
        this.progressDialog = progressDialog;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }

    @Override
    protected void onPostExecute(Result result) {
        super.onPostExecute(result);
        HttpResponse<ErrorResponse> response = (HttpResponse<ErrorResponse>) result;
     if(response.getData().getErrorCode() != -1) {
                handleErrors(response.getData());
        }else 
            onResult(result);

    }

    private void handleErrors(ErrorResponse errorResponse) {
    }
     public abstract void onResult(Result result);
    }

ただし、レトロフィットを使用すると、各リクエストにエラー処理コールバックがあります。

                    git.getFeed(user,new Callback<gitmodel>() {
                    @Override
                    public void success(gitmodel gitmodel, Response response) {

                    }

                    @Override
                    public void failure(RetrofitError error) {

                    }
                });
            }
        });

すべてのエラーを1か所で処理するにはどうすればよいですか?

18

「ロジック」エラーを取得する必要がある場合は、Javaロジックが必要です。これは、基本的にレトロフィット機能ではないためです。

  1. Retrofitコールバックを実装する実装コールバックを作成する
  2. 「isError」メソッドを定義する基本オブジェクトを作成します
  3. Retrofit OneではなくCallbackを取得するためにRetrofit RestAdapterを変更します

MyCallback.Java

_import Android.util.Log;
import retrofit.Callback;
import retrofit.client.Response;

public abstract class MyCallback<T extends MyObject> implements Callback<T> {

    @Override
    public final void success(T o, Response response) {
        if (o.isError()) {
            // [..do something with error]
            handleLogicError(o);
        }
        else {
            handleSuccess(o, response);
        }
    }

    abstract void handleSuccess(T o, Response response);

    void handleLogicError(T o) {
        Log.v("TAG", "Error because userId is " + o.id);
    }
}
_

MyObject.Java(Retrofitから取得するすべてのオブジェクトの基本クラス)

_public class MyObject {
    public long id;
    public boolean isError() {
        return id == 1;
    }
}
_

MyRealObject.Java-基本オブジェクトを拡張するクラス

_public class MyRealObject extends MyObject {
    public long userId;
    public String title;
    public String body;
}
_

RetroInterface.Java-あなたが精通している必要があるretrofitによって使用されるインターフェース

_import retrofit.http.GET;
import retrofit.http.Path;

public interface RetroInterface {

    @GET("/posts/{id}")
    void sendGet(@Path("id") int id, MyCallback<MyRealObject> callback);

}
_

そして最後に、すべてのロジックを使用するコード

_RestAdapter adapter = new RestAdapter.Builder()
    .setEndpoint("http://jsonplaceholder.typicode.com")
    .build();

RetroInterface itf = adapter.create(RetroInterface.class);
itf.sendGet(2, new MyCallback<MyRealObject>() {
    @Override
    void handleSuccess(MyRealObject o, Response response) {
        Log.v("TAG", "success");
    }

    @Override
    public void failure(RetrofitError error) {
        Log.v("TAG", "failure");
    }
});
_

このコードをコピーして貼り付けると、itf.sendGet(1, new MyCallback..)を実行するときにエラーが発生し、itf.sendGet(2, new MyCallback...)が成功します。

19
Mimmo Grottoli

正しく理解できていませんが、1つのコールバックを作成して、すべてのリクエストにパラメーターとして渡すことができます。

の代わりに:

git.getFeed(user,new Callback<gitmodel>() {
    @Override 
    public void success(gitmodel gitmodel, Response response) { 

    } 

    @Override 
    public void failure(RetrofitError error) { 

    }
}); 

まず、コールバックを定義します。

Callback<gitmodel> mCallback = new Callback<gitmodel>() {
    @Override 
    public void success(gitmodel gitmodel, Response response) { 

    } 

    @Override 
    public void failure(RetrofitError error) { 
        // logic to handle error for all requests
    } 
};

次に:

git.getFeed(user, mCallback);
7
Teo Inke

Retrofitでは、すべてのリクエストにErrorHandlerを指定できます。

public class ApiErrorHandler implements ErrorHandler {

    @Override
    public Throwable handleError(RetrofitError cause) {
        //here place your logic for all errors
        return cause;
    }
}

RestAdapterに適用します

RestAdapter.Builder()
            .setClient(client)
            .setEndpoint(endpoint)
            .setErrorHandler(errorHandler)
            .build();

あなたが求めていたものだと思います。

6
jakubbialkowski

Retrofit2では、メソッド.setErrorHandler()を使用してErrorHandlerを設定することはできませんが、アプリケーションの1か所に集中して発生する可能性のあるすべてのエラーをフォークするインターセプターを作成できます。

この例では、Retrofit2とOkHttpClientを使用したエラー処理のための1つの集中管理された場所があります。 Retrofitオブジェクト(retrofit)を再利用するだけです。

ネットワークおよびサーバーエラーのカスタムインターセプターを使用して、このスタンドアロンの例を試すことができます。これらは両方ともRetrofit2で異なる方法で処理されるため、サーバーから返されたエラーコードを応答コード(response.code())で確認し、応答が成功しなかったかどうか(!response.isSuccessful())を確認する必要があります。 。

ユーザーがネットワークまたはサーバーに接続していない場合は、メソッドResponse response = chain.proceed(chain.request());のIOExceptionをキャッチし、catchブロックでネットワークエラーを処理する必要があります。

HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
    loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

    OkHttpClient client = new OkHttpClient.Builder()
            .addInterceptor(loggingInterceptor)
            .addInterceptor(new Interceptor() {
                @Override
                public Response intercept(Chain chain) throws IOException {
                    try {
                        Response response = chain.proceed(chain.request());
                        if (!response.isSuccessful()) {
                            Log.e("tag", "Failure central - response code: " + response.code());
                            Log.e("tag", "central server error handling");

                            // Central error handling for error responses here:
                            // e.g. 4XX and 5XX errors
                            switch (response.code()) {
                                case 401:
                                    // do something when 401 Unauthorized happened
                                    // e.g. delete credentials and forward to login screen
                                    // ...

                                    break;
                                case 403:
                                    // do something when 403 Forbidden happened
                                    // e.g. delete credentials and forward to login screen
                                    // ...

                                    break;
                                default:
                                    Log.e("tag", "Log error or do something else with error code:" + response.code());

                                    break;
                            }
                        }

                        return response;
                    } catch (IOException e) {
                        // Central error handling for network errors here:
                        // e.g. no connection to internet / to server

                        Log.e("tag", e.getMessage(), e);
                        Log.e("tag", "central network error handling");

                        throw e;
                    }
                }
            })
            .build();

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("http://10.0.2.2:8000/api/v1/")
            .client(client)
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    UserRepository backendRepository = retrofit.create(UserRepository.class);
    backendRepository.getUser("userId123").enqueue(new Callback<UserModel>() {
        @Override
        public void onResponse(Call<UserModel> call, retrofit2.Response<UserModel> response) {
            Log.d("tag", "onResponse");

            if (!response.isSuccessful()) {
                Log.e("tag", "onFailure local server error handling code:" + response.code());
            } else {
                // its all fine with the request


            }
        }

        @Override
        public void onFailure(Call<UserModel> call, Throwable t) {
            Log.e("tag", "onFailure local network error handling");
            Log.e("tag", t.getMessage(), t);

        }
    });

UserRepositoryの例:

public interface UserRepository {
    @GET("users/{userId}/")
    Call<UserModel> getUser(@Path("userId") String userId);

}

UserModelの例:

public class UserModel implements Parcelable {
    @SerializedName("id")
    @Expose
    public String id = "";

    @SerializedName("email")
    @Expose
    public String mail = "";

    public UserModel() {

    }

    protected UserModel(Parcel in) {
        id = in.readString();
        mail = in.readString();
    }

    public static final Creator<UserModel> CREATOR = new Creator<UserModel>() {
        @Override
        public UserModel createFromParcel(Parcel in) {
            return new UserModel(in);
        }

        @Override
        public UserModel[] newArray(int size) {
            return new UserModel[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(id);
        dest.writeString(mail);
    }
}
2
Andrej1A

かなり単純に、カスタムエラー処理の例を改造します。ユーザーに表示されるエラーメッセージを表示するために、retrofit呼び出しの「failure」ハンドラーで多くの作業を行う必要がないように設定されています。すべてのエンドポイントで動作します。私たちのサーバーの人々があらゆる種類のランダムなものを送信することによって私たちのつま先を維持したいので、多くの例外処理があります..!

// on error the server sends JSON
/*
{ "error": { "data": { "message":"A thing went wrong" } } }
*/
// create model classes..
public class ErrorResponse {
    Error error;

    public static class Error {
        Data data;
        public static class Data {
            String message;
        }
    }
}

//
/**
 * Converts the complex error structure into a single string you can get with error.getLocalizedMessage() in Retrofit error handlers.
 * Also deals with there being no network available
 *
 * Uses a few string IDs for user-visible error messages
 */
private static class CustomErrorHandler implements ErrorHandler {
    private final Context ctx;

    public CustomErrorHandler(Context ctx) {
        this.ctx = ctx;
    }

    @Override
    public Throwable handleError(RetrofitError cause) {
        String errorDescription;
        if (cause.isNetworkError()) {
            errorDescription = ctx.getString(R.string.error_network);
        } else {
            if (cause.getResponse() == null) {
                errorDescription = ctx.getString(R.string.error_no_response);
            } else {
// Error message handling - return a simple error to Retrofit handlers..
                try {
                    ErrorResponse errorResponse = (ErrorResponse) cause.getBodyAs(ErrorResponse.class);
                    errorDescription = errorResponse.error.data.message;
                } catch (Exception ex) {
                    try {
                        errorDescription = ctx.getString(R.string.error_network_http_error, cause.getResponse().getStatus());
                    } catch (Exception ex2) {
                        Log.e(TAG, "handleError: " + ex2.getLocalizedMessage());
                        errorDescription = ctx.getString(R.string.error_unknown);
                    }
                }
            }
        }
        return new Exception(errorDescription);
    }
}

// When creating the Server...
retrofit.RestAdapter restAdapter = new retrofit.RestAdapter.Builder()
        .setEndpoint(apiUrl)
        .setLogLevel(retrofit.RestAdapter.LogLevel.FULL)
        .setErrorHandler(new CustomErrorHandler(ctx)) // use error handler..
        .build();
server = restAdapter.create(Server.class);
// Now when calling server methods, get simple error out like this:
server.postSignIn(login,new Callback<HomePageResponse>(){

    @Override
    public void success(HomePageResponse homePageResponse,Response response){
    // Do success things!
    }

    @Override
    public void failure(RetrofitError error){
        error.getLocalizedMessage(); // <-- this is the message to show to user.
    }
});
0
kuljeet singh