views:

84

answers:

3

Hi,

I have an Android app where I've extended the base Application class in order to set up some global variables.

public class MyApplication extends Application {

 private ArrayList<ModelClass> master_list; // global variable 1
 private DataBaseHelper db_helper; // global variable 2

 @Override
 public void onCreate() {
  super.onCreate();
  //do database work that will take about 5 seconds
 }
}

I'd like to show a splash screen to the user while the Application class is working (i.e. before my Main Activity is created). Is there a way to do this?

+3  A: 

You could make the SplashActivity your start activity.

When MyApplication has completed it's work you could start your main activity and dispose the splash screen.

But don't do the heavy database work in onCreate, create another function and do it there, otherwise your splash activity won't be shown.

public class SplashActivity extends Activity
    @override
    protected void onResume() {
    //Create a thread
    new Thread(new Runnable() {
            public void run() {
                //Do heavy work in background
                ((MyApplication)getApplication()).loadFromDb();
                startActivity(new Intent(SplashActivity.this, MainActivity.class));
                finish(); //End this activity
            }
        }).start();
    }
}
MatteKarla
I don't think this works. I want the sequence of events to be: 1) instantiate the MyApplication class...2) show a "splash screen/busy signal" while the onCreate() function of MyApplication runs...3) start the Main Activity. What you're suggesting is to call the "splash screen" _after_ the MyApplication class has finished its business, but then the splash screen shows up too late. Or maybe I'm not thinking about this properly?
Sorry, changed my answer while you wrote your comment. Don't know if you can start a activity from MyApplication, but my modified answer starts the splash screen, which starts MyApplication-work, and when it's done it starts the main activity and disposes the splash screen. So clicking back-button from main activity exits the application
MatteKarla
Thanks. I think this will work. Thanks again.
@MatteKarla: I am not sure if you can call `finish()` from a background thread. I'd recommend using an `AsyncTask`, with the `loadFromDb()` work in the `doInBackground()` method and the `startActivity()` and `finish()` in `onPostExecute()`. However, your general approach is sound...for the literal question the OP posed. Personally, I would like the OP to redesign the app such that the `loadFromDb()` can go on while the user is doing *something* with the app. Splash screens are annoying to users and are a crutch for developers, IMHO.
CommonsWare
@CommonsWare. Thanks as well. I never knew AsyncTask existed. As for my crutch...I'm not sure there's much I can do about it. I need the data (about 10,000 rows of database data) loaded into memory and available to all of the application's Activities (i.e., needs to be globally available) before the user can do anything....but maybe I'm not thinking hard enough about it.
@user141146: I'd try to figure out why that all needs to be in RAM. Stuff in singletons or `Application` need to be caches, not active data stores. Remember that your app can be killed off at any point, by the OS or by the user, without warning.
CommonsWare
Exactly what long-running things are you expecting your extended Application class to do that warrants a splash screen? The answer given here is the right one. Your extended Application's onCreate method should instantiate variables, but your splash screen should be used in the manner proposed to populate them with data. Additionally, if you think you need a global variable that holds 10,000 rows of data, you may want to re-think how your application is going to work.
Andrew
@CommonsWare: I tried it in the emulator, and it works there. But of course you are correct. It's more appropriate to do it using a `AsyncTask`, if it takes a lot of time before you're able to do anything then you could also use `onProgressUpdate()` to update a progressbar.
MatteKarla
A: 

First off, I think there are many approaches to having a splash screen. Intuitively, I would not have a special class/activity just to load specific information, because to keep that information, you will have to keep that activity alive and well somewhere- taking up resources.

I would have a splash screen just be a layout, that is initially loaded on with the main activity's onCreate(), and then once the DB information is loaded, change your layout to the main activities layout.

something like:

public void onCreate() {
    super.onCreate();
    setContentView(R.layout.splashscreen);
    //do database work that will take about 5 seconds
    setContentView(R.layout.mainscreen)
}
lheezy
The layout won't show until after onCreate and onResume has completed, so that's why I think you need to do it on a background thread and let the splash activity start on it's own.
MatteKarla
Hi. Thanks for the suggestion. I don't think it works though (at least not without some type of threading) because only the 2nd content-view will show up (the rendering of the layout will only take place once the onCreate function has completed and so the first time you call setContentView has no discernible effect).
A: 

The way I do this in my apps is by having your main activity extend ActivityGroup.

public class App extends ActivityGroup {
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.splashscreen);
        new Thread(new Runnable() {
            public void run() {
                // do your loading here
                final LocalActivityManager lam = getLocalActivityManager();
                runOnUiThread(new Runnable() {
                    public void run() {
                        Intent mainIntent = new Intent(MainActivity.class, App.this);
                        Window w = lam.startActivity("main", mainIntent);
                        setContentView(w.getDecorView());
                    }
                }
            }
        }, "App loading thread").start();
    }
}

This way, when the app resumes you immediately get the app, not the splash screen, and you only load your data once (when the app starts).

I actually use this to make sure the user is logged in when the app starts, and if the username/password combination is not right I don't start the main app, but a login screen :)

Thomas Vervest