0

I have a FragmentActivity with a LocateMe feature on the ActionBar and it hosts 4 fragments. Each fragment is a ListView that basically sorts the results in my list differently (e.g. based on ratings, price, distance etc.)

my question is, how do I write my code such that the Location management (e.g. retrieval, updating) is done in the FragmentActivity, whereas the fragment just takes this location to perform any data calls on create or sorts the list when the LocateMe button is pressed.

it definitely feels wrong if I have LocationManager in each fragment to deal with locations, except I dont know how to do the right thing.

thank you all. :)

cyberhicham
  • 495
  • 1
  • 10
  • 24
chongzixin
  • 1,951
  • 4
  • 28
  • 55

2 Answers2

2

the 'cleanest' way IMHO is via interfaces and registering listeners

create two interfaces:

public interface LocationListener{
    public void onLocationAvailable(/* whatever data you want to pass */ );
}
public interface LocationListenersRegistry{
    public void addLocationListener(LocationListener listener);
    public void removeLocationListener(LocationListener listener);
}

then you make your activity implement LocationListenersRegistry and your fragments implement LocationListener

on your activity you'll have an private ArrayList<LocationListener> that you'll add and remove listeners as per add/remove methods. Every time your activity receives new data, it should process it and then pass to all the listeners on the array.

on the fragments you should onPause and onResume register and unregister themselves from the activity, something like that:

onResume(){
    super.onResume();
    ((LocationListenersRegistry)getActivity()).addLocationListener(this);
}

onPause(){
    super.onPause();
    ((LocationListenersRegistry)getActivity()).removeLocationListener(this);
}

edit:

your activity implements the LocationListenersRegistry and then will have this code:

public class MyActivity extends Activity implements LocationListenersRegistry {

private ArrayList<LocationListener> listeners = new ArrayList<LocationListener>();
public void addLocationListener(LocationListener listener){
       listeners.add(listener);
}
public void removeLocationListener(LocationListener listener){
    listeners.remove(listener);
}

and then whenever the user clicks the menu button:

  for(LocationListener l:listeners)
         l.onLocationAvailable(/* pass here the data for the fragment */);

and your fragments will be implementing the LocationListener

  public class MyFragment extends Fragments implements LocationListener{
      public void onLocationAvailable( /* receive here the data */){
           // do stuff with your data
       }
Budius
  • 39,391
  • 16
  • 102
  • 144
  • hello. thanks for the answer. what if i do not require the location information whenever they are available. i just need to have the location "ready", so that when i load the other fragments or press the LocateMe function the location information can be passed to the fragments or the fragments can retrieve it from the activity. or is this data passing method considered "unclean". haha – chongzixin Jan 09 '13 at 10:34
  • well, you can just store the location on the activity and whenever the user press the menu button you call on the listeners on the array. – Budius Jan 09 '13 at 10:36
  • i am not very good with this listener concept but i am slowly understanding so please bear with me. so the LocationListenersRegistry methods will add/remove items from the arraylist. how should i implement the LocationListener though? is it just getter/setter methods or something? – chongzixin Jan 09 '13 at 12:04
  • I've added a few more code on the answer. Does that make sense? An interface is just a way of saying that this class will have that method, how the methods is implemented is up to the class. – Budius Jan 09 '13 at 12:12
  • I'd like to suggest an improvement to the Budius answer. Instead of create the interface you could use the Observer Pattern that is already implemented in Java and is available with Android. – Ignacio Rubio May 08 '14 at 11:57
1

I'd like to suggest an improvement to the Budius answer.

Instead of create these interfaces you could use the Observer Pattern that is already implemented in Java and is available with Android.

public class MyFragment extends Fragment implements Observer {
     @Override
     public void onResume() {
         super.onResume();
         myLocationServices.addObserver(this);
     }
    @Override
    public void onPause() {
         super.onPause();
         myLocationServices.deleteObserver(this);
    }
    @Override
    public void update(Observable observable, Object data) {
         // do stuff with your data
    }

}

I have created a separated class to encapsulate the data (I have used Location Client that's part of Google Play SDK and was introduced in Google IO 2013 but you could use the classic LocationManager implementation. I'm still learning :P):

public class MyLocationServices extends Observable implements
    GooglePlayServicesClient.ConnectionCallbacks,
    GooglePlayServicesClient.OnConnectionFailedListener, LocationListener {
    @Override
    public void onLocationChanged(Location location) {
         Location mBestReading;
         //Obtain the location. Do the staff
         //And notify the observers
         setChanged();
         notifyObservers(mBestReading);
    }

}

Ignacio Rubio
  • 1,354
  • 14
  • 25