0

I created an array in the database. Through the application's code I get the value from the array and I want to remove it, but for the code to work I want the value to be deleted completely, that is, the array must start again with "0", but with the help of the removeValue () command it just assigns a null. How can I remove a value from the database?

I tried both removeValue and setValue (null), but it still replaces the value in the base with null.

import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;

import java.util.Map;

public class MainActivity extends AppCompatActivity {

    Button mButtonSee;
    TextView mTextViewPromo;

    DatabaseReference mRef = FirebaseDatabase.getInstance().getReference();
    DatabaseReference mPromoRef =                 
mRef.child("delivery").child("0").child("promokod");

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

        mButtonSee = findViewById(R.id.buttonSee);
        mTextViewPromo = findViewById(R.id.promo);

        mButtonSee.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                mPromoRef.addListenerForSingleValueEvent(new 
ValueEventListener() {
                    @Override
                    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                    String text = dataSnapshot.getValue(String.class);
                    mTextViewPromo.setText(text);
                    mPromoRef.removeValue();
                }

                    @Override
                    public void onCancelled(@NonNull DatabaseError databaseError) {

                    }

                });

            }
        });

    }
}

As a result, I want to get to get a value from the first array when I click on the button, then delete it and again to get the value from the new first array again.

It's Database structure:

enter image description here

My new Code:

public class MainActivity extends AppCompatActivity {


Button mButtonSee;
TextView mTextViewPromo;


DatabaseReference mRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference mPromoRef = mRef.child("delivery");


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


    mButtonSee = findViewById(R.id.buttonSee);
    mTextViewPromo = findViewById(R.id.promo);


    mButtonSee.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            mPromoRef.addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                    LinkedList<String> values = new LinkedList<>();
                    boolean isFirst = true;
                    for (DataSnapshot codeSnapshot: dataSnapshot.getChildren()) {
                        if (isFirst) {
                            isFirst = false;
                        }
                        else {
                            String text = codeSnapshot.getValue(String.class);
                            values.add(text);
                        }
                    }
                    mPromoRef.setValue(values);
                }

                @Override
                public void onCancelled(@NonNull DatabaseError databaseError) {
                    throw databaseError.toException();
                }

            });

        }
    });

}
}

And logcat: 2019-02-20 02:11:25.263 1631-2110/? E/AudioFlinger: not enough memory for AudioTrack size=131296

2019-02-20 02:11:25.263 1631-2110/? E/AudioFlinger: createRecordTrack_l() initCheck failed -12; no control block?

2019-02-20 02:11:25.267 1631-12210/? I/AudioFlinger: AudioFlinger's thread 0xef703a00 tid=12210 ready to run

2019-02-20 02:11:25.269 2651-11949/com.google.android.googlequicksearchbox:search E/IAudioFlinger: createRecord returned error -12

2019-02-20 02:11:25.269 2651-11949/com.google.android.googlequicksearchbox:search E/AudioRecord: AudioFlinger could not create record track, status: -12

2019-02-20 02:11:25.271 2651-11949/com.google.android.googlequicksearchbox:search E/AudioRecord-JNI: Error creating AudioRecord instance: initialization check failed with status -12.

2019-02-20 02:11:25.274 2651-11949/com.google.android.googlequicksearchbox:search E/android.media.AudioRecord: Error code -20 when initializing native AudioRecord object.

2019-02-20 02:11:25.274 2651-11949/com.google.android.googlequicksearchbox:search I/MicrophoneInputStream: mic_started SR : 16000 CC : 16 SO : 6

2019-02-20 02:11:25.275 2651-11949/com.google.android.googlequicksearchbox:search E/ActivityThread: Failed to find provider info for com.google.android.apps.gsa.testing.ui.audio.recorded

Run:

E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.ru.puddig, PID: 12504 com.google.firebase.database.DatabaseException: Failed to convert value of type java.util.HashMap to String at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertString(com.google.firebase:firebase-database@@16.0.6:413) at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.deserializeToClass(com.google.firebase:firebase-database@@16.0.6:199) at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertToCustomClass(com.google.firebase:firebase-database@@16.0.6:79) at com.google.firebase.database.DataSnapshot.getValue(com.google.firebase:firebase-database@@16.0.6:212) at com.example.ru.puddig.MainActivity$1$1.onDataChange(MainActivity.java:54) at com.google.firebase.database.Query$1.onDataChange(com.google.firebase:firebase-database@@16.0.6:183) at com.google.firebase.database.core.ValueEventRegistration.fireEvent(com.google.firebase:firebase-database@@16.0.6:75) at com.google.firebase.database.core.view.DataEvent.fire(com.google.firebase:firebase-database@@16.0.6:63) at com.google.firebase.database.core.view.EventRaiser$1.run(com.google.firebase:firebase-database@@16.0.6:55) at android.os.Handler.handleCallback(Handler.java:873) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:193) at android.app.ActivityThread.main(ActivityThread.java:6669) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

2 Answers2

1

Please check this firebase blog where they mention how to use arrays with firebase. To summarise it for your question, take the following point from the blog.

  • to remove keys, we save the entire array instead of using .remove()
Jainam Jhaveri
  • 1,479
  • 1
  • 18
  • 31
1

As the article that Jainam linked explains, to remove an item from the start of an array, you will need to load the entire array, remove the item client side, and write the entire array back. In code that'd be something like this:

DatabaseReference mRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference mPromoRef = mRef.child("delivery");
mPromoRef.addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
        List<String> values = new LinkedList<String>();
        boolean isFirst = true;
        for (DataSnapshot codeSnapshot: dataSnapshot.getChildren()) {
            if (isFirst) {
                isFirst = false;
            }
            else {
                String text = codeSnapshot.getValue(String.class);
                values.add(text);
            }
        }
        mPromoRef.setValue(values);
    }

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) {
        throw databaseError.toException(); // don't ignore errors
    }
});

As you can see that is quite involved. The reason for this is that in an array the key/index of each (but the last) element, depends on the other elements in there. So removing one element (but the last) from the array, means many other elements need to be updated/moved around. For this reason you should only use an array if your data actually needs an array, meaning: if the same value can occur multiple times in the collection, if the order of values in the collection must be maintained, and if it is crucial for your application that the keys are sequential/numeric.

If that third condition does not apply, I highly recommend using Firebase's built-in push IDs for the keys. This is what the blog post Jainam refers to describes.

If however your values have to be unique in the collection, and order isn't important, you're better off using a set-like data structure. In the Firebase Realtime Database, this would look like:

{
    "del1": true,
    "del2": true,
    "del3": true
}

The value true here is not important, and merely there since Firebase can't store a key without a value. The important thing is that we now have a collection with three keys, which are guaranteed to be unique, and which can all be added/removed atomically without needing to know the other keys.

If you have a DatabaseReference to the above structure, you could remove "del1" from it with this much simpler code:

ref.child("del1").removeValue();

For more on this structure, also see my answer here: Firebase query if child of child contains a value

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • I added the code that you wrote, but the program crashes – Ara Gevorgyan Feb 19 '19 at 21:15
  • That's not enough information to help you further with. If the program crashes, show the error message and stack trace that you can find in the logcat. – Frank van Puffelen Feb 19 '19 at 22:28
  • Ok, now as a reply I will write the code changed and copy the errors from logcat – Ara Gevorgyan Feb 19 '19 at 23:05
  • The error message "not enough memory for AudioTrack size=131296" seems to indicate that there's not enough memory to load the audio track. I doubt that is caused by incorrectness in the code I shared. – Frank van Puffelen Feb 20 '19 at 01:49
  • possible, but how to fix it and did I implement your code correctly? – Ara Gevorgyan Feb 20 '19 at 06:23
  • Man, please help me understand what's wrong and how to fix it, I really want to realize my idea – Ara Gevorgyan Feb 20 '19 at 21:35
  • I added an error in the question from the window Run, and yet I put it with the code, help is not difficult to disassemble – Ara Gevorgyan Feb 22 '19 at 18:17
  • I can only repeat what the error message says: apparently there is not enough memory to load the data you're trying to load. Either way, this is a new problem after your original problem with the structure of your database. I'd open a new question, showing what data you're trying to load, give details about how much memory is available, etc. – Frank van Puffelen Feb 22 '19 at 18:49
  • but you can not somehow create a dialogue? I just want to find out if I did everything right, and you are the only one who apparently answers and understands too) – Ara Gevorgyan Feb 22 '19 at 19:11
  • Frank, new info new information, if I run the code I added below in the question, then the android studio gives the error Failed to convert the value of type java.util.HashMap to String, but when I change the line in the code"String text = dataSnapshot.getValue (String.class);" on "String text = codeSnapshot.child ("0"). getValue (String.class);" then everything works, but when it is pressed, it deletes everything in the database – Ara Gevorgyan Feb 23 '19 at 15:40