Skip to content

Commit fc29ed6

Browse files
authored
Merge pull request googlemaps-samples#88 from bellarm/java-lite-list-demo
Changed the LiteListDemo to use RecyclerView
2 parents 1a5a5d1 + bf92d73 commit fc29ed6

File tree

7 files changed

+194
-161
lines changed

7 files changed

+194
-161
lines changed

ApiDemos/java/app/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,6 @@ dependencies {
2626
implementation 'com.android.support:appcompat-v7:27.0.2'
2727
implementation 'com.google.android.gms:play-services-maps:11.6.2'
2828
implementation 'com.android.support:support-v4:27.0.2'
29+
// Needed for the LiteListDemo
30+
implementation "com.android.support:recyclerview-v7:27.0.2"
2931
}

ApiDemos/java/app/src/main/java/com/example/mapdemo/LiteListDemoActivity.java

Lines changed: 124 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -24,188 +24,190 @@
2424
import com.google.android.gms.maps.model.LatLng;
2525
import com.google.android.gms.maps.model.MarkerOptions;
2626

27-
import android.content.Context;
2827
import android.os.Bundle;
29-
import android.support.v4.app.ListFragment;
3028
import android.support.v7.app.AppCompatActivity;
29+
import android.support.v7.widget.GridLayoutManager;
30+
import android.support.v7.widget.LinearLayoutManager;
31+
import android.support.v7.widget.RecyclerView;
32+
import android.view.LayoutInflater;
33+
import android.view.Menu;
34+
import android.view.MenuItem;
3135
import android.view.View;
3236
import android.view.ViewGroup;
33-
import android.widget.AbsListView;
34-
import android.widget.ArrayAdapter;
3537
import android.widget.TextView;
3638

37-
import java.util.HashSet;
38-
3939
/**
4040
* This shows to include a map in lite mode in a ListView.
4141
* Note the use of the view holder pattern with the
4242
* {@link com.google.android.gms.maps.OnMapReadyCallback}.
4343
*/
4444
public class LiteListDemoActivity extends AppCompatActivity {
4545

46-
private ListFragment mList;
46+
private RecyclerView mRecyclerView;
4747

48-
private MapAdapter mAdapter;
48+
private LinearLayoutManager mLinearLayoutManager;
49+
private GridLayoutManager mGridLayoutManager;
4950

5051
@Override
5152
protected void onCreate(Bundle savedInstanceState) {
5253
super.onCreate(savedInstanceState);
53-
5454
setContentView(R.layout.lite_list_demo);
5555

56-
// Set a custom list adapter for a list of locations
57-
mAdapter = new MapAdapter(this, LIST_LOCATIONS);
58-
mList = (ListFragment) getSupportFragmentManager().findFragmentById(R.id.list);
59-
mList.setListAdapter(mAdapter);
56+
mGridLayoutManager = new GridLayoutManager(this, 2);
57+
mLinearLayoutManager = new LinearLayoutManager(this);
6058

61-
// Set a RecyclerListener to clean up MapView from ListView
62-
AbsListView lv = mList.getListView();
63-
lv.setRecyclerListener(mRecycleListener);
59+
// Set up the RecyclerView
60+
mRecyclerView = findViewById(R.id.recycler_view);
61+
mRecyclerView.setHasFixedSize(true);
62+
mRecyclerView.setLayoutManager(mLinearLayoutManager);
63+
mRecyclerView.setAdapter(new MapAdapter(LIST_LOCATIONS));
64+
mRecyclerView.setRecyclerListener(mRecycleListener);
65+
}
6466

67+
/** Create a menu to switch between Linear and Grid LayoutManager. */
68+
@Override
69+
public boolean onCreateOptionsMenu(Menu menu) {
70+
getMenuInflater().inflate(R.menu.lite_list_menu, menu);
71+
return true;
72+
}
73+
74+
@Override
75+
public boolean onOptionsItemSelected(MenuItem item) {
76+
switch (item.getItemId()) {
77+
case R.id.layout_linear:
78+
mRecyclerView.setLayoutManager(mLinearLayoutManager);
79+
break;
80+
case R.id.layout_grid:
81+
mRecyclerView.setLayoutManager(mGridLayoutManager);
82+
break;
83+
}
84+
return true;
6585
}
6686

6787
/**
6888
* Adapter that displays a title and {@link com.google.android.gms.maps.MapView} for each item.
6989
* The layout is defined in <code>lite_list_demo_row.xml</code>. It contains a MapView
7090
* that is programatically initialised in
71-
* {@link #getView(int, android.view.View, android.view.ViewGroup)}
91+
* {@link #(int, android.view.View, android.view.ViewGroup)}
7292
*/
73-
private class MapAdapter extends ArrayAdapter<NamedLocation> {
93+
private class MapAdapter extends RecyclerView.Adapter<MapAdapter.ViewHolder> {
7494

75-
private final HashSet<MapView> mMaps = new HashSet<MapView>();
95+
private NamedLocation[] namedLocations;
7696

77-
public MapAdapter(Context context, NamedLocation[] locations) {
78-
super(context, R.layout.lite_list_demo_row, R.id.lite_listrow_text, locations);
97+
private MapAdapter(NamedLocation[] locations) {
98+
super();
99+
namedLocations = locations;
79100
}
80101

81-
82102
@Override
83-
public View getView(int position, View convertView, ViewGroup parent) {
84-
View row = convertView;
85-
ViewHolder holder;
86-
87-
// Check if a view can be reused, otherwise inflate a layout and set up the view holder
88-
if (row == null) {
89-
// Inflate view from layout file
90-
row = getLayoutInflater().inflate(R.layout.lite_list_demo_row, null);
91-
92-
// Set up holder and assign it to the View
93-
holder = new ViewHolder();
94-
holder.mapView = (MapView) row.findViewById(R.id.lite_listrow_map);
95-
holder.title = (TextView) row.findViewById(R.id.lite_listrow_text);
96-
// Set holder as tag for row for more efficient access.
97-
row.setTag(holder);
98-
99-
// Initialise the MapView
100-
holder.initializeMapView();
101-
102-
// Keep track of MapView
103-
mMaps.add(holder.mapView);
104-
} else {
105-
// View has already been initialised, get its holder
106-
holder = (ViewHolder) row.getTag();
107-
}
108-
109-
// Get the NamedLocation for this item and attach it to the MapView
110-
NamedLocation item = getItem(position);
111-
holder.mapView.setTag(item);
112-
113-
// Ensure the map has been initialised by the on map ready callback in ViewHolder.
114-
// If it is not ready yet, it will be initialised with the NamedLocation set as its tag
115-
// when the callback is received.
116-
if (holder.map != null) {
117-
// The map is already ready to be used
118-
setMapLocation(holder.map, item);
119-
}
120-
121-
// Set the text label for this item
122-
holder.title.setText(item.name);
123-
124-
return row;
103+
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
104+
return new ViewHolder(LayoutInflater.from(parent.getContext())
105+
.inflate(R.layout.lite_list_demo_row, parent, false));
125106
}
126107

127108
/**
128-
* Retuns the set of all initialised {@link MapView} objects.
129-
*
130-
* @return All MapViews that have been initialised programmatically by this adapter
109+
* This function is called when the user scrolls through the screen and a new item needs
110+
* to be shown. So we will need to bind the holder with the details of the next item.
131111
*/
132-
public HashSet<MapView> getMaps() {
133-
return mMaps;
112+
@Override
113+
public void onBindViewHolder(ViewHolder holder, int position) {
114+
if (holder == null) {
115+
return;
116+
}
117+
holder.bindView(position);
134118
}
135-
}
136119

137-
/**
138-
* Displays a {@link LiteListDemoActivity.NamedLocation} on a
139-
* {@link com.google.android.gms.maps.GoogleMap}.
140-
* Adds a marker and centers the camera on the NamedLocation with the normal map type.
141-
*/
142-
private static void setMapLocation(GoogleMap map, NamedLocation data) {
143-
// Add a marker for this item and set the camera
144-
map.moveCamera(CameraUpdateFactory.newLatLngZoom(data.location, 13f));
145-
map.addMarker(new MarkerOptions().position(data.location));
120+
@Override
121+
public int getItemCount() {
122+
return namedLocations.length;
123+
}
146124

147-
// Set the map type back to normal.
148-
map.setMapType(GoogleMap.MAP_TYPE_NORMAL);
149-
}
125+
/**
126+
* Holder for Views used in the {@link LiteListDemoActivity.MapAdapter}.
127+
* Once the the <code>map</code> field is set, otherwise it is null.
128+
* When the {@link #onMapReady(com.google.android.gms.maps.GoogleMap)} callback is received and
129+
* the {@link com.google.android.gms.maps.GoogleMap} is ready, it stored in the {@link #map}
130+
* field. The map is then initialised with the NamedLocation that is stored as the tag of the
131+
* MapView. This ensures that the map is initialised with the latest data that it should
132+
* display.
133+
*/
134+
class ViewHolder extends RecyclerView.ViewHolder implements OnMapReadyCallback {
135+
136+
MapView mapView;
137+
TextView title;
138+
GoogleMap map;
139+
View layout;
140+
141+
private ViewHolder(View itemView) {
142+
super(itemView);
143+
layout = itemView;
144+
mapView = layout.findViewById(R.id.lite_listrow_map);
145+
title = layout.findViewById(R.id.lite_listrow_text);
146+
if (mapView != null) {
147+
// Initialise the MapView
148+
mapView.onCreate(null);
149+
// Set the map ready callback to receive the GoogleMap object
150+
mapView.getMapAsync(this);
151+
}
152+
}
150153

151-
/**
152-
* Holder for Views used in the {@link LiteListDemoActivity.MapAdapter}.
153-
* Once the the <code>map</code> field is set, otherwise it is null.
154-
* When the {@link #onMapReady(com.google.android.gms.maps.GoogleMap)} callback is received and
155-
* the {@link com.google.android.gms.maps.GoogleMap} is ready, it stored in the {@link #map}
156-
* field. The map is then initialised with the NamedLocation that is stored as the tag of the
157-
* MapView. This ensures that the map is initialised with the latest data that it should
158-
* display.
159-
*/
160-
class ViewHolder implements OnMapReadyCallback {
154+
@Override
155+
public void onMapReady(GoogleMap googleMap) {
156+
MapsInitializer.initialize(getApplicationContext());
157+
map = googleMap;
158+
setMapLocation();
159+
}
161160

162-
MapView mapView;
161+
/**
162+
* Displays a {@link LiteListDemoActivity.NamedLocation} on a
163+
* {@link com.google.android.gms.maps.GoogleMap}.
164+
* Adds a marker and centers the camera on the NamedLocation with the normal map type.
165+
*/
166+
private void setMapLocation() {
167+
if (map == null) return;
163168

164-
TextView title;
169+
NamedLocation data = (NamedLocation) mapView.getTag();
170+
if (data == null) return;
165171

166-
GoogleMap map;
172+
// Add a marker for this item and set the camera
173+
map.moveCamera(CameraUpdateFactory.newLatLngZoom(data.location, 13f));
174+
map.addMarker(new MarkerOptions().position(data.location));
167175

168-
@Override
169-
public void onMapReady(GoogleMap googleMap) {
170-
MapsInitializer.initialize(getApplicationContext());
171-
map = googleMap;
172-
NamedLocation data = (NamedLocation) mapView.getTag();
173-
if (data != null) {
174-
setMapLocation(map, data);
176+
// Set the map type back to normal.
177+
map.setMapType(GoogleMap.MAP_TYPE_NORMAL);
175178
}
176-
}
177179

178-
/**
179-
* Initialises the MapView by calling its lifecycle methods.
180-
*/
181-
public void initializeMapView() {
182-
if (mapView != null) {
183-
// Initialise the MapView
184-
mapView.onCreate(null);
185-
// Set the map ready callback to receive the GoogleMap object
186-
mapView.getMapAsync(this);
180+
private void bindView(int pos) {
181+
NamedLocation item = namedLocations[pos];
182+
// Store a reference of the ViewHolder object in the layout.
183+
layout.setTag(this);
184+
// Store a reference to the item in the mapView's tag. We use it to get the
185+
// coordinate of a location, when setting the map location.
186+
mapView.setTag(item);
187+
setMapLocation();
188+
title.setText(item.name);
187189
}
188190
}
189-
190191
}
191192

192193
/**
193194
* RecycleListener that completely clears the {@link com.google.android.gms.maps.GoogleMap}
194-
* attached to a row in the ListView.
195+
* attached to a row in the RecyclerView.
195196
* Sets the map type to {@link com.google.android.gms.maps.GoogleMap#MAP_TYPE_NONE} and clears
196197
* the map.
197198
*/
198-
private AbsListView.RecyclerListener mRecycleListener = new AbsListView.RecyclerListener() {
199+
private RecyclerView.RecyclerListener mRecycleListener = new RecyclerView.RecyclerListener() {
199200

200201
@Override
201-
public void onMovedToScrapHeap(View view) {
202-
ViewHolder holder = (ViewHolder) view.getTag();
203-
if (holder != null && holder.map != null) {
204-
// Clear the map and free up resources by changing the map type to none
205-
holder.map.clear();
206-
holder.map.setMapType(GoogleMap.MAP_TYPE_NONE);
202+
public void onViewRecycled(RecyclerView.ViewHolder holder) {
203+
MapAdapter.ViewHolder mapHolder = (MapAdapter.ViewHolder) holder;
204+
if (mapHolder != null && mapHolder.map != null) {
205+
// Clear the map and free up resources by changing the map type to none.
206+
// Also reset the map when it gets reattached to layout, so the previous map would
207+
// not be displayed.
208+
mapHolder.map.clear();
209+
mapHolder.map.setMapType(GoogleMap.MAP_TYPE_NONE);
207210
}
208-
209211
}
210212
};
211213

@@ -216,7 +218,6 @@ public void onMovedToScrapHeap(View view) {
216218
private static class NamedLocation {
217219

218220
public final String name;
219-
220221
public final LatLng location;
221222

222223
NamedLocation(String name, LatLng location) {
Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,22 @@
1-
<?xml version="1.0" encoding="utf-8"?><!--
2-
Copyright (C) 2014 The Android Open Source Project
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
Copyright 2018 Google LLC
34
4-
Licensed under the Apache License, Version 2.0 (the "License");
5-
you may not use this file except in compliance with the License.
6-
You may obtain a copy of the License at
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
78
8-
http://www.apache.org/licenses/LICENSE-2.0
9+
https://www.apache.org/licenses/LICENSE-2.0
910
10-
Unless required by applicable law or agreed to in writing, software
11-
distributed under the License is distributed on an "AS IS" BASIS,
12-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
See the License for the specific language governing permissions and
14-
limitations under the License.
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
1516
-->
16-
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
17+
<android.support.v7.widget.RecyclerView
18+
xmlns:android="http://schemas.android.com/apk/res/android"
19+
android:id="@+id/recycler_view"
20+
android:scrollbars="vertical"
1721
android:layout_width="match_parent"
18-
android:layout_height="match_parent">
19-
20-
<fragment
21-
android:id="@+id/list"
22-
class="android.support.v4.app.ListFragment"
23-
android:layout_width="match_parent"
24-
android:layout_height="match_parent" />
25-
26-
</FrameLayout>
22+
android:layout_height="match_parent" />

0 commit comments

Comments
 (0)