【发布时间】:2015-03-14 17:12:47
【问题描述】:
我正在开发一个使用 v2 MapFragment 的应用程序,我遇到了非常奇怪的行为。我创建了一个MapFragment 的子类来处理一些自定义行为(处理Markers,调整菜单选项等),并且在第一次加载时它一切正常。然后我将一个新片段嵌入到我的活动中,将自定义 MapFragment 推到后台堆栈中。但是,当我从后台返回地图时,事情变得很奇怪。平移地图变得非常滞后(我们说的是~1 FPS),无论是手动拖动/缩放还是通过单击图钉引起的动画。 然后,如果我与溢出菜单的任何部分进行交互,即使只是打开它并再次关闭它,延迟也会立即消除。似乎没有其他方法可以解决它(除了关闭/重新打开应用程序);与非溢出菜单项和导航抽屉交互无济于事。我从来没有见过这样的事情,也找不到以前描述过类似问题的人。欢迎任何想法、建议和/或修复。
在被问到之前回答几个问题:
- 是的,我正在调用我覆盖的所有生命周期方法的
super版本(onCreate()、onCreateView()[我还返回了 super 返回的内容] 和onDestroyView())。 - 据我所知,我正在正确地清理地图。每次我刷新图钉时,我都会在每个图钉上调用
remove(),然后在地图本身上调用clean(),我也在onDestroyView()中执行所有这些操作。
最后,作为参考,这是添加新片段的代码:
getFragmentManager().beginTransaction().replace(R.id.main_content_container, new JoinGroupFragment()).addToBackStack(null).commit();
当我完成它时,我只是打电话:
getFragmentManager().popBackStack();
编辑:我不确定它会有多大帮助,但这是自定义的MapFragment:
public class CustomMapFragment extends MapFragment {
private static final String DIALOG_TAG = "CUSTOM_MAP_FRAGMENT_DIALOG";
private static final int DEFAULT_ZOOM = 14;
private static final int MARKER_ZOOM = 15;
private static final int DEFAULT_PADDING = 80;
private static final int ORANGE_THRESHOLD_MINUTES = 7;
private static final int BLUE_THRESHOLD_MINUTES = 20;
public static final String KEY_GROUP_NAME = "GROUP_NAME";
public static final String KEY_GROUP_ID = "GROUP_ID";
private TextView mGroupNameOverlay;
private GoogleMap mMap;
private ArrayList<Marker> mMarkers;
private Marker mSelectedMarker;
private ArrayList<Group> mAllGroups;
private Group mCurrentGroup;
private ArrayList<Location> mAllLocations;
private boolean mMapReady;
private String mUsername;
private boolean mCenterOnUser;
public CustomMapFragment() {
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
mMarkers = new ArrayList<>();
mAllLocations = new ArrayList<>();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
mUsername = prefs.getString(PreferenceUtils.KEY_USERNAME, null);
mCenterOnUser = prefs.getBoolean(PreferenceUtils.KEY_CENTER_ON_ME, false);
mSelectedMarker = null;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ViewGroup view = (ViewGroup)super.onCreateView(inflater, container, savedInstanceState);
if (view != null) {
// View should never be null; MapFragments have a FrameLayout as their top level parent
mGroupNameOverlay = (TextView)inflater.inflate(R.layout.group_name_overlay, view, false);
view.addView(mGroupNameOverlay);
}
Bundle results = ((MainActivity)getActivity()).getFragmentResults();
if (results != null) {
String name = results.getString(KEY_GROUP_NAME);
String id = results.getString(KEY_GROUP_ID);
if (!StringUtils.isNullOrEmpty(name) && !StringUtils.isNullOrEmpty(id)) {
mCurrentGroup = new Group(name, id);
mAllGroups.add(mCurrentGroup);
}
}
if (mCurrentGroup != null) {
updateGroupNameOverlay(mCurrentGroup.getGroupName());
}
getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
@Override
public boolean onMarkerClick(Marker marker) {
mSelectedMarker = marker;
getActivity().invalidateOptionsMenu();
return false;
}
});
mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
@Override
public void onMapClick(LatLng latLng) {
mSelectedMarker = null;
getActivity().invalidateOptionsMenu();
}
});
populateMap(true, false);
}
});
GetGroupsRequest request = new GetGroupsRequest();
request.setListener(new GetGroupsRequestListener());
RequestProcessor.getInstance(getActivity()).queueRequest(request);
return view;
}
@Override
public void onDestroyView() {
mSelectedMarker = null;
for (Marker marker : mMarkers) {
marker.remove();
}
mMarkers.clear();
mMap.clear();
mMap = null;
mMapReady = false;
super.onDestroyView();
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if (mSelectedMarker == null) {
inflater.inflate(R.menu.menu_map, menu);
}
else {
inflater.inflate(R.menu.menu_marker, menu);
}
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.map_menu_refresh_pins:
performLocationsRequest(false);
return true;
case R.id.map_menu_recenter_zoom:
populateMap(true, true);
return true;
case R.id.map_menu_select_group:
DialogFragment selectDialog = new DialogFragment() {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
String[] groups = new String[mAllGroups.size()];
for (int i = 0; i < groups.length; i++) {
groups[i] = mAllGroups.get(i).getGroupName();
}
return new AlertDialog.Builder(getActivity())
.setItems(groups, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (!mAllGroups.get(which).equals(mCurrentGroup)) {
mCurrentGroup = mAllGroups.get(which);
updateGroupNameOverlay(mCurrentGroup.getGroupName());
performLocationsRequest(true);
}
}
})
.create();
}
};
selectDialog.show(getFragmentManager(), DIALOG_TAG);
return true;
case R.id.map_menu_join_group:
getFragmentManager().beginTransaction().replace(R.id.main_content_container, new JoinGroupFragment()).addToBackStack(null).commit();
return true;
case R.id.map_menu_create_group:
CreateDialogFragment createDialog = new CreateDialogFragment();
createDialog.show(getFragmentManager(), DIALOG_TAG);
return true;
case R.id.map_marker_zoom:
if (mSelectedMarker != null) {
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(mSelectedMarker.getPosition(), MARKER_ZOOM));
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void performLocationsRequest(boolean autoZoom) {
GetLocationsRequest request = new GetLocationsRequest(mCurrentGroup.getGroupId());
request.setListener(new GetLocationsRequestListener(autoZoom));
RequestProcessor.getInstance(getActivity()).queueRequest(request);
}
private void updateGroupNameOverlay(final String groupName) {
if (mGroupNameOverlay != null) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
if (groupName == null) {
mGroupNameOverlay.setText(R.string.map_group_overlay_no_group);
}
else {
mGroupNameOverlay.setText(getString(R.string.map_group_overlay_group, groupName));
}
}
});
}
}
private void populateMap(boolean zoom, boolean animate) {
if (!mMapReady) {
mMapReady = true;
}
else {
CameraUpdate update = null;
mSelectedMarker = null;
for (Marker marker : mMarkers) {
marker.remove();
}
mMarkers.clear();
mMap.clear();
if (mAllLocations.size() == 1) {
Location location = mAllLocations.get(0);
mMarkers.add(addMarker(location));
update = CameraUpdateFactory.newLatLngZoom(new LatLng(location.getLatitude(), location.getLongitude()), DEFAULT_ZOOM);
}
else if (mAllLocations.size() > 1) {
LatLngBounds.Builder builder = new LatLngBounds.Builder();
for (Location location : mAllLocations) {
mMarkers.add(addMarker(location));
if (mCenterOnUser) {
if (location.getUsername().equals(mUsername)) {
update = CameraUpdateFactory.newLatLngZoom(new LatLng(location.getLatitude(), location.getLongitude()), DEFAULT_ZOOM);
}
}
else {
builder.include(new LatLng(location.getLatitude(), location.getLongitude()));
}
}
if (!mCenterOnUser) {
update = CameraUpdateFactory.newLatLngBounds(builder.build(), DEFAULT_PADDING);
}
}
if (update != null && zoom) {
if (animate) {
mMap.animateCamera(update);
}
else {
mMap.moveCamera(update);
}
}
}
}
private Marker addMarker(Location location) {
String timestamp;
long minutesOld = (new Date().getTime() - location.getLastReported()) / 60000;
float hue = BitmapDescriptorFactory.HUE_RED;
if (minutesOld < 1) {
timestamp = getString(R.string.map_timestamp_just_now);
}
else if (minutesOld < 2) {
timestamp = getString(R.string.map_timestamp_one_minute);
}
else {
timestamp = getString(R.string.map_timestamp_n_minutes, minutesOld);
if (minutesOld >= ORANGE_THRESHOLD_MINUTES) {
hue = BitmapDescriptorFactory.HUE_ORANGE;
}
if (minutesOld >= BLUE_THRESHOLD_MINUTES) {
hue = BitmapDescriptorFactory.HUE_BLUE;
}
}
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
return mMap.addMarker(new MarkerOptions()
.position(latLng)
.icon(BitmapDescriptorFactory.defaultMarker(hue))
.title(location.getUsername())
.snippet(timestamp));
}
private class GetGroupsRequestListener extends RequestListener<GetGroupsResponse> {
public GetGroupsRequestListener() {
super(getActivity());
}
@Override
protected void onRequestComplete(GetGroupsResponse response) {
mAllGroups = response.getGroups();
if (mAllGroups.size() > 0) {
if (mCurrentGroup == null) {
mCurrentGroup = mAllGroups.get(0);
updateGroupNameOverlay(mCurrentGroup.getGroupName());
}
performLocationsRequest(true);
}
}
}
private class GetLocationsRequestListener extends RequestListener<GetLocationsResponse> {
private boolean mmAutoZoom;
public GetLocationsRequestListener(boolean autoZoom) {
super(getActivity());
mmAutoZoom = autoZoom;
}
@Override
protected void onRequestComplete(GetLocationsResponse response) {
mAllLocations = response.getLocations();
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
populateMap(mmAutoZoom, false);
}
});
}
}
}
附:我意识到以这种方式劫持视图创建并注入我自己的叠加层可能不是最佳实践,但为了它的价值,我尝试评论那部分并没有解决问题,所以我很怀疑它是相关的。
【问题讨论】:
-
如果您以这种方式处理,stackoverflow.com/questions/21815818/… 和 stackoverflow.com/questions/16265346/… 将为您提供帮助。由于您尚未发布代码,因此很难理解确切的场景
-
在发布我的问题之前,我查看了这两个问题,但没有发现任何一个特别有用。第一个是不同的问题(初始地图加载延迟),第二个显然是通过巫毒魔法解决的。至于发布更多代码,我可以;我没有这样做的主要原因是因为我不知道哪些部分实际上是有用的。
标签: java android google-maps-android-api-2