MapView в фрагменте (соты)

теперь, когда окончательный SDK вышел с google apis - какой лучший способ создать фрагмент с помощью MapView? MapView нуждается в MapActivity для правильной работы.

Имея действие, управляющее фрагментами, наследуется от MapActivity (плохое решение, потому что оно противоречит идее, что фрагменты самодостаточны), и использование обычного макета на основе xml не работает. Я получаю исключение NullPointerException в MapActivity.setupMapView():

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 и передать связанную активность (через getActivity()) в качестве Контекста к конструктору MapView. Не работает:

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, я думаю... Итак, какова нынешняя лучшая практика для этого?

Спасибо и привет от Германии, Valentin

Ответ 1

Начиная с 03.12.2012 Google выпустил API Google Maps Android 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"/>

Ответ 2

Мне удалось решить это, используя TabHost в фрагменте.

Вот идея (кратко):

  • MainFragmentActivity extends FragmentActivity (из библиотеки поддержки) и имеет MapFragment.

  • MyMapActivity extends MapActivity и содержать MapView.

  • LocalActivityManagerFragment hosts LocalActivityManager

  • MapFragment extends LocalActivityManagerFragment.

  • И LocalActivityManager содержит в нем MyMapActivity активность.

Пример реализации: https://github.com/inazaruk/map-fragment.


enter image description here

Ответ 3

Как обсуждалось в Группах Google, Питер Дойл создал специальную библиотеку совместимости, поддерживающую Карты Google. android-support-v4-googlemaps

Однако есть и недостаток:

В настоящее время одним недостатком является то, что ВСЕ классы, расширяющие FragmentActivity, являются MapActivitys. Его можно сделать отдельным классом (т.е. FragmentMapActivity), но он требует некоторого рефакторинга кода FragmentActivity.

Ответ 4

Просто, чтобы прояснить ответ. Я пробовал подход, предложенный иназаруком и Кристофом. На самом деле вы можете запускать любую деятельность в фрагменте, а не только на картах Google. Вот код, который реализует активность карты google как фрагмент благодаря иназаруку и 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());
    }
}

Ответ 5

Отличные новости от Google по этому поводу. Сегодня они выпускают новый API Карт Google, с картами внутри помещений и 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" />

Ответ 6

API Карт Google не является частью AOSP. Пока Гуглер не отвечает, едва ли можно сказать, будет ли MapFragment в будущем.

Возможной ограниченной альтернативой является использование WebViewFragment и злоупотребление ею для загрузки пользовательского URL maps.google.com.

Ответ 7

Слишком плохо, что Google еще не ответил. FWIW, если вам действительно нужно это сделать, я не нашел другого способа, чем:

Наследуйте действия по управлению вкладками из MapActivity, создайте MapView там программно, используйте mapfragment.xml, содержащий ViewGroup, и добавьте MapView в ViewGroup, используя

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

Ясно, что это сильно противоречит идее о том, что фрагменты являются самодостаточными, но...

Ответ 8

Здесь версия 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();
    }
}

Ответ 11

Могу ли я получить решение:

  • создать класс TempFragmentActivity расширяет MapActivity
  • есть объект MapView внутри TempFragmentActivity (например, normal define в xml)
  • удалить эту родительскую форму MapView parent (LinearLayout) (исключение void позже)
  • сохранить этот объект MapView где-нибудь (ex: статический член TempFragmentActivity)
  • в вашем фрагменте добавьте этот объект MapView с помощью кода (не определяйте в xml) в некоторый LinearLayout

Ответ 12

Я написал небольшую библиотеку, замалчивая решения LocalActivityManager на проблему MapFragment (также включает пример приложения, показывающий различные ситуации использования):

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