Splash Screen for slow loading Android App

I try to add Splash Screen to my Cocos2dx Android app, which I ported from iOS.

Because:

  1. It takes so much time, before the App starts (around 17 seconds).
  2. It shows black screen during waiting.

I tried to add Splash Sreen Java way, but it displays image for a few seconds only and then switches back again to black screen for the rest of start up time.

I have this code there.

styles.xml

<resources>

<!-- Base application theme. -->
<!-- <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> -->
<!-- Customize your theme here. -->
<!-- </style> -->

    <style name="SplashTheme" parent="android:style/Theme"> <!-- Theme.AppCompat.NoActionBar @android:style/Theme.NoTitleBar.Fullscreen -->
        <item name="android:windowBackground">@drawable/background_splash</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowFullscreen">true</item>
        <item name="android:windowContentOverlay">@null</item>
    </style>

</resources>

SplashActivity.Java

package com.bignerdranch.android.splash;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

public class SplashActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Intent intent = new Intent(this, MainActivity.class);
        startActivity(intent);
        finish();
    }
}

drawable/background_splash.xml

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

    <item
        android:drawable="@color/gray"/>

    <item>
        <bitmap
            android:gravity="center"
            android:src="@mipmap/ic_launcher"/>
    </item>

</layer-list>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.de.test"
    android:installLocation="auto">

    <uses-feature android:glEsVersion="0x00020000" />
    <uses-sdk
        android:minSdkVersion="11"
        android:targetSdkVersion="19" />
    
    <application
        android:allowBackup="true"
        android:label="@string/app_name"
        android:icon="@drawable/icon">
        
        <!-- Tell Cocos2dxActivity the name of our .so -->
		<meta-data android:name="android.app.lib_name"
				   android:value="cocos2dcpp" />

        <!-- android:theme="@android:style/Theme.NoTitleBar.Fullscreen"  portrait -->
        <activity
            android:name="org.cocos2dx.cpp.AppActivity"
            android:launchMode="singleTop"
            android:screenOrientation="sensorPortrait"
            android:configChanges="orientation|keyboardHidden|screenSize"
            android:label="@string/app_name"
            android:theme="@style/SplashTheme">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    
</manifest>
  1. How to improve it, to show Splash Screen during whole Cocos2dx App loading (instead of black screen)?

  2. How to improve start up time?

I think there is an example in the cpptests where it shows how to load resource using async.
Have a look, maybe it will help you out.

I had the same problem. See my thread about it here. There’s no perfect solution but you can pick one which works for you.

1 Like

You can do it modifying your .java in src folder

this is my sample of appactivity, I use the Dialog

package your bundle id;

import your bundle;
import org.cocos2dx.lib.Cocos2dxActivity;

import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;

public class AppName extends Cocos2dxActivity {

  public static Dialog loader_dialog; 

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    loader_dialog = new Dialog(this,R.style.Loader);
    loader_dialog.setContentView(R.layout.loader);
    loader_dialog.show();
  }

  public static void dismissLoader() {
    loader_dialog.dismiss();
  }

}

in the android manifest xml:

   <activity
      android:name="your bundle id"
      android:label="@string/app_name"
      android:launchMode="singleTop" 
      android:screenOrientation="sensorPortrait"
      android:configChanges="orientation"
      android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>

and finally the most important the styles.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <style name="Loader" parent="android:Theme.Black.NoTitleBar.Fullscreen">
    <item name="android:windowAnimationStyle">@style/LoaderAnimation</item>
  </style>
  <style name="LoaderAnimation">
    <item name="android:windowEnterAnimation">@android:anim/fade_in</item>
    <item name="android:windowExitAnimation">@android:anim/fade_out</item>
  </style>
</resources>

I’ve also added a fade in / out

No black screen in this way :wink:

Thanks guys! I just improved the code to start in 4-5 seconds, started to use spread sheets for this app! But it still displays, with current code, as written at the top of this forum thread, not yet modified it: first logo for a second then it shows black screen for about 3 - 4 seconds until app starts.

I will try to test Levis and or others solution too now. Will report back.

1 Like

@nov with my solution I don’t have any glitch or black screen, last year I’ve worked to resolve this, maybe you can find also useful my first post on native splashscreen:

How R is defined, please?

I am getting:

/testproject/proj.android-studio/app/src/org/cocos2dx/cpp/AppActivity.java:38: error: package R does not exist
        loader_dialog = new Dialog(this,R.style.Loader);
                                         ^
/testproject/proj.android-studio/app/src/org/cocos2dx/cpp/AppActivity.java:39: error: package R does not exist
        loader_dialog.setContentView(R.layout.loader);

I am not yet very familiar with Android code, although I know Java, I am staring to get to used to Android.

R.java is autogenerated on build, these are the resources (drawable, layout, styles etc)

maybe I forgot to add in import line when I rewrote “your bundle”:
import com.bundle.appname.R;

Ok. Thanks. Seems to be a little better, but now getting this.

/testproject/proj.android-studio/app/src/org/cocos2dx/cpp/AppActivity.java:40: error: cannot find symbol
        loader_dialog.setContentView(R.layout.loader);
                                             ^
  symbol:   variable loader
  location: class layout
1 error

You’re right, sorry forgot to add this:

layout/loader.xml

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

Next time I’ll promise to create a repo with all files :stuck_out_tongue:

Ok. Thanks. It compiles!

But now it seems the logo stays there forever, not sure what I am not doing right?

You can call dismissLoader here, in your c++ code, for the logo don’t stay forever, you close it when you enter in your application :

void EcranChargement::onEnter()
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
#include “platform/android/jni/JniHelper.h”
#include < jni.h>
JniMethodInfo methodInfo;
if (JniHelper::getStaticMethodInfo(methodInfo, “org/cocos2dx/cpp/AppActivity”, “dismissLoader”, “()V”)) {
methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID);
methodInfo.env->DeleteLocalRef(methodInfo.classID);
}
#endif

Layer::onEnter();
scheduleOnce(CC_SCHEDULE_SELECTOR(EcranChargement::RunGameScreen), 1.0f);

}

Yes @versailles is right.

You can call dismissLoader everywhere you decide in your code with JNI helper.

In some apps I call after loading data and if you want you can also add a static delay if you need some more time or whatever else:

// Remove Splashscreen when all important data is loaded
void Start::dismissLoader() {
  CCLOG("[Start] dismissLoader");
#if(CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
  this->runAction(Sequence::create(
    DelayTime::create(1.0f),
    CallFunc::create([&]() {
      JniMethodInfo t;
      if (JniHelper::getStaticMethodInfo(t, "your activity", "dismissLoader", "()V")) {
        t.env->CallStaticVoidMethod(t.classID, t.methodID);
      }
    }),
    nullptr));
#endif
}

Thanks guys! It works perfectly!

Only issue I have now is that my screenshot is whole Android screen height size height.

But it gets cut because of bottom toolbar displayed there.

Is there anything to do with it, please?

loader.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:baselineAligned="false"
    android:measureWithLargestChild="false"
    android:background="@drawable/background_splash">

</LinearLayout>

background_splash.xml

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

    <item
        android:drawable="@color/white"/>

    <item>
        <bitmap
            android:gravity="center"
            android:src="@mipmap/screen"/>
    </item>

</layer-list>

Sorry I didn’t undertand, can u post a screenshot?

At the bottom of the screen is navigation bar. Which makes the splash screen image to not fit. Image is cut at the bottom and at the top.

Ok. I fixed it by setting full screen to loader dialog and cocos2dx view according to this article and this cocos2dx thread.

http://developer.sonymobile.com/knowledge-base/tutorials/legal/how-to-provide-your-app-users-with-maximum-screen-estate-tutorial/

public class AppActivity extends Cocos2dxActivity {
    
    public static Dialog loader_dialog;
    private Cocos2dxGLSurfaceView glSurfaceView;

    private int mSystemUiVisibility =  View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
            | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
            | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
            | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        loader_dialog = new Dialog(this,R.style.Loader);
        loader_dialog.setContentView(R.layout.loader);
        if (android.os.Build.VERSION.SDK_INT >= 11) {
            loader_dialog.getWindow().getDecorView().setSystemUiVisibility(mSystemUiVisibility);
        }
        loader_dialog.show();
    }
    
    public static void dismissLoader() {
        loader_dialog.dismiss();
    }


    public Cocos2dxGLSurfaceView onCreateView()
    {
        glSurfaceView = new Cocos2dxGLSurfaceView(this);

        this.hideSystemUI();

        // create stencil buffer
        glSurfaceView.setEGLConfigChooser(5, 6, 5, 0, 16, 8);

        return glSurfaceView;
    }

    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if (hasFocus)
        {
            this.hideSystemUI();
        }
    }

    private void hideSystemUI()
    {
        if (android.os.Build.VERSION.SDK_INT >= 11) {
            // Set the IMMERSIVE flag.
            // Set the content to appear under the system bars so that the content
            // doesn't resize when the system bars hide and show.
            glSurfaceView.setSystemUiVisibility(mSystemUiVisibility);
        }
    }

    static
    {
        System.loadLibrary("cocos2dcpp");
    }
}

Now I will have to find out how to compile release version of the app and how to upload it to the Google Play?

Nice!
In this way you setup the immersive mode, that is my preferred :wink:

For compiling you can use:
cocos run -p android -j 4 -s projFolder -m release

Cocos will generate the apk that you can upload to Google Play :wink:

Thanks. I try to use this command, since I use Android Studio:
cocos compile -p android --android-studio -m release --ndk-mode release

What -j 4 means in your command?

I try to minimize APK file size.
How to remove not needed files eg. iOS startup screens from APK generation?

-j, --jobs	number of jobs at once	4	Use N jobs at once. It's only take effect with target android & linux.

You don’t need to remove iOS stuff, they are in another dir.