使用 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时,我什么时候可以再试一次?
这取决于问题的性质。
如果通过布局中的<fragment>
元素设置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 vs MapFragment性能方面