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

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

Я пытался:

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

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

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

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

спасибо

Причина, по которой первая загрузка занимает много времени, заключается в том, что 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 Services не будут загружены. Метод getMapAsync сам должен также вызываться из основного потока.

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

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

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

  // 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 необходима, чтобы гарантировать, что мы не пытаемся добавить карту в некоторые несуществующие действия или фрагменты.

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

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

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

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

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

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

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

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

Вот мой код из «основной» деятельности:

 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 

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

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

 mapFragment.getMap(); 

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

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

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

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

Просто назовите этот фрагмент из действия launcher onCreate .

 Observable.fromCallable(new Callable<Void>() { @Override public Void call() { MapView mapView = new MapView(LaunchActivity.this); // Replace LaunchActivity with appropriate activity's 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()); } }); 

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

 // In your Application class GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(); 

Проверка загрузит версию сервиса gplay при запуске. Теперь, спектакли подходят для меня, но первый запуск активности карты все еще немного отстает.