- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在开发一个使用 v2 MapFragment
的应用程序,但我遇到了非常奇怪的行为。我已经创建了一个 MapFragment
的子类来处理一些自定义行为(处理 Marker
、调整菜单选项等),并且在第一次加载时一切正常。然后我将一个新 fragment 嵌入到我的 Activity 中,将自定义 MapFragment
推送到后台堆栈。但是,当我从后台返回 map 时,事情变得很奇怪;平移 map 变得极度滞后(我们说的是 ~1 FPS),无论是手动拖动/缩放还是点击图钉引起的动画。 然后,如果我与溢出菜单的任何部分进行交互,即使只是打开它并再次关闭它,延迟也会立即消失。似乎没有其他方法可以解决它(除了关闭/重新打开应用程序);与非溢出菜单项和抽屉导航交互无济于事。我从来没有见过这样的事情,也找不到以前描述过类似问题的人。欢迎任何想法、建议和/或修复。
在他们被问到之前回答几个问题:
super
版本(onCreate()
、onCreateView()
[I我还返回 super 返回的内容],以及 onDestroyView()
)。remove()
,然后在 map 本身上调用 clean()
,我在 onDestroyView()
还有。最后,作为引用,这是添加新 fragment 的代码:
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);
}
});
}
}
}
附言我意识到劫持 View 创建并以这种方式注入(inject)我自己的覆盖层可能不是最佳做法,但就其值(value)而言,我尝试将该部分注释掉但它没有解决问题,所以我很怀疑它是相关的。
最佳答案
我遇到过类似的问题。假设我有带有子 SupportMapFragment 的 FragmentA。通过抽屉导航菜单,我调用了一个要显示的对话框。此时 FragmentA 中的子 map 进入某种“背景模式”——它大约每秒更新两次(我在这张 map 上有动画标记,所以这种行为对我来说是众所周知的)。这种“背景”模式是通过显示任何带有覆盖的元素来打开的,例如。对话框或 AppBar 菜单,并在该元素隐藏时关闭。
在对话框中我有项目列表,点击时开始 fragment 替换事务。此时 FragmentA 正在被 FragmentB 取代。这是 OnClickListener 的代码 fragment :
final SmartFragment fragment = new SmartFragment();
FragmentManager supportFragmentManager = getActivity().getSupportFragmentManager();
supportFragmentManager
.beginTransaction()
.replace(R.id.fragment_container, fragment, SmartFragment.FRAGMENT_TAG)
.addToBackStack(null)
.commit();
dismiss();
但是在我从后台返回到 FragmentA 后,保留的 map 仍然处于“背景模式”,即使对话框不再存在。在事务之前移动 dissmiss() 语句无济于事,它看起来就像对话框在执行所有代码之前不会被关闭。因此,唯一合理的解决方案(除了直接在 map fragment 上打开“背景模式”,我找不到如何做)是延迟 fragment 事务,直到对话框真正被关闭。正如我之前假设的那样,只有当 OnClick(它是对话框的一部分)中的所有代码都被执行时才会发生,所以我们需要让事务不在它被声明的实例中完成,而是稍后,将它放在 Runnable 中:
dismiss();
final SmartFragment fragment = new SmartFragment();
Handler handler = new Handler();
final FragmentManager supportFragmentManager = getActivity().getSupportFragmentManager();
handler.post(new Runnable() {
@Override
public void run() {
supportFragmentManager
.beginTransaction()
.replace(R.id.fragment_container, fragment, StopsSmartFragment.FRAGMENT_TAG)
.addToBackStack(null)
.commit();
}
});
为此,我们需要将我们的 fragment 和 supportFragmentManager 设置为最终的。现在一切正常, map 的“后台模式”已关闭,如果您从后台返回到 FragmentA, map 将正常工作。
如果有人知道如何直接关闭 map fragment 中的“背景模式”,请告诉我,我很乐意听到。
关于java - Google Maps v2 MapFragment 在从后台返回时非常滞后,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27978188/
我有一个 k*n矩阵 X 和 k*k矩阵A。对于X的每一列,我想计算标量 X[:, i].T.dot(A).dot(X[:, i]) (或者,数学上, Xi' * A * Xi )。 目前,我有一个
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我是 VueJS 的新手。我已经使用 vuetify/webpack-ssr 模板创建了一个项目,现在我想创建一个登录页面,但是没有显示表单,控制台给了我以下信息: [Vue warn]: Unkno
我尝试将 value 插入到 C++ vector v 之前的第 i 元素(或元素 (i-1) 之后) )。代码很简单 v.insert(v.begin() + i, value); 我确信当 i 介
我需要显示使用合并排序算法排序的 vector 。然而,当我使用 v.begin() 时,我的 friend 使用 v.data() 来传递 vector 。他的代码运行良好,而我的却不行。请解释。
这是我的命令(url1、url2、url3、url4 是占位符): ffmpeg -i url1 -i url2 -i url3 -i url4 -filter_complex “[1:v:0] [1
我以前用过Vue,我知道怎么用v-for渲染元素序列,v-if或v-show有条件地显示元素,并且 v-model例如,控制段落的内容。 但现在我需要对 DOM 进行更精细的控制: 我有一个range
我正在学习所有权和借用。 borrow1 和borrow2 的区别在于在borrow2 打印时使用了&: fn borrow1(v: &Vec) { println!("{}", &v[10]
我找不到一种方法来选择不同的选项来渲染 v-for 中的文本。是否有可能或者我是否需要以不同的方式构建逻辑来执行类似于下面的代码的操作? // i
Iterable 的三个直接子类型是 Map , Seq , 和 Set .除了性能问题之外,似乎还有一个 Seq是从整数到值的映射,以及 Set是从值到 bool 值的映射(如果值在集合中,则为 t
我想应用一个计算方法,如果键存在则增加值,否则将 1。有 Map map = new HashMap<>(); 我不明白为什么 for (int i = 0; i v != null ? v++ :
标准(IEEE 754/C)是否保证以下代码断言永远不会失败? int main() { for ( /* all possible float / double values */ )
代码由Vue语言编写,使用Element-ui框架, 如果一个对象包含某些内容,则会显示该内容,如果不包含则禁用菜单按钮。 输出应该是这样的: a、b(禁用)、c、d、e 但我的是这样的: a、a(禁
如果我这样做: {{ morevalue }} {{ value }} v-else 中的跨度也会在第二个 V-FOR 上循环,即使它上面没有任何 v-for,为什么? 这是
如果我这样做: {{ morevalue }} {{ value }} v-else 中的跨度也会在第二个 V-FOR 上循环,即使它上面没有任何 v-for,为什么? 这是
我将 Vue.js 与 Vuetify 一起使用,我正在尝试使用 v-data-table 从后端加载菜单列表并使用 对其设置一些权限v-switches 但我在尝试 v-model 数组时遇到问题:
我在 Java 的流式操作中努力维护我想要的数据结构,这很可能是由于缺乏正确的理解和实践。 public class Main { public static void main(String
我正在尝试为匹配中的每个匹配呈现一些 HTML,但是,我不太确定 实际上是正确的。 更具体地说,我不确定我是否可以使用 v-bind:match='match'在与循环相同的元素上 v-for='ma
所以我想知道为什么这个 v-if 和 v-else 语句不起作用,为什么我要以不同的方式解决它。 代码如下 Required: Select a Workflow {{ isChain ?
我有一个 VueJS 组件 ,我在同一个模板中使用了两次来显示两组不同的数据。每个都显示在自己的 使用 v-if 切换的容器在导航选项卡上。 似乎这些组件被实例化为同一个实例。我调用 console
我是一名优秀的程序员,十分优秀!