I have 2 views of essentially the same data:
- List of items in a android.support.v4.app.ListFragment
- 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:
- 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).
- 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).
- (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:
Borrow BusProvider class from Otto's sample code.
Create few message contracts to carry notification data:
public class LocationSelectedEvent { public long id; } public class LocationsLoadedEvent { public Cursor cursor; }
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); }
Make fragments "listening" to notifications:
@Override public void onActivityCreated(Bundle savedInstanceState) { BusProvider.getInstance().register(this); }
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); }
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
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
?
来源:https://stackoverflow.com/questions/16688073/synchronize-listfragment-and-supportmapfragment-selection