使用 SupportMapFragment 时,我如何知道地图已准备好使用?

Posted

技术标签:

【中文标题】使用 SupportMapFragment 时,我如何知道地图已准备好使用?【英文标题】:How do I know the map is ready to get used when using the SupportMapFragment? 【发布时间】:2012-12-12 09:43:39 【问题描述】:

onCreate 方法中,我使用SupportMapFragment 来显示地图。

    SupportMapFragment fragment = new SupportMapFragment();
    getSupportFragmentManager().beginTransaction()
            .add(android.R.id.content, fragment).commit();

结合这一点,我想添加一个标记。问题是当对getMap 的调用为空时,我什么时候可以再试一次?是否有我可以注册的活动,或者我的方法本身是错误的?

    mMap = ((SupportMapFragment)(getSupportFragmentManager().findFragmentById(R.id.map))).getMap();
    if(mMap == null)
        //what do I do here?

地图实际上显示在手机上,但我似乎没有运气获得添加标记的参考。

更新:

我通过构造函数创建SupportMapFragment 的原因是因为典型的setContentView 崩溃并且不起作用。这使我陷入了无法在onCreate 方法中获得参考的困境,因为当时我实际上正在创建SupportMapFragment。在进一步调查中,我的setContentView 问题似乎是没有将 Google-play-services jar 和 module/src 作为整个项目的一部分设置的副产品。完成这两项操作后,setContentView 现在可以工作了,我可以通过getMap() 获得参考,正如我所期望的那样。

lots.xml...

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
          android:id="@+id/map"
          android:name="com.google.android.gms.maps.SupportMapFragment"
          android:layout_
          android:layout_ />

LotsActivity.java...

public class LotsActivity extends FragmentActivity 
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.lots);

        GoogleMap mMap;
        mMap = ((SupportMapFragment)(getSupportFragmentManager().findFragmentById(R.id.map))).getMap();
        if(mMap == null)
            //this should not occur now
    

【问题讨论】:

Mclver,您应该将解决方案移至答案,然后将其标记为答案,而不是将其作为问题内的编辑。 【参考方案1】:

编辑:getMap is deprecated now

问题是当getMap调用为null时,我什么时候可以再试一次?

这取决于问题的性质。

如果通过布局中的&lt;fragment&gt;元素设置SupportMapFragment,则可以在onCreate()中调用getMap()成功。但是,如果您通过构造函数创建SupportMapFragment,那就太早了——GoogleMap 还不存在。您可以扩展SupportMapFragment 并覆盖onActivityCreated(),因为届时getMap() 已准备就绪。

但是,getMap()也可以返回null,以解决更大的问题,例如未安装 Google Play 服务。您需要使用 GooglePlayServicesUtil.isGooglePlayServicesAvailable() 之类的东西来检测这种情况并按照您的意愿进行处理。

【讨论】:

这是有道理的,并引导我进一步调查setContentView 不起作用的原因。在解决这个问题时,我还解决了获取对 GoogleMap 对象的空引用的问题,您的洞察力帮助我实现了这一点。 @CommonsWare 在哪里“并覆盖 onActivityCreated(),因为此时 getMap() 已准备就绪。” 记录了吗?在我当前的项目中,我仍然在onActivityCreated() 中看到null @WebnetMobile.com:“记录在案?” -- 一个片段的视图在其事务被提交之前不会被创建,因此它在一般片段行为方面是“记录的”。 onActivityCreated() 通常是一种很好的视图创建后生命周期方法。 “我在当前项目中看到 onActivityCreated() 仍然为空”——我无法解释。 正如我已经说过的 - 这种方法对我不起作用。 getMap() 总是在这里返回 null,尽管事实图是可见的。因此,作为记录,对我有用的是扩展SupportMapFragment 并改用它。我在我的子类onCreateView() 中设置了地图。不知道真正的罪魁祸首是什么。 在客户端有关于如何处理的指导:developer.android.com/google/play-services/setup.html#ensure 基本上,如果你处理结果,你可以显示一个对话框并提示用户安装它们。【参考方案2】:

我最终扩展了 SupportMapFragment 类并使用了回调。代码在这里:

public class MySupportMapFragment extends SupportMapFragment 

public MapViewCreatedListener itsMapViewCreatedListener;

// Callback for results

public abstract static class MapViewCreatedListener 
    public abstract void onMapCreated();


@Override
public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
    View view = super.onCreateView(inflater, container, savedInstanceState);
    // Notify the view has been created
    if( itsMapViewCreatedListener != null ) 
        itsMapViewCreatedListener.onMapCreated();
    
    return view;


我宁愿使用一个接口并覆盖 onAttach(activity) 方法,但就我而言,我不希望回调返回到我的 MainActivity。我希望它返回到 Fragment 的一个实例。 (GoogleMap 本质上是一个片段中的一个片段)我设置了回调并用它以编程方式加载了地图。我想在 MySupportMapFragment 的构造函数中设置 itsMapViewCreatedListener,但不鼓励使用无参数构造函数以外的任何东西。

itsMySupportMapFragment = new MySupportMapFragment();
MapViewCreatedListener mapViewCreatedListener = new MapViewCreatedListener() 
    @Override
    public void onMapCreated() 
        initPlacesGoogleMapCtrl();
    
;
itsMySupportMapFragment.itsMapViewCreatedListener = mapViewCreatedListener;
FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.mapFragmentContainer, itsMySupportMapFragment);
transaction.addToBackStack(null);
transaction.commit();

然后,当我接到回电时,我可以拿到地图;不再为空!

public void initPlacesGoogleMapCtrl() 
    // Map ready, get it.
    GoogleMap googleMap = itsMySupportMapFragment.getMap();
    // Do what you want...

【讨论】:

你为什么费心去扩展一个类并创建一个回调...对我来说听起来要简单得多,除非你假装要使用其中的多个。【参考方案3】:

我会评论 CommonsWare 的答案,但我没有足够的代表。无论如何,我也遇到了 getMap() 会在 onActivityCreated 中返回 null 的问题。我的设置是这样的:我的 MainActivity 包含一个片段。在该片段的 onCreateView 方法中,我创建了 SupportMapFragment,然后通过 childFragmentManager 将其添加到片段中。我一直引用 SupportMapFragment 并希望它在 onActivityCreated 中给我地图,但它没有。该问题的解决方案是覆盖 SupportMapFragment 的 onActivityCreated 而不是父片段。我在 onCreateView 中是这样做的:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
    View v = inflater.inflate(R.layout.fragment_location, container, false);
    mMapFragment = new SupportMapFragment() 
        @Override
        public void onActivityCreated(Bundle savedInstanceState) 
            super.onActivityCreated(savedInstanceState);
            mMap = mMapFragment.getMap();
            if (mMap != null) 
                setupMap();
            
        
    ;
    getChildFragmentManager().beginTransaction().add(R.id.framelayout_location_container, mMapFragment).commit();
return v;   

【讨论】:

不应创建非静态内部片段,因为编译器会自动创建构造函数以将外部类作为参数提供给片段。然后在片段重新创建时,您将获得InstantiationException,因为片段没有默认的空构造函数。 这正是我一直在寻找的东西,谢谢!【参考方案4】:

上个月(2014 年 12 月)谷歌给出了这个问题的官方解决方案。在newest (6.5) Google Play Services:

MapView 和 MapFragment 中的 getMap() 方法现已弃用,取而代之的是新的 getMapAsync() 方法。

使用getMapAsync(OnMapReadyCallback callback),您可以设置 GoogleMap 准备就绪时的侦听器。它在回调中传递,并提供为非空。

Google 为此提供了sample code:

public class MainActivity extends FragmentActivity
    implements OnMapReadyCallback 
...

以及在初始化片段时:

MapFragment mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);

当地图准备好时,你的回调将被调用

@Override
public void onMapReady(GoogleMap map) 
    map.addMarker(new MarkerOptions()
        .position(new LatLng(0, 0))
        .title("Marker"));

【讨论】:

所以如果你想要一个 onLongClickListener,它会放在 onMapReady 中吗? 是的,我会这样做【参考方案5】:

如果问题与未初始化的库有关,您也可以使用MapsInitializer.initialize(context);

【讨论】:

这并不能解决当 SupportMapFragment 使用“new”实例化并使用 fragmentTransaction 添加到视图时出现空映射的问题 如果您需要立即使用视图,您可以调用 fragmentManager.executePendingTransactions() 来使提交立即发生。【参考方案6】:

借助最新的 Google 服务,您可以使用 MapFragment.getMapAsync。 直接来自文档

设置一个回调对象,当 GoogleMap 实例可以使用时触发。

【讨论】:

【参考方案7】:

如果 map == null 则查找地图

 if (mGoogleMap == null)
    
        SupportMapFragment mapFragment1 = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);

        mapFragment1.getMapAsync(this);
    

然后调用你的函数 onMapReady();

【讨论】:

以上是关于使用 SupportMapFragment 时,我如何知道地图已准备好使用?的主要内容,如果未能解决你的问题,请参考以下文章

第二次打开 SupportMapFragment 时出错

选项卡上的 SupportMapFragment。我只能看到一次

SupportMapFragment 顶部有自定义视图

SupportMapFragment vs MapFragment性能方面

升级到 SupportMapFragment 后,您需要新的 google api 地图密钥吗?

如何在 SupportMapFragment 中使用 OSMDroid 在地图上启用 LongClick