フラグメント内のMapView(Honeycomb)


81

最終的なSDKがgoogleapisでリリースされたので、MapViewを使用してフラグメントを作成するための最良の方法は何ですか?MapViewが正しく機能するには、MapActivityが必要です。

フラグメントを管理するアクティビティをMapActivityから継承し(フラグメントは自己完結型であるという考えに反するため、悪い解決策)、通常の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)

2番目のアイデアは、プログラムでMapViewを作成し、関連するアクティビティを(getActivity()を介して)Contextとして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)で

本当に、MapViewが必要とするバックグラウンドスレッドを処理するMapFragmentのようなものがあるはずです...では、これを行うための現在のベストプラクティスは何ですか?

ドイツ、バレンティンからの感謝とよろしく


2
このための機能リクエストを報告しました。スターを付けてください。code.google.com/p/android/issues/detail?id=15347
Jeremy Edwards

回答:


8

2012年3月12日の時点で、GoogleはGoogle Maps Android APIv2をリリースしました。今、あなたはこれらの問題を忘れることができます。 https://developers.google.com/maps/documentation/android/

新しいAPIの使用例-https://developers.google.com/maps/documentation/android/start#add_a_map

このAPIは少なくともAndroidAPI 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. MainFragmentActivityFragmentActivity(サポートライブラリから)拡張し、を持っていMapFragmentます。

  2. MyMapActivity拡張MapActivityして含むMapView

  3. LocalActivityManagerFragment ホスト LocalActivityManager

  4. MapFragment拡張しLocalActivityManagerFragmentます。

  5. そして、その中LocalActivityManagerMyMapActivity活動が含まれています。

実装例:https//github.com/inazaruk/map-fragment


ここに画像の説明を入力してください


4
次に、MapActivityが親アクティビティ(フラグメントを使用すると簡単)と通信できるようにする場合は、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非推奨ですが、これは単なるハックです。フラグメント内にマップの適切なサポートを含めることを決定した場合、この問題は適切に解決されるはずです。
mdelolmo 2012

23

Googleグループで説明したように、PeterDoyleはGoogleマップもサポートするカスタム互換性ライブラリを構築しました。android-support-v4-googlemaps

ただし、欠点もあります。

現在、1つの欠点は、FragmentActivityを拡張するすべてのクラスがMapActivityであるということです。別のクラス(つまりFragmentMapActivity)を作成することは可能ですが、FragmentActivityコードのリファクタリングが必要です。


6
これは、アプリが最新のサポートライブラリで最新にならないことも意味します。android-support-v4-googlemapsは何度も更新されていますが、現在2バージョン遅れています。この変更されたライブラリは、非推奨のLocalActivityManagerを使用するよりも大きなハックであることに同意します。
Stan Kurdziel 2012

1
github.com/petedoyle/android-support-v4-googlemapsは現在最新です(このメッセージの時点でr10)。また、リファクタリングを行ったので、将来的に最新の状態に保つのは非常に簡単です。
ピート・ドイル

一つ質問があります。アプリケーションがすでにデプロイおよびインストールされている場合、「最新のサポートライブラリが最新でない」ことのデメリットは何ですか?
hendrix 2012年

このアプローチの主な問題であるIMOは、オプションのマップサポートを使用してアプリをデプロイできないことです。すべてのFragmentActivitiesはMapActivityを拡張するため、Google APIのないデバイス(Kindle Fireなど)でクラッシュするだけです。
Paul Lammertsma 2012年

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(ここで説明されているように:code.google.com/p/android/issues/detail?id = 15347)は、すべて を拡張することを含みFragmentActivities、これはさらに最適ではないようです。
Estel 2012

LocalActivityManagerは非推奨であるため、より非推奨になりました。これはこの状況でも引き続き役立ちます。Googleは、ユーザーが欠点を解決するために使用している場合、将来のリリースでそれを廃止することを2度考えます。
straya 2012

4

これに関するグーグルからの素晴らしいニュース。彼らは本日、屋内地図とMapFragmentを備えた新しいGoogle MapsAPIをリリースします。

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 2013年

あなたが黒い眺めについて話しているなら、それを修正するための小さなハックがありますstackoverflow.com/questions/13837697/…–
マルセロ

ありがとう。後でそれを見ることになりましたが、現在、ポラリスを備えた最初のマップAPIバージョンを使用しています。
Thomas Dignan 2013

2

Google MapsAPIはAOSPの一部ではありません。Google社員が応答しない限り、将来MapFragmentがあるかどうかを判断することはほとんど不可能です。

考えられる限定的な代替手段は、を使用し、WebViewFragmentそれを悪用してカスタムmaps.google.comURLをロードすることです。


1
Map APIがフラグメントとベクター描画でまもなく更新されることを期待しています!
Nathan Schwermann 2011年

2

グーグルがまだ応答していないのは残念です。FWIW本当にこれを行う必要がある場合、私は他の方法を見つけませんでした:

タブ管理アクティビティをMapActivityから継承し、プログラムでそこにMapViewを作成し、mapfragment.xmlにViewGroupを含め、を使用してMapViewをViewGroupに追加します。

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

明らかに、これはフラグメントが自己完結型であるという考えに強く反しますが...


おかげで、フラグメント管理アクティビティをMapActivityに拡張させることは、私にとって完璧に機能しました。
ピート・ドイル

2

ここだMonoDroidモノラル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();
    }
}



1

解決策を教えてもらえますか:

  1. クラスTempFragmentActivityを作成してMapActivityを拡張します
  2. TempFragmentActivity内にMapViewオブジェクトがあります(xmlでの通常の定義のように)
  3. このMapViewオブジェクトをparent(LinearLayout)から削除します(後で例外を無効にします)
  4. このMapViewオブジェクトをどこかに保持します(例:TempFragmentActivityの静的メンバー)
  5. Fragmentで、コード(xmlで定義しない)を使用してこのMapViewオブジェクトをLinearLayoutに追加します

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.