81

现在最终的 SDK 已经与 google apis 一起发布了 - 使用 MapView 创建片段的最佳方法是什么?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 需要的后台线程我猜......那么目前的最佳实践是什么?

来自德国的感谢和问候,Valentin

4

12 回答 12

87

我已经设法通过在片段中使用 TabHost 来解决这个问题。

这是想法(简要):

  1. MainFragmentActivity扩展FragmentActivity(来自支持库)并具有MapFragment.

  2. MyMapActivity扩展MapActivity并包含MapView.

  3. LocalActivityManagerFragment主机LocalActivityManager

  4. MapFragment延伸LocalActivityManagerFragment

  5. 并在LocalActivityManager其中包含MyMapActivity活动。

示例实现: https ://github.com/inazaruk/map-fragment 。


在此处输入图像描述

于 2011-11-14T18:28:16.213 回答
23

正如在Google Groups中所讨论的,Peter Doyle 也构建了一个支持 Google Maps 的自定义兼容性库。android-support-v4-googlemaps

但是,也有一个缺点:

目前,一个缺点是所有扩展 FragmentActivity 的类都是 MapActivity。它可以创建一个单独的类(即FragmentMapActivity),但它需要对FragmentActivity 代码进行一些重构。

于 2011-07-28T11:36:26.620 回答
13

只是为了澄清答案。我尝试了 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());
    }
}
于 2012-05-24T14:11:56.017 回答
8

自 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_width="match_parent"
    android:layout_height="match_parent"
    class="com.google.android.gms.maps.MapFragment"/>
于 2012-12-10T08:46:57.467 回答
4

谷歌在这方面的好消息。他们今天发布了一个新的 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_width="match_parent"
  android:layout_height="match_parent"
  class="com.google.android.gms.maps.MapFragment" />
于 2012-12-03T19:48:14.280 回答
2

Google Maps API 不属于 AOSP。只要没有 Google 员工回应,就几乎不可能判断未来是否会有 MapFragment。

一种可能的有限替代方法是使用WebViewFragment并滥用它来加载自定义maps.google.comURL。

于 2011-02-24T19:26:20.070 回答
2

嗯,太糟糕了,谷歌还没有回应。FWIW如果你真的需要这样做,我发现没有别的办法:

让选项卡管理活动从 MapActivity 继承,以编程方式在其中创建 MapView,让 mapfragment.xml 包含一个 ViewGroup 并使用将 MapView 添加到 ViewGroup

((ViewGroup) getFragmentManager().findFragmentById(R.id.finder_map_fragment).getView()).addView(mapView);;

显然,这强烈反对片段是自包含的想法,但是......

于 2011-02-25T17:25:50.780 回答
2

这是一个非常简化的MapFragment的MonoDroid ( Mono for Android ) 版本:

public class MapFragment : Fragment
{
    // FOLLOW http://stackoverflow.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();
    }
}
于 2012-10-02T01:45:33.843 回答
1

这解决了我在 Fragments 中添加 MapView 的问题。 https://github.com/petedoyle/android-support-v4-googlemaps

于 2012-03-11T09:42:07.613 回答
1

新版本的 ABS 4.0 不支持 MapFragmentActivity,这是一个在 Fragment 中拥有 mapview 的好解决方案!

https://xrigau.wordpress.com/2012/03/22/howto-actionbarsherlock-mapfragment-listfragment/#comment-21

于 2012-04-04T07:08:31.617 回答
1

我可以得到解决方案:

  1. 创建类 TempFragmentActivity 扩展 MapActivity
  2. TempFragmentActivity 中有一个 MapView 对象(就像 xml 中的正常定义一样)
  3. 从父级(LinearLayout)移除这个 MapView 对象(后面的异常无效)
  4. 将此 MapView 对象保存在某处(例如:TempFragmentActivity 的静态成员)
  5. 在您的 Fragment 中,使用代码(不要在 xml 中定义)将此 MapView 对象添加到一些 LinearLayout
于 2012-05-10T14:09:04.643 回答
0

我编写了一个小库,将基于 LocalActivityManager 的 MapFragment 问题解决方案混搭在一起(还包括一个显示各种使用情况的示例应用程序):

https://github.com/coreform/android-tandemactivities

于 2012-08-29T00:08:20.737 回答