Синхронный запрос залпа блокируется - PullRequest
0 голосов
/ 11 декабря 2018

Я пытаюсь реализовать «живую» проверку ввода.Проблема, с которой я столкнулся некоторое время назад, заключается в том, как вживую проверить, существует ли имя пользователя в базе данных.

Для всех запросов базы данных я использую Volley POST для PHP API, что привело к:

private boolean checkTaken(String username, Context context){
    boolean taken;
    Volley.getInstance(context).addToRequestQueue(new StringRequest(Request.Method.POST, url, output -> taken = output.contains("taken"), error -> {}) {
        @Override
        protected Map<String, String> getParams() {
            Map<String, String> params = new HashMap<>();
            params.put("username", username);
            return params;
        }
        @Override
        public Map<String, String> getHeaders() {
            Map<String, String> params = new HashMap<>();
            params.put("Content-Type", "application/x-www-form-urlencoded");
            return params;
        }
    });
    return taken;
}

Это было бы замечательно, но не сработало, потому что оператор return был достигнут задолго до получения ответа API.Именно тогда я обнаружил RequestFutures и попытался реализовать их, как я увидел здесь :

 private boolean checkTaken(String username, Context context){

    RequestFuture<String> taken = RequestFuture.newFuture();

    Volley.getInstance(context).addToRequestQueue(new StringRequest(Request.Method.POST, url, taken, error -> {}) {
        @Override
        protected Map<String, String> getParams() {
            Map<String, String> params = new HashMap<>();
            params.put("username", username);
            return params;
        }
        @Override
        public Map<String, String> getHeaders() {
            Map<String, String> params = new HashMap<>();
            params.put("Content-Type", "application/x-www-form-urlencoded");
            return params;
        }
    });
    try {
        return taken.get(500, TimeUnit.MILLISECONDS).contains("taken");
    } catch (InterruptedException | ExecutionException | TimeoutException e) {
        return false;
    }
}

К сожалению, это не сработает, даже если я увеличу время ожидания до невыносимой суммы, taken.get() никогда не решается.Я думаю, это потому, что taken, используемый в запросе, интерпретируется как новая переменная для вывода, а не как фактический запрос FutureRequest.

Я был бы очень благодарен за подсказку, почему это не работает, или за другое решение моей проблемы.

Вызов метода:

if (!email.matches(regex)){
    return "Username has an invalid format";
} else if (checkTaken(username, context)){
    return "Username already taken";
} else{
    return null;
}

1 Ответ

0 голосов
/ 11 декабря 2018
private void checkTaken(String username, Context context, Callback callback){
    boolean taken;
    Volley.getInstance(context).addToRequestQueue(new StringRequest(Request.Method.POST, url, 
        output -> callback.done(output.contains("taken")), 
        error -> {
           // TODO handle this error
        }) {
        @Override
        protected Map<String, String> getParams() {
            Map<String, String> params = new HashMap<>();
            params.put("username", username);
            return params;
        }
        @Override
        public Map<String, String> getHeaders() {
            Map<String, String> params = new HashMap<>();
            params.put("Content-Type", "application/x-www-form-urlencoded");
            return params;
        }
    });
}

Определите свой интерфейс обратного вызова и передайте лямбда-выражение от того, куда вы звоните checkTaken:

// This method wherever this is defined also needs to accept a callback so it can be asynchronous
public void whatever(StringCallback callback) {
    // ...
    if (!email.matches(regex)){
        callback.done("Username has an invalid format");
    } else {
        checkTaken(username, context, taken -> 
                 callback.done(taken ? "Username already taken" : null));
    } 

И затем, куда бы вы ни позвонили:

whatever(error -> {
    if(error == null) {
        handleSuccess();
    }
    else {
        handleError(error);
    }
 );

Это может показаться раздражающей и сложной цепочкой изменений, которые вы должны внести, но когда вы переходите от синхронного к асинхронному, часто возникает много волновых эффектов, и, поскольку вы не можете выполнять сетевые операции в основном потоке в Android, вычасто пишут асинхронные методы.

...