So I was trying to get my first app up and running and I ran in to a problem when I tried debugging it on my phone.
The error states
Caused by: java.lang.IllegalStateException: Default FirebaseApp is not initialized in this process com.stuff.morestuff. Make sure to call FirebaseApp.initializeApp(Context) first.
at com.google.firebase.FirebaseApp.getInstance(SourceFile:218)
at com.google.firebase.auth.FirebaseAuth.getInstance(Unknown Source:1)
at com.stuff.morestuff.MainActivity.<init>(MainActivity.java:13)
And I've tried using FirebaseApp.initializeApp(this) but it still throws the same error.
public class MainActivity extends AppCompatActivity {
private FirebaseAuth mAuth;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//I've tried using this too but it didn't change anything, still the same error
//FirebaseApp.initializeApp(this);
mAuth = FirebaseAuth.getInstance();
}
#Override
public void onStart() {
super.onStart();
// Check if user is signed in (non-null) and update UI accordingly.
FirebaseUser currentUser = mAuth.getCurrentUser();
if(currentUser == null){
Intent startIntent = new Intent(MainActivity.this, StartActivity.class);
startActivity(startIntent);
}
}
}
Did I miss something?
This solution worked for me. **REMARKS Check the comments to the solution if you want to use 4.1.0
https://stackoverflow.com/a/52136056/7808468
Related
I am creating a Journal app.
I am currently working on the functionality for if the user is already logged in—bypass the "get started/log in activities"
In the video I am watching to create a journal app, the instructor calls
mUser = firebaseAuth.getCurrentUser(); several times.
He calls it in onStart(), in onCreate() and in onAuthStateChanged(). I can understand why we might need to call it again in onAuthStateChanged(), but in this case, I'm just checking if the user is already logged in, so it shouldn't change from the user received in onCreate()
I removed it from onAuthStateChanged() and onStart() and everything is still working fine. However, I'm unsure if it will lead me to errors in the future. If anyone can confirm this, I would appreciate it.
Is there a reason why we need to call getCurrentUser() several times?
Thanks.
This is my full code for reference:
public class MainActivity extends AppCompatActivity {
Button getStarted;
private FirebaseUser mUser;
private FirebaseAuth firebaseAuth;
private FirebaseAuth.AuthStateListener myListener;
private FirebaseFirestore db = FirebaseFirestore.getInstance();
private CollectionReference myCollectionRef = db.collection("Users");
#Override
protected void onCreate(Bundle savedInstanceState) {
firebaseAuth = FirebaseAuth.getInstance();
mUser = firebaseAuth.getCurrentUser();
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getStarted = findViewById(R.id.btnGetStarted);
getStarted.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this, LoginActivity.class));
finish();
}
});
myListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull #NotNull FirebaseAuth firebaseAuth) {
if(mUser != null){
//logged in
//I commented this out and everything is still working fine
//mUser = firebaseAuth.getCurrentUser();
String currentUserId = mUser.getUid();
myCollectionRef.whereEqualTo("userId", currentUserId).addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable #org.jetbrains.annotations.Nullable QuerySnapshot value, #Nullable #org.jetbrains.annotations.Nullable FirebaseFirestoreException error) {
if(error != null){
Log.d("my_error", error.toString());
}
if(!value.isEmpty()){
for(QueryDocumentSnapshot snapshot : value){
JournalApi myJournalApi = new JournalApi();
myJournalApi.setUsername(snapshot.getString("username"));
myJournalApi.setId(snapshot.getString("userId"));
startActivity(new Intent(MainActivity.this, JournalList.class));
finish();
}
}
}
});
}else{
//not logged in
}
}
};
}
#Override
protected void onStart() {
super.onStart();
//I commented this out and everything is still working fine
//mUser = firebaseAuth.getCurrentUser();
firebaseAuth.addAuthStateListener(myListener);
}
#Override
protected void onPause() {
super.onPause();
if(firebaseAuth != null){
firebaseAuth.removeAuthStateListener(myListener);
}
}
}
While signing in is an active process, that your code triggers by calling one of the signInWith methods, maintaining the authentication state and restoring it on application restart are background processes that happen automatically when you use the Firebase SDK. This is great, because it means you don't have to write code to keep tokens valid, or to check if the user profile has changed or their account has been disabled.
It does mean however that you can't reliably cache the value of firebaseAuth.getCurrentUser() in a variable for much time. If you keep the value in a variable, and then the SDK updates the authentication state in the background, your code may not be looking at the correct value for firebaseAuth.getCurrentUser() anymore.
That's why you'll see more calls to firebaseAuth.getCurrentUser() than you might expect, and also why you'll see firebaseAuth.addAuthStateListener in places that want to get notified when the authentication state changed, like when the user is signed in or out by the SDK.
You've to call this method everytime you want to check the user's current session due the user's session can be changed from another service or method, if you don't call this method and just call once, you won't have the latest user's profile info, auth session, and such more.
I am using switch buttons in my Android app and I want to check the database for a value and depending on the value, the switch button should be checked on creation of the activity. The problem is that after clicking on the button, the activity ends and I cannot figure out why this happens. I don't get any errors when I run or debug the program, so I cannot follow any error trail. Any assistance on this issue would be greatly appreciated.
public class EditProfile extends AppCompatActivity implements AdapterView.OnItemSelectedListener {
DatabaseReference root, profilePicRef;
StorageReference storageReference;
StorageTask uploadTask;;
Switch EPprivacySwitchSW;
User user;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_profile);
root = FirebaseDatabase.getInstance().getReference();
user = (User) intent.getSerializableExtra("user_object");
EPprivacySwitchSW = findViewById(R.id.EPprivacySW);
if (user.getProfile_status() != null && user.getProfile_status().equals("private")){
EPprivacySwitchSW.setChecked(true);
}
EPprivacySwitchSW.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked){
profileStatus = "private";
}else{
profileStatus = "public";
}
root.child("users").child(user.getUsername())
.child("profile_status").setValue(profileStatus);
}
});
}
}
As per the #ADM 's comment.
You forgot to initialise the root variable in code.
Declare variable root as below.
private DatabaseReference root = FirebaseDatabase.getInstance().getReference().getRoot();
You need to instance the Firebase Realtime Database which is the DatabaseReference. So you should do something like this.
root = FirebaseDatabase.getInstance().getReference(); //Add here
root.child("users").child(user.getUsername()).child("profile_status").setValue(profileStatus);
I am building a sign-in activity (Firebase, Google sign in) that only starts on the application's first run. Problem is that activity persists on spawning even after the authentication process is complete.
I am combining Realtime Database for storing user data into the database when a new user gets registered.
I've run a debugger through the authentication process, which returned no errors or unexpected behavior. I can also confirm that Realtime Database gets queried as expected.
Application is written in the combination of Java and Kotlin.
This is how I call the SignInActivity inside MainActivity on application's first run (Java)
private SharedPreferences sharedPreferences;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Check if this is application's first run
sharedPreferences = getSharedPreferences(getApplicationContext().getPackageName(), Context.MODE_PRIVATE);
startActivity(new Intent(MainActivity.this, SignInActivity.class));
}
#Override
protected void onResume() {
super.onResume();
if (sharedPreferences.getBoolean("first", true)) {
startActivity(new Intent(MainActivity.this, SignInActivity.class));
sharedPreferences.edit().putBoolean("first", false).apply();
}
}
and this is a Kotlin function that commences the authentication process
private fun authenticateWithGoogle(account: GoogleSignInAccount?) {
if (account != null) {
val credential: AuthCredential = GoogleAuthProvider.getCredential(account.idToken, null)
firebaseAuth.signInWithCredential(credential).addOnCompleteListener{
if (it.isSuccessful) {
databaseReference.addValueEventListener(object: ValueEventListener {
override fun onCancelled(p0: DatabaseError) {}
override fun onDataChange(dataSnapshot: DataSnapshot) {
databaseReference.child(account.id!!)
val userModel: UserModel? = dataSnapshot.getValue(UserModel::class.java)
if (userModel == null) {
databaseReference.child(account.id!!).setValue(UserModel(account.id, account.displayName, account.email))
startActivity(Intent(this#SignInActivity, MainActivity::class.java))
}
startActivity(Intent(this#SignInActivity, MainActivity::class.java))
}
})
}
}
}
}
Upon the initial transition from MainActivity to SignInActivity, the authentication process begins on button press. Function authenticateWithGoogle gets called as expected and the database is queried for information whether a user exists or not. If the user exists, just transition back to MainActivity, if not, store their data to the database and then transition to MainActivity.
At this point, shared preference for storing the state of the first run in MainActivity should be set to false, but apparently, it's not, hence why SignInActivity gets called again.
Any sort of help would be very appreciated.
I fixed the problem differently, as suggested by shubham-vashisht.
So, here's how I did it:
private SharedPreferences sharedPreferences;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Check if it's application's first run
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
boolean state = sharedPreferences.getBoolean("firstrun", false);
if (!state) {
Editor editor = sharedPreferences.edit();
editor.putBoolean("firstrun", true);
editor.apply();
startActivity(new Intent(MainActivity.this, SignInActivity.class));
}
}
I have the following scenario: I have a model class, which looks like this:
public class UserModel implements Serializable {
private String userEmail, userName;
public UserModel() {}
public UserModel(String userEmail, String userName) { this.userEmail = userEmail; this.userName = userName;}
//setters and getters
}
In my first activity, I'm logging in to Firebase, I'm getting the data from the FirebaseUser object and then I'm creating an object of the UserModel class and passing it to intent like this:
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
intent.putExtra("userModel", userModel);
startActivity(intent);
In the second activity, every time it starts, I'm checking if the user is logged in or not. If it is, it stays here, if not I redirect to the first activity. Here, I'm getting the object using the following line of code:
UserModel userModel = (UserModel) getIntent().getSerializableExtra("userModel");
First time when the activity starts, everything works fine, but when I restart the activity, I get a NullPointerException. How can I preserve the userModel object that I got from the intent through any activity restarts?
Thanks in advance!
You should have a look at the Activity Lifecycle. You'll find a method called onSavedInstanceState(). Now what you want to do is store the object of your class in the bundle using that method, and get it back in onCreate(), as follows:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
UserModel userModel = (UserModel) savedInstanceState.getSerializable("userModel");
} else if (getIntent() != null) {
UserModel userModel = (UserModel) getIntent().getSerializableExtra("userModel");
} else {
// These is no data
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("userModel", userModel);
}
You have to persist the model to external storage. Some viable options are:
SharedPreferences: save in onPause(), restore in onResume() or onCreate(); here is a quick example.
SaveInstanceState
For example through SaveInstanceState by overriding the following callbacks:
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
/* savedInstanceState Bundle will be passed onto onCreate() when activity
* gets killed and restarted. */
savedInstanceState.putSerializable("userModel", userModel);
}
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
/* Also being passed onto onCreate(). */
UserModel mUserModel = (UserModel) savedInstanceState.getSerializable("userModel");
}
By doing a null-check against the intent first, you can save yourself some processing time, while not doing any redundant operations.
Making a prototype app that requires an email address & password
I am quite new to java, I have tried the following method but the new activity does not open. If anyone has any helpful hints/tips it would be appreciated :)
public class LogonScreen extends ActionBarActivity {
private Button SignInButton;
private EditText Emailbox,Passwordbox;
private CheckBox RememberMe;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_logon_screen);
SignInButton = (Button) findViewById(R.id.SignInButton);
Emailbox = (EditText) findViewById(R.id.EmailBox);
Passwordbox = (EditText) findViewById(R.id.PasswordBox);
RememberMe = (CheckBox) findViewById(R.id.RememberMeBox);
}
public void SignInButtonOnClick(View View){
if(((Emailbox.getText().toString()).equals(R.string.EmailAd))&&((Passwordbox.getText().toString()).equals(R.string.password))){
Intent i = new Intent(this, MenuPage.class);
startActivity(i);
}
}
Do it like this, it should work.
if(((Emailbox.getText().toString()).equals(getString(R.string.EmailAd)))&&((Passwordbox.getText().toString()).equals(getString(R.string.password))))
You're Emailbox.getText().toString()).equals(R.string.EmailAd) doing like this which is not correct because R.string.EmailAd will give you unique ID assigned to this string so this condition will never true.
To get the string which is in the resources you need to call like getString(resource_name) and try to follow java camel cases naming convention.
#Sajad, mentioned you need to apply click listener also on the signInButton button
SignInButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
//your intent
}
});