Android - предотвращение появления белого экрана при запуске

110

Как мы все знаем, многие приложения для Android очень ненадолго отображают белый экран, прежде чем они Activityпопадают в фокус. Эта проблема наблюдается в следующих случаях:

  • Приложения для Android, расширяющие глобальный Application класс и выполняют в нем основные инициализации. Application Объект создается всегда перед первым Activity(факт , что можно наблюдать в отладчике), так что это имеет смысл. Это причина задержки в моем случае.

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

Настройка здесь android:windowDisablePreview = "true"явно не работает. Я также не могу установить родительскую тему экрана-заставки, Theme.Holo.NoActionBarкак описано здесь , потому что [к сожалению] мой экран-заставка использует файл ActionBar.

Между тем, приложения, которые не расширяют Applicationкласс , не показывают белый экран при запуске.

Дело в том, что в идеале инициализации, выполняемые в Applicationобъекте, должны происходить до того, как Activityбудет показана первая . Итак, мой вопрос: как я могу выполнить эти инициализации при запуске приложения без использования Applicationобъекта? Возможно, с помощью Threadили Service, я полагаю?

Это интересная проблема, над которой стоит задуматься. Я не могу обойти это обычным способом (установив NoActionBarтему), так как, к сожалению, у моего экрана-заставки есть ActionBarнекоторые причины, не связанные с этим.

Примечание:

Я уже затронул следующие вопросы:

Ссылки:

YS
источник
1
Вы сами обнаружили проблему, вы выполняете много init в контексте приложения, блокируя загрузку активности, пытаетесь асинхронизировать это, позволяя загрузочной активности отображаться до тех пор, пока не закончится какой-то поток.
AxelH
Это может помочь
Макс
1
В идеале приложение должно разгрузить обработку и не использовать основной поток для длительных операций. Это общепринятая практика. Если операции должны выполняться до загрузки приложения, оно, по крайней мере, не должно делиться потоком с пользовательским интерфейсом.
Бешой Ханна
1
Вы можете обнаружить, что это все еще проблема после того, как вы переместили весь код инициализации из Applicationкласса. Это связано с тем, что более новые версии Android используют способ «холодного запуска» приложений. Google фактически рассмотрел время запуска на Google I / O в этом году, и оно будет исправлено на N, насколько я помню. А пока вам стоит взглянуть на то, что Google называет «фирменным экраном запуска». Вот пример того, как его создать: antonioleiva.com/branded-launch-screen - никакого белого экрана в начале ;-) И, пожалуйста, не используйте заставки - это раздражает пользователя.
Darwind
1
В случае с темой фокус не в том, чтобы установить тему NoActionBar, а в том, чтобы настроить тему начального действия так, чтобы пустой тематический экран выглядел как полностью инициализированный.
запл

Ответы:

86

Проблема с белым фоном вызвана холодным запуском Android при загрузке приложения в память, и ее можно избежать следующим образом:

public class OnboardingWithCenterAnimationActivity extends AppCompatActivity {
public static final int STARTUP_DELAY = 300;
public static final int ANIM_ITEM_DURATION = 1000;
public static final int ITEM_DELAY = 300;

private boolean animationStarted = false;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    setTheme(R.style.AppTheme);
    getWindow().getDecorView().setSystemUiVisibility(
            View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_onboarding_center);
}

@Override
public void onWindowFocusChanged(boolean hasFocus) {

    if (!hasFocus || animationStarted) {
        return;
    }

    animate();

    super.onWindowFocusChanged(hasFocus);
}

private void animate() {
    ImageView logoImageView = (ImageView) findViewById(R.id.img_logo);
    ViewGroup container = (ViewGroup) findViewById(R.id.container);

    ViewCompat.animate(logoImageView)
        .translationY(-250)
        .setStartDelay(STARTUP_DELAY)
        .setDuration(ANIM_ITEM_DURATION).setInterpolator(
            new DecelerateInterpolator(1.2f)).start();

    for (int i = 0; i < container.getChildCount(); i++) {
        View v = container.getChildAt(i);
        ViewPropertyAnimatorCompat viewAnimator;

        if (!(v instanceof Button)) {
            viewAnimator = ViewCompat.animate(v)
                    .translationY(50).alpha(1)
                    .setStartDelay((ITEM_DELAY * i) + 500)
                    .setDuration(1000);
        } else {
            viewAnimator = ViewCompat.animate(v)
                    .scaleY(1).scaleX(1)
                    .setStartDelay((ITEM_DELAY * i) + 500)
                    .setDuration(500);
        }

        viewAnimator.setInterpolator(new DecelerateInterpolator()).start();
    }
}
}

макет

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?colorPrimary"
android:orientation="vertical"
>

<LinearLayout
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:gravity="center"
    android:orientation="vertical"
    android:paddingTop="144dp"
    tools:ignore="HardcodedText"
    >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="16dp"
        android:alpha="0"
        android:text="Hello world"         android:textAppearance="@style/TextAppearance.AppCompat.Widget.ActionBar.Title.Inverse"
        android:textColor="@android:color/white"
        android:textSize="22sp"
        tools:alpha="1"
        />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="8dp"
        android:alpha="0"
        android:gravity="center"
        android:text="This a nice text"
      android:textAppearance="@style/TextAppearance.AppCompat.Widget.ActionBar.Subtitle.Inverse"
        android:textSize="20sp"
        tools:alpha="1"
        />

    <Button
        android:id="@+id/btn_choice1"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="48dp"
        android:scaleX="0"
        android:scaleY="0"
        android:text="A nice choice"
        android:theme="@style/Button"
        />

    <Button
        android:id="@+id/btn_choice2"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="4dp"
        android:scaleX="0"
        android:scaleY="0"
        android:text="Far better!"
        android:theme="@style/Button"
        />

</LinearLayout>

<ImageView
    android:id="@+id/img_logo"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:src="@drawable/img_face"
    tools:visibility="gone"
    />
</FrameLayout>

img лицо

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
        android:opacity="opaque">

<item android:drawable="?colorPrimary"/>
<item>
    <bitmap
        android:gravity="center"
        android:src="@drawable/img_face"/>
</item>

Добавьте эту тему на свой экран-заставку в манифесте

<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="android:windowBackground">@null</item>
</style>

<style name="AppTheme.CenterAnimation">
    <item name="android:windowBackground">@drawable/ll_face_logo</item>
</style>

что даст такой эффект

занятой кот

для получения дополнительной информации и дополнительных решений вы можете проверить этот BlogPost

Иван Милисавлевич
источник
3
не помогло все еще белый экран и анимация в конце
Мехвиш Али
Это прямая реализация. Могут быть другие части вашего кода, которые вызывают проблему. Пожалуйста, откройте еще один вопрос, и я буду рядом, чтобы помочь вам :)
Иван Милисавлевич
1
Я решил эту проблему, анимируя между темами и меняя тему без возможности рисования, но только с тем же цветом задней части, а затем на onWindowFocusChanged () без видимого содержимого и анимации его, в противном случае я также убрал между переходами. очень помогла анимация тем
Мехвиш Али
94

пожалуйста, добавьте эту строку в свою тему приложения

<item name="android:windowDisablePreview">true</item>

для получения дополнительной информации: https://developer.android.com/topic/performance/vitals/launch-time#themed

Хитеш Сингх
источник
25
Зависает приложение на 2 секунды, а затем запускается, мне бесполезно!
Faakhir
4
Решетка теперь не показывает цвет #ffffff, но теперь показывает # 000000
Midhilaj
@Faakhir Так ты нашел какое-нибудь решение? Я все еще ищу решение, которое убирает этот белый экран, а также нет задержки при запуске.
Рупам Дас
33

Скопируйте и вставьте эти две строки в свою тему приложения манифеста, то есть res / styles / AppTheme. тогда это будет работать как шарм ..

<item name="android:windowDisablePreview">true</item>
<item name="android:windowIsTranslucent">true</item>
прасад редди
источник
21

Прежде всего, чтобы убрать белый экран, прочтите это - https://www.bignerdranch.com/blog/splash-screens-the-right-way/

Но что более важно, оптимизируйте начальную нагрузку и отложите любую тяжелую работу до того момента, когда у вас будет время ее выполнить. Разместите здесь свой класс приложения, если хотите, чтобы мы его рассмотрели.

Шмуэль
источник
21

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

<item name="android:windowDisablePreview">true</item>

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

Как это:

Файл с возможностью рисования, my_drawable.xml

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque">
  <!-- The background color, preferably the same as your normal theme -->
  <item android:drawable="@android:color/white"/>
  <!-- Your product logo - 144dp color version of your app icon -->
  <item>
    <bitmap
      android:src="@drawable/product_logo_144dp"
      android:gravity="center"/>
  </item>
</layer-list>

Создайте новый стиль в своем styles.xml

<!-- Base application theme. -->
<style name="AppTheme">
    <!-- Customize your theme here. -->               
</style>

<!-- Starting activity theme -->
<style name="AppTheme.Launcher">
    <item name="android:windowBackground">@drawable/my_drawable</item>
</style>

Добавьте эту тему в свою начальную деятельность в файле манифеста

<activity ...
android:theme="@style/AppTheme.Launcher" />

И когда вы хотите вернуться к обычному вызову темы setTheme(R.style.Apptheme)перед вызовом super.onCreate()иsetContentView()

public class MainActivity extends AppCompatActivity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    // Make sure this is before calling super.onCreate
    setTheme(R.style.Theme_MyApp);
    super.onCreate(savedInstanceState);
    // ...
  }
}

Это рекомендуемый способ решения проблемы, взятый из шаблонов дизайна материалов Google .

Сэм
источник
14

Вы пробовали установитьandroid:windowBackground атрибута в теме вашей активности запуска либо цвет, либо возможность рисования?

Например это:

<item name="android:windowBackground">@android:color/black</item>

при добавлении в тему активности Launcher при запуске будет отображаться черный цвет (а не белый цвет). Это простой трюк, позволяющий скрыть длительную инициализацию, показывая что-то вашим пользователям, и он отлично работает, даже если вы создаете подкласс объекта Application.

Избегайте использования других конструкций (даже потоков) для выполнения длительных задач инициализации, потому что вы можете оказаться не в состоянии контролировать жизненный цикл таких конструкций. Объект Application - правильное место для выполнения именно этого типа действий.

гметалл
источник
14

Я добавил следующие две строки в свою тему в styles.xml

    <item name="android:windowDisablePreview">true</item>
    <item name="android:windowBackground">@null</item>

Работал как шарм

Аканши Шривастава
источник
10

У меня была такая же проблема, вам нужно обновить свой стиль.

style.xml

<!-- Base application theme. -->
 <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">

        <!-- Customize your theme here. -->
        <item name="drawerArrowStyle">@style/DrawerArrowStyle</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowDisablePreview">true</item>
        <item name="android:windowBackground">@null</item>
        <item name="android:windowIsTranslucent">true</item>

 </style>

Ваш файл манифеста должен выглядеть, как показано ниже.

<application
        android:name=".MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
     // Other stuff
</application>

Outout:

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

Надеюсь, это поможет тебе.

Хирен Патель
источник
2
Это отлично работает для меня в приложении NativeActivity OpenGL. Я не уверен, почему это не выше в ответах, поскольку это наиболее полный и целесообразный ответ. Никакая Java не требует всего лишь пары изменений файла XML.
Slion 02
7

В методах обратного вызова жизненного цикла вы можете объявить, как будет вести себя ваше действие, когда пользователь покидает и снова входит в действие. Помните, что в дизайне Android есть жизненный цикл для каждого приложения. Если вы поместите слишком большую нагрузку наonCreate() метод (это метод, используемый для загрузки файлов макета и инициализации любых элементов управления, которые у вас есть), тогда белый экран станет более заметным, так как файл макета будет загружаться дольше.

Я предлагаю использовать несколько разных методов, начиная деятельность. Таковы onStart()(вызываемые первым делом после загрузки приложения),onActivityCreated() (вызывается после отображения макета и полезен, если вы выполняете какую-либо обработку данных при запуске действия).

Чтобы вам было проще, ниже представлена ​​официальная диаграмма жизненного цикла активности:

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

Мишель Ла Ферла
источник
Спасибо за ответ, было очень интересно. Однако я считаю, что вы неправильно поняли мой вопрос. Проблема вызвана не инициализациями в первом Activity, а глобальным Applicationобъектом. И я не верю, что могу применить там такое разделение проблем, потому что, в отличие от этого, у Activityнего есть только onCreate()метод.
YS
Почему вы расширяете класс приложения, а не класс деятельности?
Michele La Ferla
Ладно, значит, вы имеете в виду, что я должен полностью отказаться от Applicationобъекта и переместить весь код инициализации на первый Activity...
YS
Именно так я всегда разрабатывал свои приложения, однако, если вы не хотите вносить все эти изменения, другие ответы могут помочь вам обойти проблему с помощью класса приложения. Для справки в будущем я рекомендую сразу использовать один класс деятельности, а затем несколько фрагментов. Надеюсь, это поможет :)
Мишель Ла Ферла
2

Вы пробовали поставить инициализацию на onActivityCreated ?

Внутри Applicationкласса:

 registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                if(activity.getClass().equals(FirstActivity.class) {
                    // try without runOnUiThread if it will not help
                    activity.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            new InitializatioTask().execute();
                        }
                    });
                }
            }

            @Override
            public void onActivityStarted(Activity activity) {

            }

            @Override
            public void onActivityResumed(Activity activity) {

            }

            @Override
            public void onActivityPaused(Activity activity) {

            }

            @Override
            public void onActivityStopped(Activity activity) {

            }

            @Override
            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {

            }

            @Override
            public void onActivityDestroyed(Activity activity) {

            }
        });
Сергей Шустиков
источник
2

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

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

Когда вы покажете заставку из вашего файла splash.xml, эта проблема останется прежней,

Таким образом, вам нужно создать стиль ont в файле style.xml для экрана-заставки, и там вы должны установить фон окна в качестве изображения-заставки, а затем применить эту тему к своей активности-заставке из файла манифеста. Итак, теперь, когда вы запустите приложение, сначала оно установит тему, и таким образом пользователь сможет видеть непосредственно заставку вместо белого экрана.

Викиэксперт
источник
2

Оба свойства работают

    <style name="AppBaseThemeDark" parent="@style/Theme.AppCompat">
            <!--your other properties -->
            <!--<item name="android:windowDisablePreview">true</item>-->
            <item name="android:windowBackground">@null</item>
            <!--your other properties -->
    </style>
Сохаил Захид
источник
2

Пожалуйста, попробуйте это один раз.

1) Создайте файл с возможностью рисования splash_background.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@color/{your color}" />

    <item>
        <bitmap
            android:layout_width="@dimen/size_250"
            android:layout_height="@dimen/size_100"
            android:gravity="center"
            android:scaleType="fitXY"
            android:src="{your image}"
            android:tint="@color/colorPrimary" />
    </item>

</layer-list>

2) Поместите это в styles.xml

     <style name="SplashTheme" parent="Theme.AppCompat.NoActionBar">
         <item name="android:windowBackground">@drawable/background_splash</item>
     </style>

3) В файле AndroidMainfest.xml установите для указанной выше темы значение «Запуск действия».

       <activity
            android:name=".SplashScreenActivity"
            android:screenOrientation="portrait"
            android:theme="@style/SplashTheme"
            android:windowSoftInputMode="stateVisible|adjustResize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
Сурендар D
источник
0

Просто напишите элемент в values ​​/ styles.xml:

<item name="android:windowBackground">@android:color/black</item>

Например, в AppTheme:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="windowNoTitle">true</item>
    <item name="windowActionBar">false</item>
    <item name="android:windowFullscreen">true</item>
    <item name="android:windowContentOverlay">@null</item>

    <item name="android:windowBackground">@android:color/black</item>

    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
</style>
Хавьер Рейносо
источник
0
Style :- 
<style name="SplashViewTheme" parent="Theme.AppCompat.NoActionBar">
    <item name="android:windowBackground">@drawable/splash</item>
    <item name="windowActionBar">false</item>
    <item name="windowNoTitle">true</item>
</style>

In Manifest :- 
<activity android:name=".SplashActivity"
        android:theme="@style/SplashViewTheme">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
Кришна
источник
0

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

Таким образом, время запуска с версией отладки не равно времени запуска с версией выпуска.

Моинти
источник