草庐IT

java - Google Maps v2 MapFragment 在从后台返回时非常滞后

coder 2023-12-04 原文

我正在开发一个使用 v2 MapFragment 的应用程序,但我遇到了非常奇怪的行为。我已经创建了一个 MapFragment 的子类来处理一些自定义行为(处理 Marker、调整菜单选项等),并且在第一次加载时一切正常。然后我将一个新 fragment 嵌入到我的 Activity 中,将自定义 MapFragment 推送到后台堆栈。但是,当我从后台返回 map 时,事情变得很奇怪;平移 map 变得极度滞后(我们说的是 ~1 FPS),无论是手动拖动/缩放还是点击图钉引起的动画。 然后,如果我与溢出菜单的任何部分进行交互,即使只是打开它并再次关闭它,延迟也会立即消失。似乎没有其他方法可以解决它(除了关闭/重新打开应用程序);与非溢出菜单项和抽屉导航交互无济于事。我从来没有见过这样的事情,也找不到以前描述过类似问题的人。欢迎任何想法、建议和/或修复。

在他们被问到之前回答几个问题:

  • 是的,我正在调用我覆盖的所有生命周期方法的 super 版本(onCreate()onCreateView() [I我还返回 super 返回的内容],以及 onDestroyView())。
  • 据我所知,我正在正确清理 map 。每次刷新图钉时,我都会在每个图钉上调用 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/

有关java - Google Maps v2 MapFragment 在从后台返回时非常滞后的更多相关文章

  1. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  2. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  3. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  4. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  5. Observability:从零开始创建 Java 微服务并监控它 (二) - 2

    这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/

  6. 【Java 面试合集】HashMap中为什么引入红黑树,而不是AVL树呢 - 2

    HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候

  7. 【Java入门】使用Java实现文件夹的遍历 - 2

    遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg

  8. java - 为什么 ruby​​ modulo 与 java/other lang 不同? - 2

    我基本上来自Java背景并且努力理解Ruby中的模运算。(5%3)(-5%3)(5%-3)(-5%-3)Java中的上述操作产生,2个-22个-2但在Ruby中,相同的表达式会产生21个-1-2.Ruby在逻辑上有多擅长这个?模块操作在Ruby中是如何实现的?如果将同一个操作定义为一个web服务,两个服务如何匹配逻辑。 最佳答案 在Java中,模运算的结果与被除数的符号相同。在Ruby中,它与除数的符号相同。remainder()在Ruby中与被除数的符号相同。您可能还想引用modulooperation.

  9. java - Ruby 相当于 Java 的 Collections.unmodifiableList 和 Collections.unmodifiableMap - 2

    Java的Collections.unmodifiableList和Collections.unmodifiableMap在Ruby标准API中是否有等价物? 最佳答案 使用freeze应用程序接口(interface):Preventsfurthermodificationstoobj.ARuntimeErrorwillberaisedifmodificationisattempted.Thereisnowaytounfreezeafrozenobject.SeealsoObject#frozen?.Thismethodretur

  10. ruby - 如何在 ruby​​ 中运行后台线程? - 2

    我是ruby​​的新手,我认为重新构建一个我用C#编写的简单聊天程序是个好主意。我正在使用Ruby2.0.0MRI(Matz的Ruby实现)。问题是我想在服务器运行时为简单的服务器命令提供I/O。这是从示例中获取的服务器。我添加了使用gets()获取输入的命令方法。我希望此方法在后台作为线程运行,但该线程正在阻塞另一个线程。require'socket'#Getsocketsfromstdlibserver=TCPServer.open(2000)#Sockettolistenonport2000defcommandsx=1whilex==1exitProgram=gets.chomp

随机推荐