Получение нулевых указателей от вызова API OkHttp3 в фоновом потоке

Я работаю над мобильным приложением, которое использует веб-сервис. Я использую шаблон MVP.

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

Как мне решить это? Код для вызова API работает очень хорошо, но похоже, что проблема в синхронизации.

Логин Код Класса Интерактора

public class LoginInteractorImpl implements LoginInteractor {

    private static final String TAG = LoginInteractorImpl.class.getName();
    private Handler mHandler;
    private HttpResponseResult httpResponseResult = null;
    private Gson mGson;
    private OkHttpRequestUtil okHttpRequestUtil = null;

    @Override
    public void login(final String username, final String password, final OnLoginFinishedListener listener, final LoginView mLoginView) {

        mGson = new Gson();
        mHandler = new Handler(Looper.getMainLooper());

        mHandler.post(new Runnable() {
            @Override
            public void run() {
                if (TextUtils.isEmpty(username)) {
                    listener.onUsernameError();
                    return;
                }
                if (TextUtils.isEmpty(password)) {
                    listener.onPasswordError();
                    return;
                }


            }
        });



        String postBody = mGson.toJson(new LoginRequestDTO(username, password));

        okHttpRequestUtil = new OkHttpRequestUtil();
        String url = Configuration.BASE_URL.concat(Configuration.FEED_LOGIN_URL);
        MediaType jsonMediaType = Configuration.JSON_MEDIA_TYPE;


        httpResponseResult = okHttpRequestUtil.DoPost(null, postBody, (Activity) mLoginView, listener, url, jsonMediaType);

        try {
            TransformJsonResponseToPojo(httpResponseResult, (Activity)mLoginView);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Метод DoPost класса OkHttpRequestUtil.

public class OkHttpRequestUtil {
    public static final String TAG = OkHttpRequestUtil.class.getName();

    OkHttpClient mClient = null;
    HttpResponseResult httpResponseResult = null;
    private Handler mHandler;

    public HttpResponseResult DoPost(final Map<String, String> headers, String postBody, Context context, final LoginInteractor.OnLoginFinishedListener listener, String url, MediaType jsonMediaType) {

        HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
        Request request = null;
        String processedUrl = urlBuilder.build().toString();
        RequestBody body = RequestBody.create(jsonMediaType, postBody);

        mHandler = new Handler(Looper.getMainLooper());


        if (headers != null) {
            Headers headerBuild = Headers.of(headers);

            request = new Request.Builder()
                    .headers(headerBuild)
                    .url(processedUrl)
                    .post(body)
                    .build();

        }
        else
        {
            request = new Request.Builder()
                    .url(processedUrl)
                    .post(body)
                    .build();
        }


        try {
            mClient = new OkHttpClient.Builder()
                    .connectTimeout(30, TimeUnit.SECONDS)
                    .readTimeout(30, TimeUnit.SECONDS)
                    .writeTimeout(30, TimeUnit.SECONDS)
                    .sslSocketFactory(CustomTrust.getPinnedCertSslSocketFactory(context), (X509TrustManager) CustomTrust.getTrustManagerFactory(context).getTrustManagers()[0])
                    .build();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (CertificateException e) {
            e.printStackTrace();
        }

        mClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                call.cancel();
                e.printStackTrace();
            }

            @Override
            public void onResponse(Call call, final Response response) throws IOException {
                // ... check for failure using `isSuccessful` before proceeding
                if (!response.isSuccessful()) {
                    Log.i(TAG, response.toString());
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            listener.onPasswordError();
                            try {
                                throw new IOException("Unexpected code " + response);
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    });



                }
                // Populate the HttpResponseResult

                httpResponseResult = new HttpResponseResult();
                httpResponseResult.setCode(String.valueOf(response.code()));
                httpResponseResult.setMessage(response.message());
                httpResponseResult.setBodyString(response.body().string());


                Headers okHttpResponseHeaders = response.headers();
                Map<String, String> responseHeadersTemp = new HashMap<String, String>();

                for(int i = 0; i < okHttpResponseHeaders.size(); i++)
                {
                    responseHeadersTemp.put(okHttpResponseHeaders.name(i), okHttpResponseHeaders.value(i));
                }

                httpResponseResult.setHeaders(responseHeadersTemp);

                listener.onSuccess();

            }
        });

        return httpResponseResult;
    }
}

1 ответ

Решение

По сути, ваш код работает так, как будто ваш оператор возврата происходит до завершения этой очереди Callback

mClient.newCall(request).enqueue

Сделав HTTP-ответ пустым, да.

Решение было бы сделать DoPost ничего не возвращайте (и не пишите заглавными буквами имена методов, пожалуйста). Тип метода должен быть void,

Верните свои результаты из onResponse через параметр для listener.onSuccess(responseData);

И вы можете сразу же проанализировать ответ, не нужно копировать весь HTTP-ответ с заголовками и всем

Другие вопросы по тегам