MapView у фрагменті (стільник)


81

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

Наявність Активності, яка керує Фрагментами, успадковується від 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. 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.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

23

Як обговорювали в Google Groups , Пітер Дойл створив власну бібліотеку сумісності, яка також підтримує Карти Google.android-support-v4-googlemaps

Однак є і мінус:

В даний час одним мінусом є те, що ВСІ класи, що розширюють FragmentActivity, є MapActivitys. Можна створити окремий клас (тобто FragmentMapActivity), але він вимагає певного рефакторингу коду FragmentActivity.


6
Це також означає, що ваш додаток не буде в курсі останньої бібліотеки підтримки. Незважаючи на те, що android-support-v4-googlemaps неодноразово оновлювався, на даний момент відстає 2 версії. Я погоджуюсь з іншими, що ця модифікована бібліотека є більшим злом, ніж використання застарілого LocalActivityManager.
Stan Kurdziel

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 , що здається ще менш оптимальним.
Естель,

LocalActivityManager є більш застарілим, оскільки ActivityGroup застарілий, все ще корисний для цієї ситуації, і, можливо, Google двічі подумає про його витіснення в майбутніх випусках, якщо люди використовують його, щоб вирішити свої недоліки.
straya

4

Чудові новини від Google щодо цього. Сьогодні вони випускають новий API Google Maps з картами приміщень та 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 map з polaris.
Thomas Dignan

2

API Google Maps не є частиною AOSP. Поки жоден працівник Google не реагує, навряд чи можна сказати, чи буде MapFragment в майбутньому.

Можлива обмежена альтернатива - використання WebViewFragmentта зловживання ним для завантаження користувацької maps.google.comURL-адреси.


1
Ось сподіваємось, що Map Map скоро буде оновлений фрагментами та векторним малюнком!
Nathan Schwermann

2

Шкода, що Google ще не відповів. FWIW, якщо вам дійсно потрібно це зробити, я не знайшов іншого шляху, крім:

Попросіть Tab Managing Activity успадкувати MapActivity, створити там MapView програмно, mapfragment.xml містити ViewGroup і додати MapView до ViewGroup за допомогою

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

Очевидно, це суперечить ідеї, що фрагменти мають бути замкненими, але ...


Дякую, змушуючи функцію управління фрагментами розширити MapActivity для мене спрацювало ідеально.
Піт Дойл

2

Ось версія MonoDroid ( Mono для 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. create class TempFragmentActivity розширює MapActivity
  2. є об’єкт MapView усередині TempFragmentActivity (як звичайне визначення в xml)
  3. видалити цей батьківський об'єкт MapView (LinearLayout) (void пізніше виняток)
  4. зберігати цей об’єкт MapView десь (наприклад: статичний член TempFragmentActivity)
  5. у своєму Фрагменті додайте цей об’єкт MapView за допомогою коду (не визначати в xml) у якийсь LinearLayout

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.