4

I'm trying to resolve a problem with the search bar. It works but the problem is that if I press two keys almost at the same time, the app will only search the words with the first key pressed.

Here are the logs:

In this one, it works when I press the P then R:

[EDT] 0:4:9,283 - p

[EDT] 0:4:9,348 - 10

[EDT] 0:4:9,660 - pr

[EDT] 0:4:9,722 - 3

The second one doesn't because I press P and R nearly at the same time:

[EDT] 0:4:35,237 - p

[EDT] 0:4:35,269 - pr

[EDT] 0:4:35,347 - 0

[EDT] 0:4:35,347 - 10

The logs here are generated to show the String searched and the result size. As you can see, the first case get results before typing the next char and the second case got all results when the two chars are typed.

The main problem is that in the second case, results from the 'p' String are shown instead of those of 'pr'.

I'm using the searchbar from the Toolbar API with addSearchCommand and an InfiniteContainer to show result data.

Could it be a problem in the order of the events from the addSearchCommand are treated ?

EDIT: Here is the client side code. Server side it's just a simple rest service call which fetch the data from the database.

public static ArrayList<Patient>getSearchedPatient(int index,int amount, String word)
{
    ArrayList<Patient> listPatient = null;
    Response reponse;
    try {
        reponse = RestManager.executeRequest(
            Rest.get(server + "/patients/search")
                .queryParam("index", String.valueOf(index))
                .queryParam("amount", String.valueOf(amount))
                .queryParam("word", word),
            RequestResult.ENTITIES_LIST,
            Patient.class);
        listPatient = (ArrayList<Patient>)reponse.getResponseData();
        Log.p(""+listPatient.size());
    } catch (RestManagerException e) {
        LogError("", e);
    }
    return listPatient; 
}

private static Response executeRequest(RequestBuilder req, RequestResult type, Class objectClass) throws RestManagerException
{
    
    Response response = null;
    try {
        switch (type) {
        case BYTES:
            response = req.getAsBytes();
            break;
        case JSON_MAP:
            response = req.acceptJson().getAsJsonMap();
            break;
        case ENTITY:
            response = req.acceptJson().getAsProperties(objectClass);
            break;
        case ENTITIES_LIST:
            response = req.acceptJson().getAsPropertyList(objectClass);
            break;
        default:
        case STRING:
            response = req.getAsString();
            break;
        }
    } catch (Exception e) {
        log().error("Erreur à l'exécution de la requête", e);
        response = null;
    }
    
    if(response == null)
        return null;
    
    
    return response;
        
}
Community
  • 1
  • 1
Farssi Issam
  • 173
  • 6
  • Is this in the simulator or devices? Notice that this behaves very differently on devices as you would be using the virtual keyboard on the device and input behavior on them is very different. – Shai Almog Feb 15 '19 at 04:05
  • this was on both. But still the same problem, even worse on the device because the problem appear with more time interval between entering the 2 keys. You have to know that i'm using a rest service every time i enter a letter in the search bar to get the right names. – Farssi Issam Feb 15 '19 at 12:44
  • In that case I'm guessing you are using addToQueueAndWait which might be impacting this. Try using this without the rest service and see if the input works properly. If so you should follow a different strategy – Shai Almog Feb 16 '19 at 05:25
  • But i'm obliged to use the rest service to get datas from the database. – Farssi Issam Feb 18 '19 at 16:07
  • 1
    The problem is the `AndWait` part. If it doesn't happen with a "mock" then that's the problem. In that case you should list the network code and I'll explain to you how you can fix it to work properly. – Shai Almog Feb 19 '19 at 03:25
  • ok i've edited my post to show you the concerned code – Farssi Issam Feb 21 '19 at 08:42

1 Answers1

1

So the trick here is a simple one. Don't make a request... Most users type fast enough to saturate your network connection speed so you will see completion suggestions referring to things that are no longer relevant.

This is a non-trivial implementation which I discuss in-depth in the Uber book where such a feature is implemented.

The solution is to send a request after a delay while caching responses to avoid double requests and ideally canceling request in progress when applicable. The solution in the Uber book does all 3 I'll try to cover just the basics in this mockup code. First you need a field for the timer and current request. Ideally you would also have a Map containing cached data:

private UITimer delayedRequest;
private String currentSearch;
private Map<String, String> searchCache = new HashMap<>();

Then you need to bind a listener like this:

tb.addSearchCommand(e -> {
    String s = (String)e.getSource();
    if(s == null) {
       if(delayedRequest != null) {
          delayedRequest.cancel();
          delayedRequest = null;
       }
       return;
    }
    if(currentSearch != null && s.equals(currentSearch)) {
       return;
    }
    if(delayedRequest != null) {
       delayedRequest.cancel();
       delayedRequest = null;
    }
    currenSearch = s;
    delayedRequest = UITimer.timer(100, false, () -> {
         doSearchCode();
    });
});

I didn't include here usage of the cache which you need to check within the search method and fill up in the result code. I also didn't implement canceling requests already in progress.

Shai Almog
  • 51,749
  • 5
  • 35
  • 65
  • Sorry to answer this late and thank you for your answer Shai. I've finally found the solution, i wanted to use timer as you did but my teacher didn't agree with it because it's not a constant solution, it can change according the devices. He told me that when i enter 2 characters in almost the same time, there is 2 threads which will handle both the sequence for the characters. For example : i enter RA, T1 -> R and T2 -> RA, so i've edited my code not continue the treatment with an exception by comparing, the current character : RA with the old character: R. – Farssi Issam Mar 01 '19 at 09:11
  • So i can keep the result search from the last characters in my container : RA – Farssi Issam Mar 01 '19 at 09:11
  • Hello Shai, is the solution from the Uber book also in the academy ? – Gauvain Klug Mar 01 '19 at 09:13
  • Yes I should also upload the full book PDF to the academy but didn't get around to do it yet – Shai Almog Mar 02 '19 at 04:59