片段中的 MapView(蜂窝)
Posted
技术标签:
【中文标题】片段中的 MapView(蜂窝)【英文标题】:MapView in a Fragment (Honeycomb) 【发布时间】:2011-07-03 19:40:21 【问题描述】:现在最终的 SDK 已经与 google api 一起发布了 - 使用 MapView 创建 Fragment 的最佳方法是什么? MapView 需要一个 MapActivity 才能正常工作。
让 Activity 管理 Fragments 从 MapActivity 继承(不好的解决方案,因为它违背了 Fragments 是自包含的想法)并且使用基于 xml 的常规布局不起作用。我在 MapActivity.setupMapView() 中得到 NullPointerException:
E/androidRuntime(597):引起:java.lang.NullPointerException E/AndroidRuntime(597):在 com.google.android.maps.MapActivity.setupMapView(MapActivity.java:400) E/AndroidRuntime(597):在 com.google.android.maps.MapView.(MapView.java:289) E/AndroidRuntime(597):在 com.google.android.maps.MapView.(MapView.java:264) E/AndroidRuntime(597):在 com.google.android.maps.MapView.(MapView.java:247)我的第二个想法是以编程方式创建 MapView 并将关联的活动(通过 getActivity())作为上下文传递给 MapView 构造函数。不工作:
E/AndroidRuntime(834):原因:java.lang.IllegalArgumentException:MapViews 只能在 MapActivity 的实例中创建。 E/AndroidRuntime(834):在 com.google.android.maps.MapView.(MapView.java:291) E/AndroidRuntime(834):在 com.google.android.maps.MapView.(MapView.java:235) E/AndroidRuntime(834):在 de.foo.FinderMapFragment.onCreateView(FinderMapFragment.java:225) E/AndroidRuntime(834):在 android.app.FragmentManagerImpl.moveToState(FragmentManager.java:708) E/AndroidRuntime(834):在 android.app.FragmentManagerImpl.moveToState(FragmentManager.java:900) E/AndroidRuntime(834):在 android.app.FragmentManagerImpl.addFragment(FragmentManager.java:978) E/AndroidRuntime(834):在 android.app.Activity.onCreateView(Activity.java:4090) E/AndroidRuntime(834):在 android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:664)真的应该有像 MapFragment 这样的东西来处理 MapView 需要的后台线程我猜......那么目前的最佳实践是什么?
来自德国的感谢和问候, 瓦伦丁
【问题讨论】:
我报告了一个功能请求。请给它加星。 code.google.com/p/android/issues/detail?id=15347 【参考方案1】:我已经设法通过在片段中使用 TabHost 来解决这个问题。
这是想法(简要):
MainFragmentActivity
扩展 FragmentActivity
(来自支持库)并具有 MapFragment
。
MyMapActivity
扩展 MapActivity
并包含 MapView
。
LocalActivityManagerFragment
主机LocalActivityManager
MapFragment
扩展LocalActivityManagerFragment
。
其中LocalActivityManager
包含MyMapActivity
活动。
示例实现:https://github.com/inazaruk/map-fragment。
【讨论】:
如果您希望 MapActivity 能够与父 Activity 通信(使用 Fragment 很容易),那么您可以使用 Activity.getParent() 您实际上不需要使用 TabHost,您也可以只使用 LocalActivityManager 并将返回的窗口附加到片段的内容 如果其他人想知道,这里是代码:Intent i = new Intent(getActivity().getParent(), MyMapActivity.class); Window w = localActivityManager.startActivity("tag", i); currentView=w.getDecorView(); currentView.setVisibility(View.VISIBLE); currentView.setFocusableInTouchMode(true); ((ViewGroup) currentView).setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); this.contentView.addView(currentView);
小心,LocalActivityManager 现已弃用
使用标签和片段对我来说效果很好。对于那些询问解释的人,我宁愿看项目及其代码,这很容易理解。是的,LocalActivityManager
已被弃用,但这只是一个 hack,当他们决定在 Fragments 中包含对 Maps 的适当支持时,这个问题将得到妥善解决。【参考方案2】:
正如Google Groups 所讨论的,Peter Doyle 也构建了一个支持 Google 地图的自定义兼容性库。 android-support-v4-googlemaps
不过,也有不利的一面:
目前,一个缺点是所有扩展 FragmentActivity 的类都是 MapActivity。可以创建一个单独的类(即 FragmentMapActivity),但需要对 FragmentActivity 代码进行一些重构。
【讨论】:
这也意味着您的应用将不会与最新的支持库保持同步。虽然 android-support-v4-googlemaps 已更新多次,但目前落后 2 个版本。我同意其他人的观点,即这个修改后的库比使用已弃用的 LocalActivityManager 更大。 github.com/petedoyle/android-support-v4-googlemaps 现在是最新的(截至本消息的 r10)。我还重构了一些东西,因此将来保持最新状态会非常容易。 我有一个问题。如果应用已经部署安装好了,“没有更新到最新的支持库”有什么坏处? IMO 这种方法的主要问题是您将无法使用可选的地图支持部署您的应用程序。由于所有 FragmentActivity 都扩展了 MapActivity,它只会在没有 Google API 的设备上崩溃(例如 Kindle Fire)。【参考方案3】:只是为了澄清答案。我尝试了 inazaruk 和 ChristophK 建议的方法。实际上,您可以在片段中运行任何活动 - 不仅仅是谷歌地图。由于 inazaruk 和 ChristophK,这是将谷歌地图活动作为片段实现的代码。
import com.actionbarsherlock.app.SherlockFragment;
import android.view.Window;
import android.app.LocalActivityManager;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class MapFragment extends SherlockFragment
private static final String KEY_STATE_BUNDLE = "localActivityManagerState";
private LocalActivityManager mLocalActivityManager;
protected LocalActivityManager getLocalActivityManager()
return mLocalActivityManager;
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
Bundle state = null;
if (savedInstanceState != null)
state = savedInstanceState.getBundle(KEY_STATE_BUNDLE);
mLocalActivityManager = new LocalActivityManager(getActivity(), true);
mLocalActivityManager.dispatchCreate(state);
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
//This is where you specify you activity class
Intent i = new Intent(getActivity(), GMapActivity.class);
Window w = mLocalActivityManager.startActivity("tag", i);
View currentView=w.getDecorView();
currentView.setVisibility(View.VISIBLE);
currentView.setFocusableInTouchMode(true);
((ViewGroup) currentView).setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
return currentView;
@Override
public void onSaveInstanceState(Bundle outState)
super.onSaveInstanceState(outState);
outState.putBundle(KEY_STATE_BUNDLE,
mLocalActivityManager.saveInstanceState());
@Override
public void onResume()
super.onResume();
mLocalActivityManager.dispatchResume();
@Override
public void onPause()
super.onPause();
mLocalActivityManager.dispatchPause(getActivity().isFinishing());
@Override
public void onStop()
super.onStop();
mLocalActivityManager.dispatchStop();
@Override
public void onDestroy()
super.onDestroy();
mLocalActivityManager.dispatchDestroy(getActivity().isFinishing());
【讨论】:
但唯一避免LocalActivityManager
(如此处讨论:code.google.com/p/android/issues/detail?id=15347)的解决方案涉及扩展all FragmentActivities
,这似乎更不理想。
LocalActivityManager 更被弃用,因为 ActivityGroup 已被弃用,在这种情况下仍然有用,如果人们使用它来解决他们的缺点,Google 可能会三思而后行在未来的版本中将其淘汰。【参考方案4】:
截至 2012 年 12 月 3 日,Google 发布了 Google Maps Android API v2。现在你可以忘记这些问题了。 https://developers.google.com/maps/documentation/android/
使用新 API 的示例 - https://developers.google.com/maps/documentation/android/start#add_a_map
此 API 至少适用于 Android API 8,因此请使用它;)。
所以现在您可以简单地使用“com.google.android.gms.maps.MapFragment”片段类。它将在您的活动中显示地图。上面链接中的布局示例:
<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/map"
android:layout_
android:layout_
class="com.google.android.gms.maps.MapFragment"/>
【讨论】:
【参考方案5】:来自 Google 的好消息。他们今天发布了new Google Maps API,其中包含室内地图和 MapFragment。
With this new API, adding a map to your Activity is as simple as:
<fragment
android:id="@+id/map"
android:layout_
android:layout_
class="com.google.android.gms.maps.MapFragment" />
【讨论】:
不完全是。尝试在 FragmentPagerAdapter 中使用它。 如果你在谈论黑色视图,有一个小技巧可以修复它***.com/questions/13837697/… 谢谢。后来我终于看到了,但我现在正在使用第一个带有北极星的地图 api 版本。【参考方案6】:Google Maps API 不属于 AOSP。只要没有 Google 员工回应,就几乎不可能判断未来是否会有 MapFragment。
一种可能的有限替代方法是使用WebViewFragment
并滥用它来加载自定义maps.google.com
URL。
【讨论】:
希望 Map API 能尽快更新片段和矢量图!【参考方案7】:抱歉,Google 尚未做出回应。 FWIW,如果您真的需要这样做,我没有其他办法:
让选项卡管理活动从 MapActivity 继承,以编程方式在其中创建 MapView,让 mapfragment.xml 包含一个 ViewGroup 并使用将 MapView 添加到 ViewGroup 中
((ViewGroup) getFragmentManager().findFragmentById(R.id.finder_map_fragment).getView()).addView(mapView);;显然,这与片段被认为是独立的但......
【讨论】:
谢谢,让 Fragment 管理 Activity 扩展 MapActivity 非常适合我。【参考方案8】:这是一个非常简化的 MapFragment 的 MonoDroid(Mono for Android)版本:
public class MapFragment : Fragment
// FOLLOW http://***.com/questions/5109336/mapview-in-a-fragment-honeycomb
private static String KEY_STATE_BUNDLE = "localActivityManagerState";
public override void OnCreate(Bundle savedInstanceState)
base.OnCreate(savedInstanceState);
Bundle state = null;
if (savedInstanceState != null)
state = savedInstanceState.GetBundle(KEY_STATE_BUNDLE);
mLocalActivityManager = new LocalActivityManager(Activity, true);
mLocalActivityManager.DispatchCreate(state);
public override Android.Views.View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
//This is where you specify you activity class
Intent i = new Intent(Activity, typeof(SteamLocationMapActivity));
Window w = mLocalActivityManager.StartActivity("tag", i);
View currentView=w.DecorView;
currentView.Visibility = ViewStates.Visible;
currentView.FocusableInTouchMode = true;
((ViewGroup) currentView).DescendantFocusability = DescendantFocusability.AfterDescendants;
return currentView;
private LocalActivityManager mLocalActivityManager;
protected LocalActivityManager GetLocalActivityManager()
return mLocalActivityManager;
public override void OnSaveInstanceState(Bundle outState)
base.OnSaveInstanceState(outState);
outState.PutBundle(KEY_STATE_BUNDLE,mLocalActivityManager.SaveInstanceState());
public override void OnResume()
base.OnResume();
mLocalActivityManager.DispatchResume();
public override void OnPause()
base.OnPause();
mLocalActivityManager.DispatchPause(Activity.IsFinishing);
public override void OnStop()
base.OnStop();
mLocalActivityManager.DispatchStop();
【讨论】:
【参考方案9】:这解决了我在 Fragments 中添加 MapView 的问题。 https://github.com/petedoyle/android-support-v4-googlemaps
【讨论】:
【参考方案10】:新版ABS 4.0,不支持MapFragmentActivity,这里有一个在Fragment中有mapview的好解决方案!
https://xrigau.wordpress.com/2012/03/22/howto-actionbarsherlock-mapfragment-listfragment/#comment-21
【讨论】:
【参考方案11】:我可以得到解决方案吗:
-
创建类 TempFragmentActivity 扩展 MapActivity
在 TempFragmentActivity 中有一个 MapView 对象(就像在 xml 中正常定义一样)
从父级中移除这个 MapView 对象(LinearLayout)(后面的无效异常)
将此 MapView 对象保存在某处(例如:TempFragmentActivity 的静态成员)
在您的 Fragment 中,使用代码(不要在 xml 中定义)将此 MapView 对象添加到一些 LinearLayout 中
【讨论】:
【参考方案12】:我编写了一个小库,将基于 LocalActivityManager 的 MapFragment 问题解决方案混搭在一起(还包括一个显示各种使用情况的示例应用):
https://github.com/coreform/android-tandemactivities
【讨论】:
以上是关于片段中的 MapView(蜂窝)的主要内容,如果未能解决你的问题,请参考以下文章
Mapview 给出 nullpointerexception 片段
以编程方式创建 MapView 并添加标记导致片段中出现空指针异常
使用 ViewPager2 时 MapView/SupportMapFragment 图形故障