Подтвердить что ты не робот

Первый запуск Activity с Google Maps очень медленный

Я хочу иметь SupportMapFragment в одном из моих действий. Я добавляю этот фрагмент непосредственно в макет xml, и этот макет устанавливается как просмотр содержимого. Но когда активность запускается впервые, она занимает слишком много времени (более 1 секунды). Следующие запуски в порядке и занимают несколько миллисекунд.

Я пробовал:

  • удалить любую инициализацию
  • используйте MapFragment вместо SupportMapFragment
  • добавить MapFragment программно

но ничего не помогло. Карта отображается без каких-либо проблем или подозрительного журнала.

Есть ли у вас какие-либо предложения, какие причины и как их улучшить?

изменить У меня есть ListView, и когда пользователь нажимает на Item, он запускает DetailActivity с MapFragment. После нажатия на элемент появляется заметная задержка до появления DetailActivity. Только метод onCreate, где я вызываю setContentView, работает более 1 секунды. И хотя активность в методе onCreate, из этого действия нет видимого содержимого. Эта задержка между кликом и показом контента не очень удобна для пользователя.

Спасибо

4b9b3361

Ответ 1

Причина, по которой первая загрузка занимает много времени, заключается в том, что API-интерфейсы Play Services должны загружаться, как показано в строках журнала:

I/Google Maps Android API﹕ Google Play services client version: 6587000
I/Google Maps Android API﹕ Google Play services package version: 6768430

К сожалению, для "пакета" требуется примерно одна секунда для загрузки, и использование MapsInitializer приведет вас к "клиенту". Итак, вот не очень красивая работа: Инициализируйте фиктивную карту в своей основной активности запуска.

mDummyMapInitializer.getMapAsync(new OnMapReadyCallback() {
  @Override
  public void onMapReady(GoogleMap googleMap) {
    Log.d(TAG, "onMapReady");
  }
});

Теперь, когда вы загружаете свою фактическую карту позже, ей не нужно инициализировать API-интерфейсы Play. Это не должно вызывать каких-либо задержек в вашем основном действии либо потому, что асинхронный метод выполняется из основного потока.

Поскольку вам нужно инициализировать где-нибудь, что бы ни случилось, я думаю, что имеет смысл делать это правильно, когда приложение запускается, так что, когда вы загружаете действие, которое действительно нуждается в карте, вам не нужно ждать вообще.

Примечание: mDummyMapInitializer должен быть MapFragment или SupportMapFragment и должен быть добавлен в действие, иначе API-интерфейсы Play Play не будут загружены. Сам метод getMapAsync также должен быть вызван из основного потока.

Ответ 2

Хорошо, поэтому у меня была одна и та же проблема, и после просмотра этого вопроса подумайте, что нет "хорошего" решения.

Мой текущий взломать - это отложить добавление фрагмента, давая активности возможность сделать все остальное перед добавлением карты.

Теперь я вставляю карту в качестве дочернего фрагмента, поэтому мой код выглядит следующим образом:

    // inside onCreateView
    new Handler().postDelayed(new Runnable() {

        @Override
        public void run() {
            if (isAdded()) {
                FragmentManager fm = getChildFragmentManager();
                GoogleMapFragment mapFragment = GoogleMapFragment
                        .newInstance();
                fm.beginTransaction()
                        .replace(R.id.mapContainer, mapFragment).commit();
            }
        }
    }, 1000);

если добавить непосредственно к Activity, это может выглядеть так:

    // inside onCreate
    new Handler().postDelayed(new Runnable() {

        @Override
        public void run() {
            if (!isFinishing()) {
                FragmentManager fm = getFragmentManager();
                GoogleMapFragment mapFragment = GoogleMapFragment
                        .newInstance();
                fm.beginTransaction()
                        .replace(R.id.mapContainer, mapFragment).commit();
            }
        }
    }, 1000);

Тем не менее, проверка внутри Runnable необходима, чтобы гарантировать, что мы не пытаемся добавить карту к некоторому несуществующему Activity или Fragment.

Я не являюсь поклонником жестко запрограммированных задержек, подобных этому, поэтому вернусь, если придумаю что-то лучшее. 1 секунда должна быть много, хотя и, вероятно, может быть еще меньше.

Ответ 3

Я тоже борюсь с этой проблемой и нашел значительные улучшения, выполнив следующие действия:

1) Отключите USB-кабель (или отключите сеанс отладки) и повторите попытку. Карты Google в приложении намного медленнее, когда активен сеанс отладки. Отключите отладчик, и он будет намного быстрее... он все же, конечно, не самый быстрый, но, по крайней мере, приемлемый.

2) Не вызывайте setMapType(), если вы уже не вызвали getMapType() и не подтвердили, что он отличается от того, что вы хотите установить. Несколько вызовов для одного и того же типа карты по-прежнему будут иметь значение reset каждый раз, что может занять некоторое время.

3) Добавьте фрагмент карты программно, аналогично тому, что было опубликовано в @cYrixmorten, но я делаю это из фонового потока, запущенного в конце моего onResume(), который затем ждет 50 мс, а затем запускает его в потоке пользовательского интерфейса. Это позволяет сразу же ударить нить пользовательского интерфейса, так что время активности загружается и отображается; вы должны, по крайней мере, быть на экране, пока карта, возможно, все задыхается.

Ловушка здесь заключается в том, что вы хотите создать новый экземпляр MapFragment только один раз для каждой операции, а не каждый раз, когда ориентация экрана вращается. То, что я делаю, называется "getFragmentManager(). FindFragmentById (R.id.mapContainer)", который либо даст мне обработчик фрагмента карты из последнего времени, либо null, если это первый раз (в этом случае я создам фрагмент карты и сделать FragmentManager.replace()).

Ответ 4

Я решил это, используя MapsInitializer в своем приложении Application.onCreate():

MapsInitializer.initialize(this);

Хорошие результаты и более чистое (и не хаки) решение!

Ответ 5

У меня есть "основная" активность - и активность с mapView. Когда это действие-с-mapView запускается в первый раз, оно действительно медленное.

clocksmith post дал мне идею начать инициализацию из основной активности в отдельном потоке. И это действительно решает проблему.

Вот мой код из "основного" действия:

public void onCreate(Bundle savedInstanceState) {
    ...

    Runnable initMap = () -> {
        BaseApplication.d("Start init mapView");
        MapView mapView = new MapView(MainActivity.this);
        mapView.onCreate(null);
        BaseApplication.d("... done");
    };
    new Thread(initMap).start();
}

mapView никогда не используется - это только для целей инициализации.

И вот трассировка стека - только для информации:

12-09 19:31:54.442 17172-17341/my.app D/XXX: Start init mapView
12-09 19:31:54.525 17172-17341/my.app I/zzy: Making Creator dynamically
12-09 19:31:55.007 17172-17341/my.app D/ChimeraCfgMgr: Reading stored module config
12-09 19:31:55.153 17172-17341/my.app D/ChimeraCfgMgr: Loading module com.google.android.gms.maps from APK /data/user/0/com.google.android.gms/app_chimera/chimera-module-root/module-71c764a6f3cb92bdc5525a965b589e7c5ed304f3/MapsModule.apk

12-09 19:31:55.154 17172-17341/my.app D/ChimeraModuleLdr: Loading module APK /data/user/0/com.google.android.gms/app_chimera/chimera-module-root/module-71c764a6f3cb92bdc5525a965b589e7c5ed304f3/MapsModule.apk
12-09 19:31:55.262 17172-17341/my.app D/ChimeraFileApk: Primary ABI of requesting process is armeabi-v7a
12-09 19:31:55.271 17172-17341/my.app D/ChimeraFileApk: Classloading successful. Optimized code found.
12-09 19:31:55.316 17172-17341/my.app W/System: ClassLoader referenced unknown path: /data/user/0/com.google.android.gms/app_chimera/chimera-module-root/module-71c764a6f3cb92bdc5525a965b589e7c5ed304f3/native-libs/armeabi-v7a

12-09 19:31:55.317 17172-17341/my.app W/System: ClassLoader referenced unknown path: /data/user/0/com.google.android.gms/app_chimera/chimera-module-root/module-71c764a6f3cb92bdc5525a965b589e7c5ed304f3/native-libs/armeabi
12-09 19:31:55.618 17172-17341/my.app I/Google Maps Android API: Google Play services client version: 7571000
12-09 19:31:55.630 17172-17341/my.app I/Google Maps Android API: Google Play services package version: 8489438
12-09 19:31:55.969 17172-17341/my.app I/e: Token loaded from file. Expires in: 423267993 ms.
12-09 19:31:55.969 17172-17341/my.app I/e: Scheduling next attempt in 422967 seconds.
12-09 19:31:56.338 17172-17341/my.app D/XXX: ... done

Как мы видим, это действительно занимает много времени...

Ответ 6

Для меня это было медленнее, чем 1сек, потому что я использовал:

mapFragment.getMap();

Затем я изменил на:

 mapFragment.getMapAsync(new OnMapReadyCallback() {
        @Override
        public void onMapReady(GoogleMap googleMap) {
            map = googleMap;
        }
 });

Использование getMapAsync() не блокирует ui, поэтому ваша активность будет загружаться перед картой. Его все еще медленно, но для моих целей это было нормально, только показывая сообщение загрузки.

Ответ 7

Подобно другим решениям здесь, но используя RxJava + RxAndroid.

Просто вызовите этот фрагмент из активности запуска onCreate.

Observable.fromCallable(new Callable<Void>() {
    @Override
    public Void call() {
        MapView mapView = new MapView(LaunchActivity.this); // Replace LaunchActivity with appropriate activity name
        mapView.onCreate(null);
        return null;
    }
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(
    new Action1<Void>() {
        @Override
        public void call(Void ignorable) {
            Log.i("Google Maps", "Initialised Google Maps.");
        }
    }, new Action1<Throwable>() {
        @Override
        public void call(Throwable ignorable) {
            Log.w("Google Maps", "[EXPECTED] Initialized Google Maps but got: " + ignorable.getMessage());
        }
    });