views:

162

answers:

3

Hi,

I am currently facing the following problem: whenever my Android application is started, it needs to execute some time consuming initialization code. Without this code all my activities/services within the application won't work correctly.

So far, I have put this initialization code into a SplashScreen activity, which I declared as MAIN activity in the manifest. Once the initialization code has been executed, I finish() the splash screen and start the actual main activity, i.e. an activity consisting of several tabs, from where the user can reach several other activities.

The problem is now the following: when my app is put in the background, after some time and after launching other apps, my app/process is killed. When I re-launch it from the homescreen, Android restores the activity stack (task) and invokes onCreate() on them. However, the splash screen activity and hence the initialization code aren't executed, which results in an exception.

I could put now the initialization code in the application's onCreate(), however this results in a black screen until the method finishes.

Does anybody have an idea, where and how I can properly initialize my app on startup?

Initialization code:

public void init() {
    if (initialized) {
        return;
    }

    // Initialize terms
    List<Tag> tags= DynamicDao.loadAll(Tag.class);
    int numTags = tags.size();
    terms = new String[numTags];
    for (int i = 0; i < numTags; i++) {
        terms[i] = tags.get(i).getTag();
    }

    // Initialize document-term matrix
    List<Item> items = DynamicDao.loadAll(Item.class);
    createDocumentTermMatrix(items);

    initialized = true;
}

Note: An Item has several associated tags, from which I need to create a document vector.

A: 

Just how expensive is your initialization? What do you do there? In general, I would recommend against using a splash screen (it's a mobile app, not a desktop application). Instead, use a worker thread to initialize your data while the main UI is being displayed, and then use handler to initialize the UI once your worker thread is done.

Alternatively, I would look into why your initialization is taking so long, and optimizing it. What are you doing there?

EboMike
During initialization, I create a matrix of doubles of size 50x70 in order to speed up certain calculations afterwards. This computation needs approximately 2-3 seconds on a Nexus One, 6 seconds for a HTC Magic and still a little bit longer on the emulator. The initialization algorithm can't be optimized anymore. Eventually (but I am not very convinced of this idea) I could write results of this computation in a file on first launch of the app and read and just update from there afterwards...
Matthias
Writing 3500 doubles should NOT take 3 seconds. Something seems wrong
Falmarri
Perhaps I need to give a few more details: this matrix is a word-document matrix, which I pre-compute using entries in the application's SQLite DB and which I use to compute similarities afterwards.
Matthias
Still sounds highly inefficient. Are you looking up the DB for each one of those doubles? Wanna post some code? Btw, in either case, sounds like my suggestion to use a worker thread would be perfect here. Be sure to give it a lower priority so the UI remains responsive.
EboMike
OK, I have now posted a code snippet. As you can see, I read a list of Tags and a list of Items from the DB, which I then use to built a document-term matrix (consisting of tag frequencies for each item) - hence I don't directly read the double values from the DB.
Matthias
Did you add timers? See how long each part of this code block takes. Measure the time it takes to do loadAll, the time for the for loop, and the time for createDocumentTermMatrix.
EboMike
loadAll() consumes only little time; approximately 90% of the computation are needed for createDocumentTermMatrix() which has complexity O(n^2). However, createDocumentTermMatrix() can't be improved anymore.
Matthias
Well, then there's little point in posting only the code that doesn't take up much time :) In any case, do you want us to help you optimize that function, or did this answer your question?
EboMike
Actually, I posted this snippet only such that you have a rough idea of what should be performed on application startup - optimization of this function is not part of this question :-) Regarding your answer, I am not 100% convinced of spawning a worker thread in my actual main activity - since from a design point of view this initialization code is needed for all activities and hence shouldn't be tied to just one activity.
Matthias
Your worker thread doesn't have to be tied to an activity. The thread is tied to your process, and as such persists across activities. You can create a separate class, derive it from Thread, and treat it like a singleton. Every activity creates it (if it doesn't already exist) and uses it to read the matrix.
EboMike
OK, that could work! Thanks for this suggestion. I'll accept this answer if I won't receive any better proposal...
Matthias
Better proposal? You're speaking treason :)
EboMike
A: 

If you really have to execute a long lasting operation then you should use AsyncTask. It's really simple to use, it provides you with two functions called onPreExecute and onPostExecute which are invoked in the main thread respectively before and after the operation. All the expensive stuff should go in doInBackground which will work in the worker thread.

While you are doing that operation you could show a progress dialog (creating it inside the above mentioned onPreExecute) showing the progress of what you are doing by using one of the callback provided: onProgressUpdate you will then dismiss the dialog in the above mentioned inside onPostExecute

lucabox
Don't know why I cannot comment on the other answer will comment here: If the matrix you are going to calculate is used by more than one activity instead of making that class a singleton you could easily subclass the Application ( http://developer.android.com/reference/android/app/Application.html )class (which will exist as long one of the Activities or Services of your application is running) where you could store your matrix which will be then accessible from any part of your program.
lucabox
Accessing the matrix from multiple activities is not the problem. The problem is where to compute this matrix. In a SplashScreenActivity, in a singleton thread class or in Application.onCreate(). Application.onCreate() is not an option, since the user sees a black screen until the computation is in progress - I don't see any possibility to customize this, e.g. by showing custom image. If I use a SplashScreenActivity, then I have the problem as described in the question.
Matthias
In fact my point (see main answer) is to use **AsyncTask** to don't block the main thread. A separate thread is needed in **any** case or the UI will be blocked and a AsyncTask is a nice and easy way to execute something in a different thread and get notified when the operation is over and updates on the progress too (hence the progress update callback I mentioned). I mentioned the Application class can be used *just* to store the result of the operation so that can be easily accessed by any activity/service present in the app.
lucabox
A: 

If you want to keep your current splash screen, you have a couple of options.

If your data structure isn't too colossal, you can store it in onSaveInstanceState and restore it in onRestoreInstanceState and/or onPostCreate.

If the data is too large, you may just need to check to see whether your app is initialized in onResume or one of the other variety of startup methods like onRestart, onStart, etc. (I'm still a little hazy on when exactly each should be used.) If not, start your splash screen Activity.

The advice from others on this topic is good, as well. But this may work for you if you need a quick fix.

BenTobin