2

Here is my target event :

refDatabase.addChildEventListener(new ChildEventListener() {
    @Override
    public void onChildAdded(DataSnapshot dataSnapshot, String s) {
        LatLng newlocation = new LatLng(dataSnapshot.child("latitude").getValue(Double.class),dataSnapshot.child("longitude").getValue(Double.class));
        nama = new String(dataSnapshot.child("nama").getValue(String.class));
        kec = new String(dataSnapshot.child("kecamatan").getValue(String.class));
        kab = new String(dataSnapshot.child("kebupaten").getValue(String.class));

        googleMap.addMarker(new MarkerOptions().position(newlocation).title(nama+", "+kec+", "+kab));  
    }
});

How can I get the object newlocation and put that in this event:

tampil.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        //
    }
});
Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
husen
  • 89
  • 2
  • 10

2 Answers2

1

You can achieve this, using a callback. Fist you need to create an interface:

public interface MyCallback {
    void onCallback(LatLng newlocation);
}

Then you need to create a method that is actually getting the data from the database. This method should look like this:

public void readData(MyCallback myCallback) {
    refDatabase.addChildEventListener(new ChildEventListener() {
        @Override
        public void onChildAdded(DataSnapshot dataSnapshot, String s) {
            newlocation = new LatLng(dataSnapshot.child("latitude").getValue(Double.class),dataSnapshot.child("longitude").getValue(Double.class));
            nama = new String(dataSnapshot.child("nama").getValue(String.class));
            kec = new String(dataSnapshot.child("kecamatan").getValue(String.class));
            kab = new String(dataSnapshot.child("kebupaten").getValue(String.class));

            googleMap.addMarker(new MarkerOptions().position(newlocation).title(nama+", "+kec+", "+kab));
            myCallback.onCallback(newlocation);
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {}
    });
}

In the end just simply call readData() method and pass an instance of the MyCallback interface as an argument in your onClick() method like this:

tampil.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        readData(new MyCallback() {
            @Override
            public void onCallback(LatLng newlocation) {
                //Do what you need to do with newlocation
            }
        });
    }
});

For more informations, I recommend you see the anwser from this post and also take a look at this video.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • This is a good solution if the database event listener is in another class, and to make things a little safer I would put the click listener inside the callback. This way, there is always a button but is not always clickable until the async is resolved. Once the async is resolved then the object will never be null. And, I think what op wants is to do something with the object once the button is clicked, instead of triggering the database request. – cutiko Mar 27 '18 at 14:12
  • It is the solution even if this code is used within the same class because `onChildAdded()` has an asynchronous behaviour and by the time you are trying to use `newlocation` object inside the onClick() method, the data isn't loaded yet from the database, so this object will always be `null`. And note, the Firebase Database client already runs all network operations in a background thread, without blocking your main thread. – Alex Mamo Mar 27 '18 at 14:31
  • I don't understand why you are explaining the Firebase behavior but thanks, I guess. However seems weird you are aware of it but don't apply it to the solution. If that is the case then readData should be called inside onCreate for an Activity or inside onViewCreated for a Fragment. Then the callback should set the click listener. Doing it this way is prompt to error, the user can click the button more than once, while the async called hasn't returned. – cutiko Mar 27 '18 at 15:01
  • `readData()` method should be called wherever is needed, in this case, in the `onClick` method. It won't be an error and you know why? Becase using this callback, we are waiting for the data. So there will be no error. The app will not crash if the data is not loaded, it will wait for it. That's why we using this callback. I also recommend you read my answer from this [post](https://stackoverflow.com/questions/47847694/how-to-return-datasnapshot-value-as-a-result-of-a-method/47853774). Do some tests using some log statements or why not, real data from the database and you'll see the behaviour. – Alex Mamo Mar 27 '18 at 15:16
  • So you are admiting the user can click the button more than once while waiting, that is my point, thanks – cutiko Mar 27 '18 at 17:18
  • Thank for your response Bro – husen Apr 03 '18 at 01:27
0

You can use EventBus libray for this purpose: https://github.com/greenrobot/EventBus in three steps

  1. Define the event (E.g locationRetrievedEvent)
  2. Register the subscriber (E.g your activity)
  3. Post the event with EventBust post() function
Nicola Gallazzi
  • 7,897
  • 6
  • 45
  • 64
  • It seems like an overkill – cutiko Mar 27 '18 at 14:08
  • Maybe yes, it depends on the location of "tampil" click listener, I agree with you if the click listener is in the same class of refDatabase, otherwise I would use an interface or EventBus – Nicola Gallazzi Mar 27 '18 at 17:13
  • No! If there is only 1 case you should go with the Mamo solution below. Is pretty standard to use an interface as callback. Otherwise if the full project go with EventBus as a overall strategy, then yes! – cutiko Mar 27 '18 at 17:21