Pergunta

I have 2 views of essentially the same data:

  1. List of items in a android.support.v4.app.ListFragment
  2. Markers on a map in a com.google.android.gms.maps.SupportMapFragment

Both of the above are using loader pattern to obtain the same data (extending LoaderCallbacks, querying ContentProvider, and so on)

Both are hosted within a single activity inside a ViewPager.

What will be the best strategy to synchronize currently selected list item / marker for both of these fragments? (Think of "My Places" edit UI, or "Directions" of the Google Maps with their left-hand pane and a map in the center).

Scenarios i'm thinking of so far:

  1. Make every fragment manually notify it's counterpart about selection change via callback interface (this will probably involve underlying activity to coordinate inter-fragment communications, as it is suggested by Android docs).
  2. Somehow make both fragments use the same Cursor, or even ListAdapter (whatever it means for a map, because now it's populated directly from the cursor).
  3. (Something else?)

Maybe someone has already dealt with this exact case? (I'll sure find some solution, just wanted to avoid "reinventing the wheel". Sorry for a too conceptual question.)

EDIT (Solution)

I think Maciej has answered my exact question ("best strategy", and so on..), so the answers are both 1 and 2 ;-)

Going into more details, my implementation went like this:

At first I frightened by enormous overhead of dealing with publisher/subscriber pattern in Java (involving interfaces, finding proper places for callbacks, and what's not). Fortunately, Otto bus implementation caught my eyes, which made communication between fragments a trivial thing. Not only it is possible to notify all subscribers about selection change, but also the whole Loader Patter fit nicely:

  1. Borrow BusProvider class from Otto's sample code.

  2. Create few message contracts to carry notification data:

    public class LocationSelectedEvent {  
        public long id;  
    }  
    
    public class LocationsLoadedEvent {  
        public Cursor cursor;  
    }  
    
  3. Annotate "receiver" methods in fragments with @Subscribe (example below is for loader case, for selection change it's no more complex):

    @Subscribe
    public void onLoadFinished(LocationsLoadedEvent event) {  
        final CursorAdapter a = (CursorAdapter) getListAdapter();  
        a.swapCursor(event.cursor);  
    }  
    
  4. Make fragments "listening" to notifications:

    @Override  
    public void onActivityCreated(Bundle savedInstanceState) {  
        BusProvider.getInstance().register(this);  
    }  
    
  5. Make fragments to stop listening when they're not "alive" (specially true for fragments API, learned it the hard way):

    @Override  
    public void onDestroy() {  
        super.onDestroy();  
        BusProvider.getInstance().unregister(this);  
    }  
    
  6. Finally, trigger notifications where desired (example below deomnstrates how to notify from LocationList activity when cursor has been loaded):

    @Override
    public void onResume() {
        if(null == getLoaderManager().getLoader(0)) {
            getSupportLoaderManager().initLoader(0, null, new LoaderCallbacks<Cursor>() {
                @Override
                public Loader<Cursor> onCreateLoader(int paramInt, Bundle paramBundle) {
                    return new CursorLoader(LocationsList.this, Locations.CONTENT_URI, null, null, null, null);
                }
    
                @Override
                public void onLoadFinished(Loader<Cursor> paramLoader, Cursor cursor) {
                    BusProvider.getInstance().post(new LocationsLoadedEvent(cursor));
                }
    
                @Override
                public void onLoaderReset(Loader<Cursor> paramLoader) {
                    BusProvider.getInstance().post(new LocationsLoadedEvent(null));
                }
            });
        }
        super.onResume();
    }
    

Bonus: notifications flow visualization

Foi útil?

Solução

For click-coordination your point 1 is what I would do, using Activity and interfaces of course.

I just have hard time understanding why would you want to load the same data from ContentProvider twice. Why not load it once in a shared object? Some object inside Application, injected singleton or even another Fragment, which notifies Activity of data load complete and it pushes data to your two Fragments?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top