片段中的MapView(蜂窝)


81

现在,最终的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:只能在MapActivity实例内部创建MapView。
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我需要的后台线程...那么,目前这样做的最佳实践是什么?

感谢德国瓦伦丁先生


2
我报告了对此功能的要求。请加注星标。code.google.com/p/android/issues/detail?id=15347
杰里米·爱德华兹

Answers:


8

从2012年12月3日起,谷歌发布了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"/>

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


在此处输入图片说明


4
然后,如果您希望MapActivity能够与父Activity通信(使用Fragment很容易),则可以使用Activity.getParent()
Dori

3
您实际上并不需要使用TabHost,也可以只使用LocalActivityManager并将返回的窗口附加到片段的内容上
ChristophK,

4
如果有人想知道,这里的代码是: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);
ChristophK

8
请注意,LocalActivityManager现在已弃用
louiscoquio,2012年

4
使用制表符和片段,对我来说效果很好。对于那些询问解释的人,我宁愿看到该项目及其代码,这很容易理解。是的,LocalActivityManager已弃用,但这只是一个hack,当他们决定在Fragments中包括对Maps的适当支持时,应正确解决此问题。
mdelolmo

23

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

但是,也有一个缺点:

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


6
这也意味着您的应用程序将不是最新的支持库。虽然android-support-v4-googlemaps已更新了许多次,但目前落后2个版本。我同意其他人的观点,即与使用不推荐使用的LocalActivityManager相比,此修改后的库是一个更大的技巧。
Stan Kurdziel 2012年

1
github.com/petedoyle/android-support-v4-googlemaps是最新的(此消息为r10)。我还对事物进行了重构,因此将来保持最新非常容易。
皮特·道尔

我有一个问题。如果已经部署和安装了应用程序,那么“不了解最新的支持库”的缺点是什么?
hendrix 2012年

IMO这种方法的主要问题是,您将无法通过可选的Maps支持来部署应用程序。由于所有FragmentActivity都扩展了MapActivity,因此它将在没有Google API的设备(例如Kindle Fire)上崩溃。
Paul Lammertsma,2012年

13

只是为了澄清答案。我尝试了inazaruk和ChristophK建议的方法。实际上,您可以在一个片段中运行任何活动-不仅是Google Maps。这是由于inazaruk和ChristophK而将Google地图活动作为一个片段实现的代码。

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());
    }
}

2
但是唯一避免的解决方案LocalActivityManager(如此处讨论:code.google.com/p/android/issues/detail?id=15347)包括扩展all FragmentActivities,这似乎并不是最佳选择。
Estel 2012年

不推荐使用LocalActivityManager,因为不推荐使用ActivityGroup,它在这种情况下仍然有用,并且如果人们使用它来解决其缺点,谷歌可能会考虑在将来的版本中淘汰它。
straya 2012年

4

来自Google的好消息。他们今天发布了一个新的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" />

不完全是。尝试在FragmentPagerAdapter中使用它。
Thomas Dignan

如果你正在谈论的黑色看法,有一个小黑客来修复它stackoverflow.com/questions/13837697/...
马塞洛

谢谢。我最终在稍后看到它,但现在使用的是带有Polaris的第一个地图API版本。
Thomas Dignan

2

Google Maps API不属于AOSP。只要没有Googler做出回应,就几乎无法判断将来是否会有MapFragment。

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


1
希望Map API会很快用片段和矢量绘图进行更新!
内森·史威文

2

太可惜了,Google尚未回应。FWIW,如果您确实需要执行此操作,除了以下方法外,我没有发现其他方法:

让Tab管理活动从MapActivity继承,以编程方式在其中创建MapView,让mapfragment.xml包含ViewGroup,然后使用以下方法将MapView添加到ViewGroup

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

显然,这与碎片是独立的但...


谢谢,让Fragment management Activity扩展MapActivity对我来说非常理想。
皮特道尔

2

这是一个非常简化的MapFragmentMonoDroid适用于Android的Mono)版本:

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();
    }
}



1

我可以得到解决方案:

  1. 创建类TempFragmentActivity扩展MapActivity
  2. TempFragmentActivity内部有一个MapView对象(就像xml中的正常定义一样)
  3. 从父对象(LinearLayout)移除此MapView对象形式(避免以后出现异常)
  4. 将此MapView对象保留在某处(例如:TempFragmentActivity的静态成员)
  5. 在您的Fragment中,使用代码(不在xml中定义)将此MapView对象添加到一些LinearLayout中

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.