0

Edit

After moving my loading / creation code to an Async Task (see below) - I still have the initial problems that I had with my original splashscreen.

Those being that:

1) On starting the Async task in onCreate, everything is loaded but my Dialog can only be shown when onStart() is called which makes the whole process kind of pointless as there is a long pause with a blank screen, then after everything has loaded, the 'loading' dialog flashes up for a split second before disappearing.

2) I can't move object loading / creation etc to onStart because a) it will be run again even when the app is resumed after being sent to the background which I don't want to happen, and b) when when calling restoring the savedInstanceState in onCreate() I'll get a nullPointerException because i'm restoring properties of objects that won't have yet been created.

Would really appreciate if someone could advise how to get around these problems and create a simple splashscreen. Thanks!

Background

My app uses only one activity and I would like to keep it that way if possible.

I've struggled with this for over a week so really hope someone can help me out.

All I want to do is use a splashscreen with a simple 'loading' message displayed on the screen while my resources load (and objects are created etc.) There are a couple of points:

Conditions

1) The splashscreen should not have it's own activity - everything needs to be contained in a single-activity

2) The splashscreen should not use an XML layout (I have created a Splashscreen class which uses View to display a loading PNG)

3) My app is openGL ES 2.0 so the textures need to be loaded on the OpenGL Thread (creation of objects etc that don't use GL calls are OK to go on another thread if necessary).

What I've attempted so far

What I did so far was to create a dialog and display it in my onStart() method with:

Dialog.show();

then let everything load in my onSurfaceCreated method before getting rid of it with:

Dialog.dismiss();

However I needed to change this for varioius reasons so now I create my objects from a call within my onCreate() method and just let the textures load in my GL Renderer's onSurfaceCreated method.

However, this means that because the dialogue isn't displayed until after onCreate, I still get a delay (blank screen) while everything is created before the splash-screen is shown, this then stays on the screen until the textures have loaded. There are other issues with this too which can wait for another day!

So my approach is obviouly very wrong. I read every tutorial I could and every splash-screen related question I could find on SO and Gamedev.SE but I still can't find an explanation (that makes sense to me), of how this can be achieved.

I'm hope someone here can explain.

Zippy
  • 3,826
  • 5
  • 43
  • 96

1 Answers1

0

You should be able to use AsyncTask to load resources in the background and then just dismiss your splash

Here's an AsyncTask that I use to load data from a remote db. This displays a loading progress circle until the task is complete but should be easily re-purposed to display your splash

AsyncTask that runs in the background

private class SyncList extends AsyncTask<Void, ULjException, Void> {

    private static final String TAG = "SyncList";

    private final class ViewHolder {
        LinearLayout progress;
        LinearLayout list;
    }

    private ViewHolder m;

    /**
     * Setup everything
     */
    protected void onPreExecute() {
        Log.d(TAG, "Preparing ASyncTask");
        m = new ViewHolder();
        m.progress = (LinearLayout) findViewById(R.id.linlaHeaderProgress);
        m.list = (LinearLayout) findViewById(R.id.listContainer);

        m.list.setVisibility(View.INVISIBLE); //Set the ListView that contains data invisible
        m.progress.setVisibility(View.VISIBLE); //Set the loading circle visible you can sub in Dialog.show() here
    }

    /**
     * Async execution performs the loading
     */
    @Override
    protected Void doInBackground(Void... arg0) {
        try {
            Log.d(TAG, "Syncing list in background");
            dba.open(ListActivity.this);
            dba.sync();
        } catch (ULjException e) {
            publishProgress(e);
        }
        return null;
    }

    /**
     * Display exception toast on the UI thread
     */
    protected void onProgressUpdate(ULjException... values) {
        Log.e(TAG, values[0].getMessage());
        Toast.makeText(ListActivity.this, "Sync failed", Toast.LENGTH_LONG).show();
    }

    /**
     * Finish up
     */
    protected void onPostExecute(Void result) {
        Log.d(TAG, "ASyncTask completed, cleaning up and posting data");
        fillData();
        m.list.setVisibility(View.VISIBLE); //Show the list with data in it
        m.progress.setVisibility(View.INVISIBLE); //Hide the loading circle sub in Dialog.dismiss()
    }
}

Calling the Task

protected void onStart() {
    super.onStart();
    // Init the dba
    dba = DBAccessor.getInstance();
    new SyncList().execute();
}

It should be noted that the AsyncTask is an inner class of the Activity its related to here

Edit
onCreate Method

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_layout);

    Dialog.show();
    //This launches a new thread meaning execution will continue PAST this call
    //to onStart and your loading will be done concurrently
    //Make sure to not try to access anything that you're waiting to be loaded in onStart or onResume let your game start from onPostExectue
    new AsyncTask.execute();
}

doInBackground

protected Void doInBackground(Void... arg0) {
    Load all resources here
}

onPostExecute

protected void onPostExecute(Void result) {
    Dialog.dismiss();
    Call a method that starts your game logic using your newly loaded resources
}
jhorvat
  • 385
  • 3
  • 14
  • Thanks @jhorvat could you explain a bit more how this would help? I've implement a simple Async Task now but I still have a couple of issues. One is that I start the task in my onCreate() so it goes off and starts to create my objects, but the rest of the code carries on and I get a nullpointer because object creation hasn't yet finished. Also, can I show my dialogue here? My understanding is that if I do a Dialog.show() from onCreate it won't actually show until onStart(); - is this the case also when showing it from an Async Task or so I have this all wrong? Thanks for your help. – Zippy Jun 20 '13 at 16:38
  • You'd want to move any calls that depend on objects being initialized to the `onPostExecute` method. You can show the dialogue in `onPreExecute` and hide it in `onPostExecute` (`doInBackground` doesn't have UI thread access). The point of doing this in an AsyncTask is that your UI updates (showing/hiding the dialog) will not be blocked by resource loads because the loads will be executed on another thread. This should remove your blank screen issue. Also later on it gives you the option of showing a progress bar on the splash to indicate progress to your users if you want – jhorvat Jun 20 '13 at 17:09
  • If showing the dialog in `onPreExecute` doesn't work call show in your `onCreate` before you start the task but you should still `dismiss` it in `onPostExecute` as this method will always execute as soon as the AsyncTask's `doInBackground` is completed – jhorvat Jun 20 '13 at 17:24
  • OK so I've moved my object creations to the onPostExcecute method along with everything else that needs to be initialised. There are 2 things I still don't get - 1) doesn't this defeat the purposed of doing this in an Async Task? I mean my doInBackground method is empty. Are you saying that code in the onPostExcecute is still done in the background? Also I can't show my dialog until onStart, Dialog's don't appear until onStart because in onCreate the activity hasn't yet been started. So again, it only appears after my resources have loaded - thanks again, I really want to understand this! – Zippy Jun 20 '13 at 17:55
  • No you still want the loading of resources to be done in `doInBackground` but you want some way of not trying to us those resources until everything is loaded in my code above this is handled by the `fillData` method that takes my newly synced db and displays the data. As for the Dialog it will be shown because AsyncTask opens a new thread to run on meaning that your app will continue to `onStart` as your resources are loaded not after. It sounds like you may not know too much about threads so have a look at [this](http://en.wikipedia.org/wiki/Thread_(computing)) – jhorvat Jun 20 '13 at 18:14
  • Could you possibly show me the fillData() method? It doesn't seem to be in your post. I've actually got this working by moving my setContentView() to onPostExcecute(). There are 2 things that aren't working still - the most important being that when I try to restore game state in on Create, I get a nullpointer because I'm restoring the state of game objects that are still being created. So I need to tell the bundle to restore only when it's the loading is completed. Apart from that is seems OK. Thanks again, your suggestions so far have been helpful. – Zippy Jun 20 '13 at 19:38
  • `fillData` just fills a ListView with data that I'm reading from the db I just synced. You should be able to still `setContentView` in `onCreate` though. And as I said anything that relies on your resources being loaded should not be executed until `onPostExecute` which will only be called once your loading is done. In other words don't touch your Bundle if stuff inside relies on the resources your're loading in the AsyncTask. So save your Bundle to a private global and in `onPostExecute` call some method (located outside the AsyncTask in your Activitys namespace) that restores state – jhorvat Jun 20 '13 at 19:54
  • No it gives a nullPointerExeption if I setContentView in onCreate I'm guessing because something relies on something that has yet to be created. However, I've seen examples where people put it into onPostExcecute and it seems a safe option. At least I know it won't run until everything that is required is there. Regarding the Bundle - I've done what you said that it works great, so I have a few minor problems to iron out, but the bulk of it is done and working, I'll mark your answer as accepted and thank you for all your help! – Zippy Jun 20 '13 at 20:37