Pregunta

I'm trying to implement Firebase with an Android application, and I've written a simple login code. The problem is that unless the Firebase code is used within the Activity class, the user is required to press the login button twice.

In short, the user tries to login, but the Firebase reference isn't retrieved instant, and so returns a false result. However, a few seconds later, you can see that LogCat returns a true result, and if the user then clicks the login button again, he/she's able to login.

LogCat

04-30 10:29:25.003: I/WMT(30932): activity
04-30 10:29:25.003: I/WMT(30932): controller
04-30 10:29:25.003: I/kolla(30932): https://REMOVEDURL.firebaseio.com/users/testing
04-30 10:29:25.003: I/kolla(30932): ITS TRUE!
04-30 10:29:25.133: D/dalvikvm(30932): GC_CONCURRENT freed 514K, 14% free 9799K/11271K, paused 6ms+13ms, total 62ms
04-30 10:29:26.274: I/kolla(30932): datachange
04-30 10:29:26.274: I/kolla(30932): https://REMOVEDURL.firebaseio.com/users/testing
04-30 10:29:26.274: I/kolla(30932): hej
04-30 10:29:26.274: I/kolla(30932): Normal password: hej
04-30 10:29:26.274: I/kolla(30932): Password is correct
04-30 10:29:26.274: I/kolla(30932): userExists is true

The calling activity

public class MainActivity extends Activity {

    private MainController mainController;

    private EditText edtUsername;
    private EditText edtPassword;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mainController = new MainController();

        edtUsername = (EditText)findViewById(R.id.edtUsername);
        edtPassword = (EditText)findViewById(R.id.edtPassword);
    }

    public void btnLoginClick(View view)
    {
        Log.i("WMT", "activity");
        if(mainController.login(edtUsername.getText().toString(), edtP    assword.getText().toString()) != null) {
            Toast toast = Toast.makeText(getApplicationContext(), "Login correct, redirecting...", Toast.LENGTH_LONG);
            toast.show();

            User user = mainController.login(edtUsername.getText().toString(), edtPassword.getText().toString());

            Intent intent = new Intent(this, UserWindowActivity.class);
            intent.putExtra("user", user);
            startActivity(intent);
        } else {
            Toast toast = Toast.makeText(getApplicationContext(), "Invalid username and/or password", Toast.LENGTH_SHORT);
            toast.show();
        }
    }
}

Controller

public final class MainController {

    // This controller handles main activity

    private FirebaseDba dba;

    public MainController() {
        dba = new FirebaseDba();
    }

    public User login(String username, String password) {
        Log.i("WMT", "controller");
        return dba.login(username, password);
    }

}

Database access class

public class FirebaseDba {

    private final String FIREBASE_URL = //Removed for safety purposes;

    private Firebase fb;

//  String savedPassword;
    boolean userExists;

    public FirebaseDba() {
        fb = new Firebase(FIREBASE_URL);
    }

    private Firebase getFirebaseConnection() {
        return fb;
    }

    public User login(final String username, final String password) {
        final Firebase dbaa = new Firebase(fb.toString() + "/users/" + username);
        Log.i("kolla", dbaa.toString());
        dbaa.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot snap) {
                Log.i("kolla" ,"datachange");
                Log.i("kolla", dbaa.toString());
                Object value = snap.getValue();
                if (value != null) {
                    String dbPassword = snap.child("password").getValue().toString();
                    Log.i("kolla", dbPassword);
                    Log.i("kolla", "Normal password: " + password);
                    if (password.equals(dbPassword)) {
                        Log.i("kolla", "Password is correct");
                        changeToTrue();
                        if(userExists) Log.i("kolla", "userExists is true");

                    }
                }
                else {
                    userExists = false;
                }
            }
            @Override
            public void onCancelled(FirebaseError arg0) {
                // TODO Auto-generated method stub

            }
        });

        Log.i("kolla", "ITS TRUE!");
        if (userExists == true) {
            Log.i("kolla", "userExists equals true");
            return new User(username, password);
        }

        //return new User(username, password);
        return null;
    }

    public void changeToTrue() {
        userExists = true;
    }
}

EDIT: Aren't there anyone that has had this problem? Is everyone running their DB-access in their Activity? Cause that sounds like bad practice, and I'd like to solve this issue with a separate class. All help appreciated.

¿Fue útil?

Solución

Firebase events do not fire synchronously like your code is expecting. They fire when data has been fetched from the server. What you could instead do is pass a callback to your FirebaseDba.login method that is called with the results of call when they are available. Your login call should not return a User, since you are not guaranteed that you have the data yet.

You might also consider checking out the Simple Login client (https://www.firebase.com/docs/security/simple-login-java-overview.html) to handle auth for you. Or if not, you can at least check out the code it uses to achieve the result you want: https://github.com/firebase/firebase-simple-login-java

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top