81

現在最終的SDK與谷歌apis - 什麼是用MapView創建片段的最佳方式? MapView需要MapActivity才能正常工作。MapView中的片段(蜂窩)

讓管理碎片的活動繼承自MapActivity(糟糕的解決方案,因爲它違背碎片自包含的想法)並且使用常規的基於xml的佈局不起作用。我得到了MapActivity.setupMapView()一個NullPointerException:

 
E/AndroidRuntime( 597): Caused by: java.lang.NullPointerException 
E/AndroidRuntime( 597): at com.google.android.maps.MapActivity.setupMapView(MapActivity.java:400) 
E/AndroidRuntime( 597): at com.google.android.maps.MapView.(MapView.java:289) 
E/AndroidRuntime( 597): at com.google.android.maps.MapView.(MapView.java:264) 
E/AndroidRuntime( 597): at com.google.android.maps.MapView.(MapView.java:247) 

我的第二個想法是,以編程方式創建的MapView和語境的MapView的構造函數傳遞相關的活動(()通過getActivity)。不工作:

 
E/AndroidRuntime( 834): Caused by: java.lang.IllegalArgumentException: MapViews can only be created inside instances of MapActivity. 
E/AndroidRuntime( 834): at com.google.android.maps.MapView.(MapView.java:291) 
E/AndroidRuntime( 834): at com.google.android.maps.MapView.(MapView.java:235) 
E/AndroidRuntime( 834): at de.foo.FinderMapFragment.onCreateView(FinderMapFragment.java:225) 
E/AndroidRuntime( 834): at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:708) 
E/AndroidRuntime( 834): at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:900) 
E/AndroidRuntime( 834): at android.app.FragmentManagerImpl.addFragment(FragmentManager.java:978) 
E/AndroidRuntime( 834): at android.app.Activity.onCreateView(Activity.java:4090) 
E/AndroidRuntime( 834): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:664) 

真的應該有類似MapFragment,是以後臺線程護理需要MapView類我猜...那麼,什麼是做到這一點當前的最佳做法是什麼?

感謝和來自德國的問候, 瓦倫丁

+2

我爲此報告了功能請求。 請明星。 http://code.google.com/p/android/issues/detail?id=15347 – 2011-03-13 04:39:29

回答

8

由於2012年3月12日谷歌發佈谷歌地圖API的Android V2。現在你可以忘記這些問題。使用新的API https://developers.google.com/maps/documentation/android/

實施例 - 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"/> 
2

的谷歌地圖API是不是AOSP的一部分。只要沒有Google員工迴應,幾乎無法確定將來是否會出現MapFragment。

可能有限的替代方法是使用WebViewFragment並濫用它來加載自定義的maps.google.com URL。

+1

希望Map API能夠很快更新,並帶有碎片和矢量圖! – schwiz 2011-03-27 05:28:57

2

Hm太糟糕了,Google尚未回覆。 FWIW如果你真的需要做到這一點,我發現沒有其他辦法比:

有標籤管理活動從MapActivity繼承,創造有程序的MapView,有mapfragment.xml包含一個ViewGroup中和的MapView添加到一個ViewGroup使用

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

顯然這正好強烈反對的想法,片段彪是自包含的,但...

+0

謝謝,使片段管理Activity擴展MapActivity對我來說非常合適。 – 2011-03-07 20:27:37

23

截至Google Groups討論,彼得·道爾建立了一個自定義兼容性庫支持谷歌地圖了。 android-support-v4-googlemaps

然而,有一個缺點太:

目前,一個缺點是,延長FragmentActivity所有類MapActivitys。它可能會創建一個單獨的類(即FragmentMapActivity),但它需要重構FragmentActivity代碼。

+6

這也意味着您的應用程序不會與最新的支持庫保持同步。雖然android-support-v4-googlemaps已經更新了很多次,但它目前有2個版本。我同意其他人的看法,認爲這個修改後的庫比使用不推薦的LocalActivityManager更大膽。 – 2012-08-02 02:08:23

+1

https://github.com/petedoyle/android-support-v4-googlemaps現在是最新版本(此消息爲r10)。我也重構了一些東西,所以未來會更容易保持最新。 – 2012-09-25 19:43:01

+0

我有一個問題。如果應用程序已經部署和安裝,那麼「沒有及時更新最新的支持庫」有什麼缺點? – hendrix 2012-10-23 16:01:43

87

我已經設法通過在片段中使用TabHost來解決此問題。

這裏的想法(簡述):

  1. MainFragmentActivity延伸FragmentActivity(從支持庫),並有MapFragment

  2. MyMapActivity延伸MapActivity幷包含MapView

  3. LocalActivityManagerFragment主機LocalActivityManager

  4. MapFragment延伸LocalActivityManagerFragment

  5. and LocalActivityManager contains MyMapActivity activity in it。

實施例:https://github.com/inazaruk/map-fragment


enter image description here

+4

如果您希望MapActivity能夠與父活動(使用片段很容易)通信,那麼您可以使用Activity.getParent() – Dori 2011-12-14 14:18:13

+3

您並不需要使用TabHost,您也可以使用LocalActivityManager並將返回的窗口附加到片段的內容 – ChristophK 2012-02-10 10:20:27

+0

@christophk,請您詳細說明「將返回的窗口附加到片段的內容」是什麼意思?我真的不明白,但看起來很有趣。 – Arnaud 2012-02-29 11:11:10

1

我可以得到解決:

  1. 創建類TempFragmentActivity擴展MapActivity
  2. 裏面有TempFragmentActivity一個MapView的對象(如正常定義XML)
  3. 刪除此MapView類對象形式父(LinearLayout)(void後來的異常)
  4. 將此MapView對象保存在某處(例如:TempFragme的靜態成員ntActivity)
  5. 在你的片段,添加使用的代碼(不XML定義)本MapView類對象爲一些LinearLayout中
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()); 
    } 
} 
+2

但是避免'LocalActivityManager'的唯一解決方案(如這裏所討論的:http://code.google.com/p/android/issues/detail?id=15347)涉及擴展* all *'FragmentActivities',這似乎更少最佳。 – Estel 2012-07-19 09:19:00

+0

LocalActivityManager不贊成使用,因爲ActivityGroup已被棄用,對於這種情況仍然有用,如果人們正在使用它來解決它們的缺點,Google可能會在將來的版本中推翻它。 – straya 2012-08-29 00:07:07

+0

你可以發表SherlockFragment的代碼嗎? – Derzu 2012-10-28 15:15:37

2

這裏有一個MonoDroid的Mono for Android)版本的一個非常簡化的MapFragment

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

谷歌在這方面的好消息。他們今天發佈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_width="match_parent" 
    android:layout_height="match_parent" 
    class="com.google.android.gms.maps.MapFragment" /> 
+0

不完全。嘗試在FragmentPagerAdapter中使用它。 – 2013-01-22 11:12:52

+0

如果你正在談論的黑色看法,有一個小黑客來修復它http://stackoverflow.com/questions/13837697/viewpager-with-google-maps-api-v2-mysterious-black-view – Marcelo 2013-01-22 11:48:50

+0

感謝。後來我看到了,但現在我正在使用polaris的第一個地圖API版本。 – 2013-02-04 18:44:16