Android - Evita tela branca na inicialização


110

Como todos sabemos, muitos aplicativos Android exibem uma tela branca brevemente antes de seu primeiro Activityentrar em foco. Este problema é observado nos seguintes casos:

  • Aplicativos Android que estendem a Applicationclasse global e executam inicializações importantes nela. O Application objeto é sempre criado antes do primeiro Activity(fato que pode ser observado no depurador), então faz sentido. Essa é a causa do atraso no meu caso.

  • Aplicativos Android que exibem a janela de visualização padrão antes da tela inicial.

A configuração android:windowDisablePreview = "true"obviamente não funciona aqui. Nem posso definir o tema pai da tela inicial Theme.Holo.NoActionBarconforme descrito aqui , porque [infelizmente] minha tela inicial usa umActionBar .

Enquanto isso, aplicativos que não estendem a Applicationclasse não mostram a tela branca na inicialização.

A questão é que, idealmente, as inicializações realizadas no Applicationobjeto precisam ocorrer antes que a primeira Activityseja mostrada. Então, minha pergunta é: como posso realizar essas inicializações na inicialização do aplicativo sem usar um Applicationobjeto? Possivelmente usando um Threadou Service, suponho?

Este é um problema interessante para se pensar. Não consigo ignorar da maneira usual (definindo o NoActionBartema), pois tragicamente minha tela inicial tem umActionBar devido a alguns motivos não relacionados.

Nota:

Já me referi às seguintes questões:

Referências:


1
Você mesmo encontrou o problema, está fazendo para muitos init in no contexto da aplicação, bloqueando o carregamento da atividade, tente assincronizar isso, deixando uma atividade de carregamento aparecer até que algum thread termine.
AxelH

Isso pode ajudar
Máx.

1
Idealmente, um aplicativo descarregaria o processamento e não usaria o thread principal para operações longas. Esta é uma prática bem aceita. Se as operações precisarem acontecer antes de o aplicativo carregar, ele pelo menos não deve compartilhar um thread com a IU.
Beshoy Hanna

1
Você pode descobrir que isso ainda é um problema depois de mover todos os códigos de inicialização para fora da Applicationclasse. Isso se deve às versões mais recentes da maneira do Android de "inicializar a frio" os aplicativos. O Google realmente abordou os horários de lançamento no Google I / O este ano e será corrigido em N pelo que me lembro. Nesse ínterim, você deve olhar para o que o Google chama de "tela de lançamento de marca". Aqui está um exemplo de como criá-lo: antonioleiva.com/branded-launch-screen - chega de tela branca no início ;-) E, por favor, não use splashscreens - é irritante para o usuário.
Darwind

1
Agora, o truque não é definir um tema NoActionBar, mas ajustar o tema da atividade inicial para que uma tela com o tema vazio se pareça com a totalmente inicializada.
zapl

Respostas:


86

O problema com o fundo branco é causado pela inicialização a frio do Android enquanto o aplicativo carrega na memória e pode ser evitado com isto:

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();
    }
}
}

layout

<?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>

cara 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>

Adicione este tema à sua tela inicial no manifesto

<?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>

que irá produzir um efeito como este

um gato ocupado

para mais detalhes e mais soluções você pode verificar este BlogPost


3
não ajudou ainda tela branca e animação no final
Mehvish Ali

Esta é uma implementação direta. Pode haver algumas outras partes do seu código que estão causando o problema. Abra outra pergunta e estarei lá para ajudá-lo :)
Ivan Milisavljevic

1
Resolvi esse problema animando entre os temas e alterando o tema sem drawable, mas apenas a cor de fundo da mesma e, em seguida, em onWindowFocusChanged () tornei o conteúdo visível e o animado de outra forma também meu branco entre a transição. animação de temas ajudou muito
Mehvish Ali

92

por favor, adicione esta linha ao tema do seu aplicativo

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

para mais informações: https://developer.android.com/topic/performance/vitals/launch-time#themed


25
Ele suspende o aplicativo por 2 segundos e depois o inicia, não é útil para mim!
Faakhir,

4
grate agora não está mostrando a cor #ffffff, mas agora está mostrando # 000000
Midhilaj

@Faakhir Então você encontrou alguma solução? Ainda estou procurando uma solução, que remova essa tela branca e também não haja demora no lançamento.
Rupam Das

33

Copie e cole essas duas linhas no tema do aplicativo de manifesto, ou seja, res / styles / AppTheme. então vai funcionar como um encanto ..

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


20

A maneira recomendada de resolver esse problema está faltando nas respostas. Portanto, estou adicionando minha resposta aqui. O problema de tela branca na inicialização ocorre por causa da tela em branco inicial que o processo do sistema desenha ao iniciar o aplicativo. Uma maneira comum de resolver isso é desligar esta tela inicial adicionando-a ao seu styles.xmlarquivo.

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

Mas, de acordo com a documentação do Android, isso pode resultar em um tempo de inicialização mais longo. A maneira recomendada de evitar essa tela branca inicial de acordo com o Google é usar owindowBackground atributo tema e fornecer um drawable personalizado simples para a atividade inicial.

Como isso:

Arquivo de layout drawable, 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>

Crie um novo estilo em seu 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>

Adicione este tema à sua atividade inicial no arquivo Manifest

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

E quando você quiser voltar ao seu tema normal, ligue setTheme(R.style.Apptheme)antes de ligar super.onCreate()esetContentView()

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);
    // ...
  }
}

Esta é a maneira recomendada para resolver o problema e isso vem dos padrões do Google Material Design .


14

Você já tentou definir oandroid:windowBackground atributo no tema de sua atividade de inicialização, como uma cor ou um desenho?

Por exemplo, este:

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

quando adicionado ao tema de atividade do Launcher, irá mostrar uma cor preta (em vez da cor branca) na inicialização. Este é um truque fácil para ocultar a inicialização longa, enquanto mostra algo aos usuários, e funciona bem mesmo se você criar uma subclasse do objeto Aplicativo.

Evite usar outras construções (mesmo Threads) para fazer longas tarefas de inicialização, porque você pode acabar não sendo capaz de controlar o ciclo de vida de tais construções. O objeto Aplicativo é o local correto para realizar exatamente esse tipo de ação.


14

Eu adicionei as duas linhas a seguir em meu tema em styles.xml

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

Funcionou como um encanto


10

Eu tive o mesmo problema, você tem que atualizar seu estilo.

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>

Seu arquivo de manifesto deve ser semelhante a abaixo.

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

Fora fora:

insira a descrição da imagem aqui

Espero que isso possa ajudá-lo.


2
Isso funciona muito bem para mim em um aplicativo NativeActivity OpenGL. Não sei por que isso não está no topo das respostas, pois é a resposta mais completa e conveniente. Nenhum Java envolveu apenas algumas alterações no arquivo XML.
Slion

7

Dentro dos métodos de retorno de chamada do ciclo de vida, você pode declarar como sua atividade se comporta quando o usuário sai e entra novamente na atividade. Lembre-se de que, da maneira como o Android foi projetado, há um ciclo de vida para cada aplicativo. Se você colocar muita carga no onCreate()método (que é o método usado para carregar os arquivos de layout e inicializar quaisquer controles que você tenha nele), então a tela branca ficará mais visível, pois o arquivo de layout demorará mais para carregar.

Sugiro usar vários métodos diferentes ao iniciar uma atividade. Tais são o onStart()(sendo chamado como a primeira coisa depois que o aplicativo é carregado), onActivityCreated()(sendo chamado depois que o layout é exibido e útil se você estiver fazendo qualquer processamento de dados ao iniciar a atividade).

Para facilitar para você, abaixo está o diagrama oficial do ciclo de vida da atividade:

insira a descrição da imagem aqui


Obrigado pela sua resposta, foi muito interessante. No entanto, acredito que você entendeu mal minha pergunta. O problema não é causado pelas inicializações no primeiro Activity, mas sim no Applicationobjeto global . E não acredito que possa aplicar essa separação de preocupações aqui, porque ao contrário de um, Activityela só tem um onCreate()método.
YS de

Por que você está estendendo a classe de aplicativo e não a de atividade?
Michele La Ferla

Ok, então você quer dizer que devo abandonar o Applicationobjeto completamente e mover todo o código de inicialização para o primeiro Activity...
YS

É assim que sempre desenvolvi meus aplicativos, no entanto, se você não deseja fazer todas essas alterações, outras respostas podem ajudá-lo a contornar seu problema usando a classe de aplicativo. Para sua referência futura, recomendo usar uma classe de atividade imediatamente e, em seguida, muitos fragmentos. Espero que isso ajude :)
Michele La Ferla

2

Você tentou colocar a inicialização em onActivityCreated?

Dentro da Applicationclasse:

 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

Como você já sabe por que essa tela branca está ali, como devido a processos em segundo plano ou inicialização de aplicativos ou arquivos grandes, basta verificar a seguir a ideia para superar isso.

Para evitar essa tela branca no início do aplicativo, uma forma é a tela inicial, esta é apenas uma forma não final e você deve ter que usar.

Quando você mostrar a tela inicial do arquivo splash.xml, este problema permanecerá o mesmo,

Portanto, você deve criar um estilo no arquivo style.xml para a tela inicial e definir o plano de fundo da janela como sua imagem inicial e, em seguida, aplicar esse tema à sua atividade inicial a partir do arquivo de manifesto. Então, agora, quando você executar o aplicativo, primeiro ele definirá o tema e, dessa forma, o usuário poderá ver a imagem inicial diretamente em vez da tela branca.


2

Ambas as propriedades funcionam

    <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

Por favor, tente uma vez.

1) Crie um arquivo drawable 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) Coloque isso em styles.xml

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

3) Em seu AndroidMainfest.xml, defina o tema acima para Lançar atividade.

       <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

Basta escrever o item em values ​​/ styles.xml:

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

Por exemplo, no 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

Para qualquer pessoa que tenha uma tela branca durante a depuração, esteja ciente de que, se estiver depurando, ela demorará mais para carregar. Se você criar seu APK de lançamento e instalá-lo em seu telefone, perceberá que leva muito menos tempo para carregar.

Portanto, o tempo de inicialização com a versão de depuração não é igual ao tempo de inicialização com a versão de lançamento.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.