1

I am using android Room and I have a boolean method that querys a DB through an Executor to see if an ID provided by the user is already used. everything works fine but sometimes the ansewer from the DB call arrives to late to the main thread meaning that my code doesnt know if the id is new or old. I want to make the code in the method wait until the runOnUiThread inside the executor has delivered a result for the rest of the method to work with.

//check id validity with two different error messages
    int isNew=-1;
    void setIsNewId(int result){
        isNew=result;
    }
    private boolean checkId(){
        String id=mId.getText().toString().trim();


        try{
            final int parseId=Integer.parseInt(id);

            AppExecutors.getInstance().diskIO().execute(new Runnable() {
                @Override
                public void run() {
                    final int result=mDb.clientDao().isIdNew(parseId);
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            setIsNewId(result);//<--THIS ARRIVES TOO LATE TO MAIN THREAD

                        }
                    });
                }
            });

            //THIS SHOULD WAIT UNTIL RESULT IS AVAILABLE
            if (isNew==1 && !id.isEmpty()){
                ilId.setErrorEnabled(false);
                return  true;
            }else  if(isNew==0){
                ilId.setErrorEnabled(true);
                ilId.setError("Id has to be new");
                mId.setError("Id needs to be new");
                Toast.makeText(this,"Id needs to be new", Toast.LENGTH_LONG).show();
                return false;
            }else{
                Toast.makeText(this,"its taking too long", Toast.LENGTH_LONG).show();
                return false;
            }

        }catch(Exception e){
            ilId.setErrorEnabled(true);
            ilId.setError("Id has to be numeric");
            mId.setError("Id has to be numeric");
            Toast.makeText(this,"Id needs to be numeric", Toast.LENGTH_LONG).show();
            return false;
        }
    }

I have already tried synchronizing on an object, using a mutex, a CountDownLatch,a sleep call. but all seem to freeze my UI and make my App crash. I know that executors have a submit() method but I have not been able to find an example about how to use it in the context of my nested thread. I am rather new to android and this is my first encounter with synchronization issues. maybe the solution is simple and i am just doing something wrong. any help is much appreciated

DaFois
  • 2,197
  • 8
  • 26
  • 43
quealegriamasalegre
  • 2,887
  • 1
  • 13
  • 35
  • Why u dont use `Async`? And put your db code inside `doInBackground`, even u can show progressbar before start reaching to db and at the end your `onPostExecute` part will be called which u can remove progressbar and run code block which needs execute after checking id (//THIS SHOULD WAIT UNTIL RESULT IS AVAILABLE) example: https://www.journaldev.com/9708/android-asynctask-example-tutorial – Vasif Nov 11 '18 at 21:52
  • @Vasif I understand I should use an executer as it will guarantee that there is always only one thread accessing the DB, which is important because of race conditions. I found this very enlightening post https://stackoverflow.com/questions/5999100/is-there-a-block-until-condition-becomes-true-function-in-java but I cant seem to make it work – quealegriamasalegre Nov 12 '18 at 00:58
  • I am thinking about just circumventing the problem by setting an onChangeListener on the field where the id is entered but it feels like a patch and i am sure there is a proper way to do it. besides I am definitely running into this issue again in the future – quealegriamasalegre Nov 12 '18 at 01:03
  • You can use special flag like `isInProgress` to force used only one thread – Vasif Nov 12 '18 at 11:48

0 Answers0