I am practicing with the Firebase library and I would like to be able to have some methods in a separated class from the Main and from this to be able to call those methods and to return for example the user.
Example FirebaseDBHelper.java
public static UserModel getUserFromId(String userId) {
final UserModel[] user = new UserModel[1];
dbRef.child("status").child(userId).addListenerForSingleValueEvent(
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get user value
user[0] = dataSnapshot.getValue(UserModel.class);
Log.d("TAG", "Value is: " + dataSnapshot.getValue());
Log.d("TAG", "User: " + user);
// ...
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.d("TAG", "getUser:onCancelled", databaseError.toException());
// ...
}
});
return user[0];
}
Main call
UserModel user = FirebaseDatabaseHelper.getUserFromId("9876");
Log.d("TAG", "UserInfo: " + user);
But I have some problems because the method getUserFromId() don't return anything.
If you know about RxJava2, it really good to go with this approach:
public Observable<UserModel> UserModel getUserFromId(String userId) {
return Observable.create(new ObservableOnSubscribe<UserModel>() {
#Override
public void subscribe(#NonNull ObservableEmitter<UserModel> e) throws Exception {
dbRef.child("status").child(userId).addListenerForSingleValueEvent(
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get user value
UserModel user = dataSnapshot.getValue(UserModel.class);
e.onNext(user);
// ...
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.d("TAG", "getUser:onCancelled", databaseError.toException());
e.onError(databaseError);
// ...
}
});
}
});
}
OR, you can define an interface callback when you get your UserModel like this
public static void getUserFromId(String userId,OnGetUser callback) {
dbRef.child("status").child(userId).addListenerForSingleValueEvent(
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get user value
user[0] = dataSnapshot.getValue(UserModel.class);
Log.d("TAG", "Value is: " + dataSnapshot.getValue());
Log.d("TAG", "User: " + user);
callback.onGetUser();
// ...
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.d("TAG", "getUser:onCancelled", databaseError.toException());
// ...
}
});
}
interface OnGetUser
{
void onGetUser();
}
OR, user[0] should have some value when onCancelled was called, like empty UserModel
Better way is to use callback from the helper class create and interface and let ure activity implement it when you call the static method pass the class when firebase gets the data call the activity callback...
Related
I'm trying to retrieve the array list generated in the function recuperarPessoasModelo(), but it only runs much later than I need so the value passed to revelaPessoas() is null, does anyone know any way I can run this function and just get the value after recuperarPessoasModelo() is executed? I can't put it inside because since it has a for loop it will run X times and generate a repeating list
The .Json in the DB looks like this:
Perfil{
PcCPoh01wscJj7jJBQQorme7Rqq1{
status:online
name: Carl Johnson
age: 21
sex: male}
t3IeEKy7XxdGeLYRxw2G1djNHdp2{
status:online
name: John Marston
age: 33
sex: male}
}
Requisicoes{
t3IeEKy7XxdGeLYRxw2G1djNHdp2{
Enviadas{
PcCPoh01wscJj7jJBQQorme7Rqq1{
idPessoa:PcCPoh01wscJj7jJBQQorme7Rqq1
status: Aguardando
}
}
}
}
the class in question:
public class Perfil_outter extends AppCompatActivity{
private List <RequisicoesCitty> requisicao = new ArrayList<>();
private List <ModeloPerfil> pessoaQuestao = new ArrayList<>();
private String idComp;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
carregarIds();
revelaPessoa()
}
public List<ModeloPerfil> getPessoaQuestao() {
return pessoaQuestao;
}
public void setPessoaQuestao(List<ModeloPerfil> pessoaQuestao) {
this.pessoaQuestao = pessoaQuestao;
}
public void carregarIds(){
Log.d("Part 1", "Working");
DatabaseReference firebaseRef = ConfiguracaoFirebase.getFirebaseDatabase();
DatabaseReference idsRef = firebaseRef.child("Requisicoes");
Query refId = idsRef.child(usuarioAtual.getId()).child("Enviadas").orderByChild("id");
refId.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for(DataSnapshot ds: snapshot.getChildren()) {
RequisicoesCitty reqSnapshots = ds.getValue(RequisicoesCitty.class);
Log.d("IdPessoas",reqSnapshots.getIdPessoa());
requisicao.add(reqSnapshots);
}
carregarRequisicoes();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
public void carregarRequisicoes(){
if(requisicao.isEmpty()){
Log.d("Não encontrado", "Nenhuma requisição Citty");
}
for(RequisicoesCitty requisicao: requisicao) {
Log.d("Part 2", "Working");
DatabaseReference firebaseRef = ConfiguracaoFirebase.getFirebaseDatabase();
Query requisicoesEnviadas = firebaseRef.child("Requisicoes").child(usuarioAtual.getId())
.child("Enviadas").child(requisicao.getIdPessoa());
requisicoesEnviadas.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
RequisicoesCitty reqSnap = snapshot.getValue(RequisicoesCitty.class);
idComp = reqSnap.getIdPessoa();
recuperarPessoasModelos();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
}
public void recuperarPessoasModelos(){
Log.d("Part 3", "Working");
DatabaseReference firebaseRef = ConfiguracaoFirebase.getFirebaseDatabase();
Query pessoas = firebaseRef.child("Perfil").child(idComp);
pessoas.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
ModeloPerfil pessoas = snapshot.getValue(ModeloPerfil.class);
pessoaQuestao.add(pessoas);
setPessoaQuestao(pessoaQuestao);
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
public void revelaPessoas(){
for(ModeloPerfil modelo: getPessoaQuestao()){
Log.d("Funcionar", modelo.getNome());
}
}
}
did you understand my problem? my goal is to get the value modelo.getNome() inside of revelaPessoas back and display but it runs sooner than it should
You're calling recuperarPessoasModelos each time that carregarRequisicoes loops through one of its for(RequisicoesCitty requisicao: requisicao) {. This is totally fine, but I'm guessing that recuperarPessoasModelos is not handling these multiple calls correctly.
If you only want to call recuperarPessoasModelos once all requisicao are done, you can check a counter like this:
List snapshots = new List(); // 👈 a list to track the snapshots we have already loaded
for(RequisicoesCitty requisicao: requisicao) {
Log.d("Part 2", "Working");
DatabaseReference firebaseRef = ConfiguracaoFirebase.getFirebaseDatabase();
Query requisicoesEnviadas = firebaseRef.child("Requisicoes").child(usuarioAtual.getId())
.child("Enviadas").child(requisicao.getIdPessoa());
requisicoesEnviadas.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
snapshots.add(snapshot); // 👈 add snapshot to list
RequisicoesCitty reqSnap = snapshot.getValue(RequisicoesCitty.class);
idComp = reqSnap.getIdPessoa();
if (snapshots.size() == requisicao.size()) { // 👈 check if we got all of them
recuperarPessoasModelos();
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
throw error.toException(); // 👈 never ignore errors
}
hello i'm looking to create a way to check if the username is already in use or not.
The problem is that if the username is already taken the error is displayed correctly, but the user still registers ...
private boolean validateForm () {
boolean valid = true;
String username = rUsernameField.getText().toString();
String email = rEmailField.getText().toString();
if (TextUtils.isEmpty(email)) {
rEmailField.setError(getText(R.string.field_error));
valid = false;
} else {
rEmailField.setError(null);
}
String password = rPasswordField.getText().toString();
if (TextUtils.isEmpty(password)) {
rPasswordField.setError(getText(R.string.field_error));
valid = false;
} else {
rPasswordField.setError(null);
}
if (TextUtils.isEmpty(username)) {
rUsernameField.setError(getText(R.string.field_error));
valid = false;
validUsername = false;
} else {
rUsernameField.setError(null);
}
if (!validUsername) {
valid = false;
}
if (rCGUCheck.isChecked()) {
rCGUCheck.setError(null);
} else {
rCGUCheck.setError(getText(R.string.err_cgu));
valid = false;
}
return valid;
}
public void setValidUsername() {
String username = rUsernameField.getText().toString();
FirebaseDatabase.getInstance().getReference().child("users").orderByChild("username").equalTo(username).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
validUsername = false;
Log.d(TAG, "false");
rUsernameField.setError("This username already exists");
} else {
validUsername = true;
Log.d(TAG, "true");
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
private void signUp() {
Log.d(TAG, "signUp");
if (!validateForm()) {
return;
}
#Override
public void onClick (View v){
int i = v.getId();
if (i == R.id.regBtn) {
setValidUsername();
signUp();
}
therefore if one of the fields is not filled in, the user cannot register. But what I don't understand is why even if the username already exists the user can still register ^^
Thank's in advance.
Have one function called validateUser:
public void validateUser() {
//get string from editTexts
String username = rUsernameField.getText().toString();
String email = rEmailField.getText().toString();
String password = rPasswordField.getText().toString();
FirebaseDatabase.getInstance().getReference().child("users").orderByChild("username").equalTo(username).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
//username is not available
rUsernameField.setError("This username already exists");
} else {
//username is available
//so check now if all is okay
if(!TextUtils.isEmpty(email) && !TextUtils.isEmpty(password) && !TextUtils.isEmpty(username) && rCGUCheck.isChecked()){
signUp();
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
The signUp() method:
private void signUp(){
//sign up
Log.d(TAG, "signUp");
}
onclick() method
#Override
public void onClick (View v){
int i = v.getId();
if (i == R.id.regBtn) {
validateUser();
}
Your setValidUsername is an asynchronous operation. Data is loaded from Firebase asynchronously (like with most cloud APIs), since it may take some time to complete. While that is happening, you main code continues and your signUp method executes. Then when the data is available, your onDataChange is called and sets validUsername.
For a good example of this and a solution, see my answer here: getContactsFromFirebase() method return an empty list
For you this could mean:
Defining an interface for your own callback:
public interface UserExistsCallback {
void onCallback(boolean value);
}
Modify setValidUsername to take this callback as an argument, and call it:
public void isValidUsername(UserExistsCallback callback) {
String username = rUsernameField.getText().toString();
FirebaseDatabase.getInstance().getReference().child("users").orderByChild("username").equalTo(username).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
callback.onCallback(false);
rUsernameField.setError("This username already exists");
} else {
callback.onCallback(true);
Log.d(TAG, "true");
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException(); // never ignore errors
}
});
}
Call this new function and use the value in the callback:
isValidUsername(new UserExistsCallback() {
#Override
public void onCallback(boolean exists) {
System.out.println("User exists: "+exists);
}
});
I have a field in Firebase: balance. What I need is that after a person enters a sum 100, the field changes the value to 100. Then when the person enters a sum of 50, the field value becomes 150.
How do I write processing logic on the client? Summation of data. I think it is over-easy, but I need your help!
mDatabaseUsers.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String user_id = mAuth.getCurrentUser().getUid();
String balance = dataSnapshot.child(user_id).child("Balance").getValue(String.class);
mCountPayment.setText(balance + " ₽");
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
mPaymentButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
paymentIntent();
}
});
}
private void paymentIntent() {
final String user_id = mAuth.getCurrentUser().getUid();
final String count = mPaymentList.getText().toString().trim();
if (!TextUtils.isEmpty(count)) {
mDatabaseUsers.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
mDatabaseUsers.child(user_id).child("Balance").setValue(count);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
To write a value to the realtime database based on an existing value, you will need to use a transaction.
The basic code for your transaction will look like this:
DatabaseReference balanceRef = FirebaseDatabase.getInstance().getReference("/Users/"+ user_id +"/Balance");
Long delta = 50l;
balanceRef.runTransaction(new Transaction.Handler() {
#Override
public Transaction.Result doTransaction(MutableData mutableData) {
Long balance = mutableData.getValue(Long.class);
if (balance == null) {
mutableData.setValue(delta);
}
else {
Long amount = mutableData.getValue(Long.class);
amount = amount + delta;
mutableData.setValue(amount);
}
return Transaction.success(mutableData);
}
#Override
public void onComplete(DatabaseError databaseError, boolean b,
DataSnapshot dataSnapshot) {
// Transaction completed
Log.d(TAG, "balanceTransaction:onComplete:" + databaseError);
}
});
I am working on a project where user request for our valet services and on the other end valet accepts request.
I am using using Firebase as backend and on request customer uid is save on 'request' child.
When valet accepts request, customer uid should move from 'request' node to 'on progress' node.
How can i do that?
I recommend using this :
public void moveFirebaseRecord(Firebase fromPath, final Firebase toPath)
{
fromPath.addListenerForSingleValueEvent(new ValueEventListener()
{
#Override
public void onDataChange(DataSnapshot dataSnapshot)
{
toPath.setValue(dataSnapshot.getValue(), new Firebase.CompletionListener()
{
#Override
public void onComplete(FirebaseError firebaseError, Firebase firebase)
{
if (firebaseError != null)
{
System.out.println("Copy failed");
}
else
{
System.out.println("Success");
}
}
});
}
#Override
public void onCancelled(FirebaseError firebaseError)
{
System.out.println("Copy failed");
}
});
}
This come from this source : https://gist.github.com/katowulf/6099042 . I used it several times in my JavaEE code and also in my android app.
You pass your fromPath and toPath. This is a copy tought and not a move, so the original will remain at his original place too. If you would like to delete, you can do a set value on the fromPath just after the System.out.println("Success"); .
As of compile firebase-database:11.0.1, this is the same function with the new class references (https://firebase.google.com/support/guides/firebase-android July 05 2017)
private void moveGameRoom(final DatabaseReference fromPath, final DatabaseReference toPath) {
fromPath.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
toPath.setValue(dataSnapshot.getValue(), new DatabaseReference.CompletionListener() {
#Override
public void onComplete(DatabaseError firebaseError, DatabaseReference firebase) {
if (firebaseError != null) {
System.out.println("Copy failed");
} else {
System.out.println("Success");
}
}
});
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
If you want to perform a move which also erases the original, you might make use of the following snippet:
// In this piece of code, "fromPath" and "toPath" parameters act like directories.
private void removeFromFirebase(final DatabaseReference fromPath, final DatabaseReference toPath, final String key) {
fromPath.child(key).addListenerForSingleValueEvent(new ValueEventListener() {
// Now "DataSnapshot" holds the key and the value at the "fromPath".
// Let's move it to the "toPath". This operation duplicates the
// key/value pair at the "fromPath" to the "toPath".
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
toPath.child(dataSnapshot.getKey())
.setValue(dataSnapshot.getValue(), new DatabaseReference.CompletionListener() {
#Override
public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
if (databaseError == null) {
Log.i(TAG, "onComplete: success");
// In order to complete the move, we are going to erase
// the original copy by assigning null as its value.
fromPath.child(key).setValue(null);
}
else {
Log.e(TAG, "onComplete: failure:" + databaseError.getMessage() + ": "
+ databaseError.getDetails());
}
}
});
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.e(TAG, "onCancelled: " + databaseError.getMessage() + ": "
+ databaseError.getDetails());
}
});
}
you can listen to value event on your child you want to copy it ,, and #onDataChange get reference of new child and set value dataSnapshot to this child like below sample code
FirebaseDatabase.getInstance().getReference("childYouWantToCopy")
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
FirebaseDatabase.getInstance().getReference("ChildCopyTo").setValue(dataSnapshot.getValue());
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
Good Day.
I have tried my level best but failed to update the data whenever i enter new "Name","Age" or anything the data entered before is wiped.I want to use push or something else to update the data.But still failing to do that.
nameRef.addValueEventListener(new com.google.firebase.database.ValueEventListener() {
#Override
public void onDataChange(com.google.firebase.database.DataSnapshot dataSnapshot) {
String text = dataSnapshot.getValue(String.class);
String ho = name.getText().toString();
nameRef.setValue(ho);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
genderRef.addValueEventListener(new com.google.firebase.database.ValueEventListener() {
#Override
public void onDataChange(com.google.firebase.database.DataSnapshot dataSnapshot) {
String text = dataSnapshot.getValue(String.class);
String ho = gender.getText().toString();
genderRef.setValue(ho);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
ageRef.addValueEventListener(new com.google.firebase.database.ValueEventListener() {
#Override
public void onDataChange(com.google.firebase.database.DataSnapshot dataSnapshot) {
`enter code here` String text = dataSnapshot.getValue(String.class);
String ho = age.getText().toString();
ageRef.setValue(ho);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
EmailRef.addValueEventListener(new com.google.firebase.database.ValueEventListener() {
#Override
public void onDataChange(com.google.firebase.database.DataSnapshot dataSnapshot) {
String text = dataSnapshot.getValue(String.class);
String ho = email.getText().toString();
EmailRef.setValue(ho);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
If you have a JSON tree like this:
->users
->uid
->name
->age
->gender
->email
Then to update the values in the database you should do something like this:
DatabaseReference mFirebaseDBRef = FirebaseDatabase.getInstance().getReference();
FirebaseAuth mFirebaseAuth = FirebaseAuth.getInstance();
FirebaseUser mFirebaseUser = mFirebaseAuth.getCurrentUser();
//use a POJO and make sure to have a default empty constructor in that class definition
User user = new User(name, age, gender, email)
mFirebaseDBRef.child("users").child(mFirebaseUser.getUid()).setValue(user);
And that should update your database! If something is not clear, feel free to ask.