同步排球请求锁定

问题描述 投票:1回答:1

我正在尝试实现“实时”输入验证。我现在面临的问题是如何检查用户名是否已存在于数据库中。

对于所有数据库请求,我使用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;
}

哪个会很好但不起作用,因为在API响应到达之前很久就已达到return语句。就在那时我发现了RequestFutures并试图实现它们,因为我看到了here

 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;
}
android android-volley synchronous
1个回答
1
投票
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;
        }
    });
}

定义你的Callback接口,并从你调用checkTaken的任何地方传入一个lambda表达式:

// 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的主线程上进行网络操作,你将会经常发现自己编写异步方法。

© www.soinside.com 2019 - 2024. All rights reserved.