Как улучшить скорость загрузки фрагментов?

Повышение производительности:

Раньше я сохранял ВСЕ изображения в папке drawable, возможно, это было причиной того, что карта сначала загружалась медленно, когда рисовал маркеры на экране, изображение могло не соответствовать размеру экрана. Теперь я сохранил изображения в drawable-mdpi, drawable-hdpi и т. д., приложение работает более плавно, чем раньше. Надеюсь, поможет

Исходный вопрос:

Я создал карту во фрагменте, исходный код можно найти ниже.

Фрагмент карты тормозит при первой загрузке. Если я перехожу к любому другому фрагменту и снова щелкаю фрагмент карты, он загружается быстро и больше не слаг.

Кто-нибудь может сказать мне, что здесь происходит? Спасибо!

фрагмент_карты.xml, идентификатор map

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:map="http://schemas.android.com/apk/res-auto"
    android:id="@+id/map"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:name="com.google.android.gms.maps.SupportMapFragment" />

MyMapFragment.java (содержит onCreateView и setUpMapIfNeeded)

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    try {
        rootView = inflater.inflate(R.layout.fragment_map, container, false);
    } catch (InflateException e) {
    /* map is already there, just return view as it is */
        Log.e(TAG, "inflateException");
    }

    setUpMapIfNeeded();
     
    return rootView;
}


public void setUpMapIfNeeded() {
    // Do a null check to confirm that we have not already instantiated the fragment_map.
    if (myMap == null) {
        // Try to obtain the fragment_map from the SupportMapFragment.
        myMap = ((SupportMapFragment) MainActivity.fragmentManager.findFragmentById(R.id.map)).getMap();
        // Check if we were successful in obtaining the fragment_map.
        if (myMap != null) {
            setUpMap();
        }
    }
}

person Haifeng Zhang    schedule 08.10.2014    source источник
comment
Ты когда-нибудь что-нибудь понял по этому поводу?   -  person theblang    schedule 18.11.2014
comment
Я добавил небольшое (грязное) исправление в качестве ответа, потому что эта проблема все еще существует.   -  person Xyaren    schedule 25.03.2015


Ответы (5)


Я использую очень хакерский, но эффективный способ в своем приложении, но он работает хорошо. Мой mapFragment не отображается сразу после запуска приложения! В противном случае это не имело бы смысла.

Поместите это в свою активность запуска onCreate:

    // Fixing Later Map loading Delay
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                MapView mv = new MapView(getApplicationContext());
                mv.onCreate(null);
                mv.onPause();
                mv.onDestroy();
            }catch (Exception ignored){

            }
        }
    }).start();

Это создаст представление карты в фоновом потоке (далеко от пользовательского интерфейса) и вместе с ним инициализирует все сервисы Google Play и данные карты.

Загруженные данные составляют около 5 МБ дополнительно.

Если у кого-то есть идеи по улучшению, не стесняйтесь комментировать, пожалуйста!


Версия Java 8:

// Fixing Later Map loading Delay
new Thread(() -> {
    try {
        MapView mv = new MapView(getApplicationContext());
        mv.onCreate(null);
        mv.onPause();
        mv.onDestroy();
    }catch (Exception ignored){}
}).start();
person Xyaren    schedule 25.03.2015
comment
Ты восхитителен. Я пытался исправить это в течение некоторого времени, думал, что это даже не связано с анимацией. Для меня это не взлом, это предзагрузка, мне нравится :) - person guy_m; 15.10.2015
comment
На самом деле, я бы с радостью дал вам награду за это. Можно ли начинать награду только за это или это против правил? Серьёзно спрашивал.. - person guy_m; 15.10.2015
comment
Я рад, что смог помочь :) Я думаю, что награда возможна, но я не эксперт по этому вопросу. - person Xyaren; 15.10.2015
comment
я бы это даже хакишным не назвал - person Cruncher; 27.10.2015
comment
это прекрасно работает на Android 5.1, на устройстве под управлением 4.0.4 происходит сбой с: RuntimeException: невозможно создать обработчик внутри потока, который не вызвал Looper.prepare() - person marmor; 04.11.2015
comment
Попробуйте запустить Runnable в потоке пользовательского интерфейса, используя runOnUiThread() вместо new Thread().start() - person Xyaren; 05.11.2015
comment
Я поместил этот трюк в свой класс BaseApplication onCreate(), чтобы загружать playservices каждый раз, когда приложение запускается, потому что в моем приложении карты будут загружаться в любое время. Я сократил время загрузки mapFragment с 980 мс до 311 мс, отлично. Спасибо - person Pelanes; 11.05.2016
comment
Ха-ха, если вы не проигнорируете исключение, вы получите java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() - person Langusten Gustel; 30.09.2016
comment
Хорошо, поэтому это обходной путь. Все еще делает свою работу. - person Xyaren; 30.09.2016
comment
2 вещи, которые я заметил. 1) Он по-прежнему работает медленно, когда вы не используете new Thread() 2) Он по-прежнему работает медленно, когда вы используете new Thread() и используете другие методы жизненного цикла mapView.onStart(), mapView.onStop... - person Jemshit Iskenderov; 27.02.2017
comment
Только что заметил ошибку, написанную @LangustenGustel, из-за которой код застревает на mv.onCreate(null);, а остальные даже не выполняются! Теперь изменен код на mapView.getMapAsync(this); после mapView.onCreate(null); без new Thread(). И в обратном вызове onMapReady() я закрываю экран запуска - person Jemshit Iskenderov; 10.03.2017
comment
Карта не загружается. - person us2956; 28.03.2018
comment
FWIW Я обнаружил ошибку в Google: issuetracker.google.com/issues/80147879 Не стесняйтесь пометьте это, если вы считаете, что они должны решить это в корне проблемы - person murki; 23.05.2018

Просто чтобы добавить к ответу @Xyaren, мне нужно, чтобы он работал для SupportFragment, что, казалось, требовало некоторых дополнительных шагов. Внедрите в свою деятельность OnMapReadyCallback.

В вашем onCreate:

new Thread(() -> {
    try {
        SupportMapFragment mf = SupportMapFragment.newInstance();
        getSupportFragmentManager().beginTransaction()
                .add(R.id.dummy_map_view, mf)
                .commit();
        runOnUiThread(() -> mf.getMapAsync(SplashActivity.this));
    }catch (Exception ignored){
        Timber.w("Dummy map load exception: %s", ignored);
    }
}).start();

Вам нужно будет реализовать это:

@Override
public void onMapReady(GoogleMap googleMap) {
    // Do nothing because we only want to pre-load map.
    Timber.d("Map loaded: %s", googleMap);
}

и в вашем макете деятельности:

<FrameLayout
    android:id="@+id/dummy_map_view"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:visibility="gone"/>

Он должен пройти все шаги, включая транзакцию для сервисов Google Play, чтобы загрузить данные карты.

person Conti    schedule 23.08.2016

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

Посмотрите мой связанный пост здесь: First запуск Activity with Google Maps очень медленный

person Wookie    schedule 22.12.2014
comment
or just unplugged the USB cable это мне очень помогло - person vahid; 15.03.2021

[ОТРЕДАКТИРОВАНО]

Методы getMap() и setUpMap(), вероятно, очень медленные. Их обработка должна выполняться в AsyncTask, чтобы onCreateView() мог каждый раз быстро возвращаться.

Дополнительная информация: onCreateView() вызывается в потоке пользовательского интерфейса, поэтому любая медленная обработка, которую он выполняет, приведет к зависанию пользовательского интерфейса. Ваш AsyncTask должен выполнять всю медленную обработку в своем методе doInBackground(), а затем обновлять пользовательский интерфейс в своем методе onPostExecute(). Дополнительную информацию см. в AsyncTask JavaDoc.

person cybersam    schedule 08.10.2014
comment
Спасибо за быстрый ответ, я все еще медленно комментирую setUpMap - person Haifeng Zhang; 09.10.2014
comment
getMap() может быть медленным. Таким образом, вызов getMap() также должен обрабатываться AsyncTask. Я отредактировал свой ответ. - person cybersam; 09.10.2014
comment
в чем разница между getMap() в моем фрагменте и AsyncTask? Если я помещу его в асинтаск, как я узнаю, что getMap() готов, кроме нуля? - person Haifeng Zhang; 09.10.2014
comment
Я добавил больше информации в свой ответ. - person cybersam; 09.10.2014
comment
спасибо за помощь, попробовал асинтаск, не помогает - person Haifeng Zhang; 09.10.2014
comment
Я также пробовал это без везения. Похоже, что он не использует какое-либо время в потоке пользовательского интерфейса, по крайней мере, непосредственно из вызова getMap. - person Kenneth; 07.11.2014
comment
Я проверял, эта медленная загрузка не имеет ничего общего с getMap. Задержка происходит где-то между onViewCreated и onStart в этом коде. - person theblang; 17.11.2014
comment
используйте этот mapView.getMapAsync(это); - person raditya gumay; 22.05.2016

Вы можете попробовать это

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.mapActivity);
    getSreenDimanstions();
    fragment = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map));
    
    map = fragment.getMap();    
}

Этот класс расширен от Activity

person Kelo Adler    schedule 08.10.2014