Android - запобігання білого екрану при запуску


110

Як ми всі знаємо, багато додатків для Android відображають білий екран дуже коротко, перш ніж їх перший Activityприйшов у фокус. Ця проблема спостерігається в таких випадках:

  • Додатки для Android, що розширюють глобальний Applicationклас та виконують основні ініціалізації в ньому. Application Об'єкт створюється завжди перед першим Activity(факт , що можна спостерігати в отладчике), так що це має сенс. Це причина затримки в моєму випадку.

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

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

Тим часом додатки, які не розширюють Applicationклас , не роблять показують білий екран при запуску.

Вся справа в тому, що в ідеалі ініціалізації, що виконуються в Applicationоб'єкті, повинні відбуватися до того, Activityяк будуть показані перші . Отже, моє запитання полягає в тому, як я можу виконати ці ініціалізації при запуску програми без використання Applicationоб'єкта? Можливо, використовуючи Threadабо Service, я думаю, що?

Це цікава проблема, про яку слід подумати. Я не можу обійти його звичайним способом (встановивши NoActionBarтему), оскільки трагічно мій екран Splash насправді ActionBarпов'язаний із деякими непов'язаними причинами.

Примітка:

Я вже звертався до таких питань:

Список літератури:


1
Ви самі знайшли проблему, ви робите багато хто з init у контексті програми, блокуючи завантаження активності, намагайтеся асинхронізувати це, дозволяючи активізації завантаження відображатися, поки не закінчиться деяка нитка.
AxelH

Це може допомогти
Макс

1
В ідеалі додаток буде вивантажувати обробку і не використовувати основну нитку для тривалих операцій. Це добре прийнята практика. Якщо операції потрібно здійснити перед завантаженням програми, то вона, принаймні, не повинна мати спільний потік з інтерфейсом користувача.
Бешой Ганною

1
Ви можете виявити, що це все ще проблема після того, як ви перемістили весь ініціалізаційний код із Applicationкласу. Це пов’язано з новішими версіями Android способу "холодного запуску" додатків. Google фактично вирішив час запуску в Google I / O цього року, і це буде фіксовано в N від того, що я пам’ятаю. Тим часом слід переглянути, як Google називає "фірмовий стартовий екран". Ось приклад того, як його створити: antonioleiva.com/branded-launch-screen - на початку більше немає білого екрана ;-) І, будь ласка, не використовуйте splashscreens - це дратує користувача.
Дарвінд

1
Тема Wrt, хитрість полягає не у встановленні теми NoActionBar, а в налаштуванні теми початкової діяльності так, щоб порожній тематичний екран виглядав як повністю ініціалізований.
zapl

Відповіді:


86

Проблема з білим тлом викликана холодним запуском андроїда, поки додаток завантажується в пам'ять, і цього можна уникнути:

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>

Додайте цю тему до свого splashscreen у маніфесті

<?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 () розізлив видимий вміст і анімував його іншим розумним моїм білим вниз між переходом. анімація тем допомогла багато
Мехвіш Алі

93

будь ласка, додайте цей рядок у тему програми

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

для отримання додаткової інформації: https://developer.android.com/topic/performance/vitals/launch-time#themed


25
Він висить додаток на 2 секунди, а потім запуск програми, не корисний для мене!
Фаахір

4
натерти зараз він не показує #ffffff color, але він тепер показує # 000000
Midhilaj

@Faakhir Отже, ти знайшов якесь рішення? Я все ще шукаю рішення, яке видалить цей білий екран, а також немає затримки на час запуску.
Rupam Das

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/

Але що ще важливіше, оптимізуйте початкове навантаження та відкладіть будь-яку важку роботу, коли встигнете її виконати. Опублікуйте свій клас заявки тут, якщо ви хочете, щоб ми його ознайомили.


20

Рекомендований спосіб вирішення цієї проблеми відсутній у відповідях. Тому я додаю тут свою відповідь. Проблема під час запуску з білим екраном виникає через початковий порожній екран, який системний процес малює під час запуску програми. Поширений спосіб вирішити це - вимкнути цей початковий екран, додавши це у свій 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>

Додайте цю тему до своєї початкової діяльності у файлі Manifest

<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 Material Design .


14

Ви спробували встановитиandroid:windowBackground атрибут у темі вашої запускової діяльності на колір або на малюнок?

Наприклад це:

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

при додаванні до теми запуску буде показано чорний колір (а не білий колір) при запуску. Це простий трюк, щоб приховати довгу ініціалізацію, при цьому показуючи користувачам щось, і це чудово працює, навіть якщо ви підкласируєте об’єкт 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>

Вихід:

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

Сподіваюся, це допоможе вам.


2
Це відмінно підходить для програми NativeActivity OpenGL. Я не впевнений, чому це не вище у відповідях, оскільки це найбільш повна і доцільна відповідь. Жодна Java не включала лише декілька змін XML-файлів.
Сліон

7

У межах методів зворотного виклику життєвого циклу ви можете оголосити, як поводиться ваша діяльність, коли користувач залишає та знову входить у діяльність. Пам’ятайте, що в тому, як Android розроблений, існує життєвий цикл для кожного додатка. Якщо ви покладете занадто багато навантаження наonCreate() метод (який є методом, який використовується для завантаження файлів макета та дезабілітації будь-яких елементів управління, які у вас є), білий екран стане більш помітним, оскільки завантажувальний файл займе більше часу.

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

Щоб зробити вас легше, нижче наведена офіційна схема життєвого циклу діяльності:

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


Дякую за вашу відповідь, це було дуже цікаво. Однак я вважаю, що ви неправильно зрозуміли моє запитання. Проблема викликана не ініціалізаціями в першій Activity, а тими в глобальному Applicationоб'єкті. І я не вірю, що я можу застосувати таке розмежування проблем, тому що на відміну від цього є Activityлише onCreate()метод.
YS

Чому ви розширюєте клас додатків, а не діяльність?
Мішель Ла Ферла

Гаразд, значить, ви маєте на увазі, що я повинен повністю відмовитися від 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>

0

Просто запишіть елемент у значення / 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-версію та встановите її на свій телефон, ви помітите, що для завантаження потрібно набагато менше.

Тому час запуску версії для дебюгу не дорівнює часу запуску версії для випуску.

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