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

81

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

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

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

Спасибо и привет из Германии, Валентин

Валентин
источник
2
Я сообщил о запросе функции для этого. Пожалуйста, отметьте это. code.google.com/p/android/issues/detail?id=15347
Джереми Эдвардс,

Ответы:

8

По состоянию на 03.12.2012 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"/>
Павел Аннеков
источник
87

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

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

  1. MainFragmentActivityextends FragmentActivity(из библиотеки поддержки) и имеет MapFragment.

  2. MyMapActivityрасширяется MapActivityи содержит MapView.

  3. LocalActivityManagerFragment хозяева LocalActivityManager

  4. MapFragmentрасширяется LocalActivityManagerFragment.

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

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


введите описание изображения здесь

Иназарук
источник
4
Если вы затем хотите, чтобы MapActivity мог связываться с родительским Activity (что легко с фрагментом), вы можете использовать Activity.getParent ()
Дори
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
4
У меня это хорошо работает, используя вкладки и фрагменты. Для тех, кто интересуется объяснением, я бы предпочел увидеть проект и его код, это легко понять. И да, LocalActivityManagerэто устарело, но это просто взлом, эта проблема должна быть решена должным образом, когда они решат включить соответствующую поддержку карт во фрагменты.
mdelolmo 07
23

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

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

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

TomTasche
источник
6
Это также означает, что ваше приложение не будет обновлено до последней версии библиотеки поддержки. Хотя android-support-v4-googlemaps обновлялся несколько раз, в настоящее время он отстает на 2 версии. Я согласен с другими в том, что эта модифицированная библиотека - более серьезная уловка, чем использование устаревшего LocalActivityManager.
Stan Kurdziel 02
1
github.com/petedoyle/android-support-v4-googlemaps сейчас обновлен (r10 на момент этого сообщения). Я также реорганизовал некоторые вещи, чтобы в будущем было очень легко оставаться в курсе.
Пит Дойл,
У меня есть один вопрос. Если приложение уже развернуто и установлено, в чем недостаток «отсутствия последней версии библиотеки поддержки»?
hendrix
Основная проблема этого подхода, IMO, заключается в том, что вы не сможете развернуть свое приложение с дополнительной поддержкой Карт. Поскольку все FragmentActivities расширяют MapActivity, он просто выйдет из строя на устройствах без API Google (например, Kindle Fire).
Пол Ламмертсма
13

Просто чтобы уточнить ответ. Я попробовал подход, предложенный inazaruk и ChristophK. На самом деле вы можете запускать во фрагменте любую активность, а не только карты Google. Вот код, который реализует активность карты Google как фрагмент благодаря 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
LocalActivityManager более устарел, потому что ActivityGroup устарел, он все еще полезен в этой ситуации, и, возможно, Google дважды подумает, чтобы вытеснить его в будущих выпусках, если люди будут использовать его для устранения своих недостатков.
straya
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/…
Марсело
Благодарю. Я увидел это позже, но сейчас я использую первую версию api карты с polaris.
Thomas Dignan
2

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

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

Октавиан А. Дамиан
источник
1
Надеемся, что API карт скоро будет обновлен фрагментами и векторной графикой!
Натан Шверманн,
2

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

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

((ViewGroup) getFragmentManager (). FindFragmentById (R.id.finder_map_fragment) .getView ()). AddView (mapView) ;;

Ясно, что это резко противоречит идее, что фрагменты должны быть самодостаточными, но ...

Валентин
источник
Спасибо, расширение Activity по управлению фрагментами MapActivity отлично сработало для меня.
Пит Дойл,
2

Вот версия очень упрощенного MapFragment для MonoDroid ( Mono для 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();
    }
}
Ян Винк
источник
1

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

  1. создать класс TempFragmentActivity расширяет MapActivity
  2. внутри TempFragmentActivity есть объект MapView (как обычное определение в xml)
  3. удалить этот родительский объект формы MapView (LinearLayout) (недействительное исключение позже)
  4. храните этот объект MapView где-нибудь (например, статический член TempFragmentActivity)
  5. в вашем фрагменте добавьте этот объект MapView с помощью кода (не определяемого в xml) в некоторый LinearLayout
Джо Чжан
источник
0

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

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

Straya
источник