Change variable value inside anonymous class

0

I would like to know the reason that whenever inside an anonymous class I try to change the value of an "external" variable it does not, changes remain the same. Would there be something similar that could do that would give the same result?

I used Thread as an example, but in any anonymous class this happens. (Including Android)

public class Teste {

    public boolean umIgualUm = false;

    public Teste() {
        fazerAlgo();
    }

    public void fazerAlgo() {

        new Thread() {
            public void run() {
                if (1 == 1) {
                    System.out.println("Entra aqui");
                    umIgualUm = true;
                }
            }
        }.start();

        System.out.println(umIgualUm); //Exibe false

    }

}

Android example

public class UsuarioDAO {

    public boolean metodoDeuCerto = false;

    public UsuarioDAO(){}

    public boolean cadastrarUsuario(Usuario usuario) {

        ParseUser parseUser = new ParseUser();
        parseUser.setUsername(usuario.getNome());
        parseUser.setEmail(usuario.getEmail());
        parseUser.setPassword(usuario.getSenha());

        parseUser.signUpInBackground(new SignUpCallback() {
            @Override
            public void done(ParseException e) {
                if(e == null) { //Quer dizer que deu certo
                    metodoDeuCerto = true;
                }else{
                    e.printStackTrace();
                    metodoDeuCerto = false;
                }

            }

        });

        return metodoDeuCerto;

    }
}
    
asked by anonymous 22.08.2017 / 21:58

2 answers

0

There are two issues here:

  • The start method may take a long time to actually start the new thread. With this, System.out may end up running first.

  • Variables can stay in thread-specific caches, and with this, different threads can see different values for the same variable at the same time. To work around this problem you can use synchronization or make the variables volatile (something that instructs the JVM not to allow them to be kept in thread-separated caches). Another possibility is to use AtomicBoolean .

  • The problem has no relation to the fact that the variable is being accessed from within the anonymous class. The problem is that it is being accessed from another thread.

    If you see this problem happening when you use an anonymous class that is not a Thread , I ask you to show this code.

    As for your second code, the signUpInBackground method creates a new thread to execute what is in the anonymous class, which means that the cadastrarUsuario method will execute return without waiting signUpInBackground to complete.

    In fact, the method signUpInBackground() returns a Task<Void> .

    What is the class Task according to the documentation?

      

    Represents the result of an asynchronous operation.

    Translating to Portuguese:

      

    Represents the result of an asynchronous operation.

    What is an asynchronous operation?

    It means that the process that starts it does not wait for its end , which will produce some result only in an uncertain future. That is, your cadastrarUsuario method is not actually registering a user, you are only asking a user to be registered and returning immediately . Note that this does not imply that the user was actually registered at any time. You would have to wait for Task finished to know this.

    In both cases, the problem is that what appears in the body of the anonymous class is only executed long after the main method has already returned, and on top of that it runs on another thread.

        
    22.08.2017 / 22:07
    0

    As you've said before, you can not change the value of a variable within the thread and test it right away. Probably your test (if, println, or whatever) will be called before the thread is started.

    One of the right ways to work would be: (With your own example)

    public class Teste {
    
        public Teste() {
            fazerAlgo();
        }
    
        public void fazerAlgo() {
    
            new Thread() {
                public void run() {                                       
                    System.out.println("Entra aqui");
    
                    if (1 == 1) {
                        metodoDeuCerto();
                    } else {
                        metodoNaoDeuCerto();
                    }
                }
            }.start();
        }
    
        public void metodoDeuCerto() {
            System.out.println("Deu certo!");
        }
    
    
        public void metodoNaoDeuCerto() {
            System.out.println("Nao deu certo!"); 
        }
    }
    

    (EDITED)

    Android Example:

    public class UsuarioDAO {
    
        private SignupListener listener;
    
        public UsuarioDAO(){}
    
        public void cadastrarUsuario(Usuario usuario) {
    
            ParseUser parseUser = new ParseUser();
            parseUser.setUsername(usuario.getNome());
            parseUser.setEmail(usuario.getEmail());
            parseUser.setPassword(usuario.getSenha());
    
            parseUser.signUpInBackground(new SignUpCallback() {
                @Override
                public void done(ParseException e) {
                    if(e == null) {
                       if ( listener != null ) {
                           listener.deuCerto();
                       }
                    }else{
                       e.printStackTrace();
                       if ( listener != null ) {
                           listener.naoDeuCerto();
                       }
                    }
    
                }
    
            });
        }
    
        public void setSignupListener(SignupListener signupListener) {
            this.listener = signupListener; 
        }
    
        public interface SignupListener {
            void deuCerto();
            void naoDeuCerto();
        }
    }
    

    // Example of Activity calling the UserID

    public class MainActivity extends Activity {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main_activity); 
    
            Usuario usuario = new Usuario();
            usuario.setUserName("usuario");
            usuario.setEmail("[email protected]");
            usuario.setPassword("senha");
    
            UsuarioDAO dao = new UsuarioDAO();
            dao.setSignupListener(signupListener);
            dao.cadastrarUsuario(usuario);
    
        }
    
        private UsuarioDAO.SignupListener signupListener = new UsuarioDAO.SignupListener {
            @Override
            public void deuCerto() {
               //DO SOMETHING
            }
    
            @Override
            public void naoDeuCerto() {
               //DO SOMETHING
            }
        }
    }
    
        
    23.08.2017 / 00:02