views:

1142

answers:

2

Hi everybody,
I'm developping an android application and trying to deal with threads without really knowing a lot about them... (Yeah bit stupid of me, I know) I'll try to explain it properly and quite quickly.

In the onCreate method of my activity, I'm calling an AlertDialog to make the user choose to either load data from the internet or directly access the application using the data previously stored in database.
For that, in the onCreate, I call my method to raise the AlertDialog, positive button should start the worker thread to download, and negative button should call intent to move to next activity. So far, I got this :

-by not calling wait() anywhere, my AlertDialog appears but the thread starts anyway

-by calling wait() at the first line of my thread, I have to declare it static to access it from the listeners of my AlertDialog and be able to notify() it or interrupt(), I receive the following error :

"object not locked by thread before wait()

worker = new Thread(new Runnable() {

        public void run() {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

[rest of my run method]

private void miseAJourDesDonnes() {
    confirmInscrip = new AlertDialog.Builder(this).setMessage(
            "Voulez-vous mettre à jour l'intégralité des données de l'application? (Connexion internet requise").setPositiveButton("Mettre à jour",
            okListener).setNegativeButton("Continuer sans", nonListener);
    confirmInscrip.create();
    confirmInscrip.show();
}

OnClickListener okListener = new OnClickListener() {
    public void onClick(DialogInterface dialog, int which) {
        dialog.cancel();
        Toast.makeText(AccueilSplash.this, "Mise à jour en cours", Toast.LENGTH_SHORT).show();
        worker.notify();
        return;
    }
};
OnClickListener nonListener = new OnClickListener() {
    public void onClick(DialogInterface dialog, int which) {
        dialog.cancel();
        Toast.makeText(AccueilSplash.this, "Accès direct à l'application", Toast.LENGTH_SHORT).show();
        worker.interrupt();
        Intent entre = new Intent(AccueilSplash.this, Androt.class);
        startActivity(entre);
    }
};

worker is my instance of Thread (the bbackground one) Am I just being dumb or Is there a subtility I havent grasped? thanks for any answer...

A: 

I'm new to using threads as well, but you could try reading this example to give you a good starting point. It's about progress dialogs, but it illustrates how to manage threads and start them up at the right time. The really useful code is collapsed under the 'see more about Progress Dialgos with a second Thread' section.

Going to your code, I think your mistake is in how you declare your thread. Try instead creating is as a class extending Thread. e.g.

private class Worker extends Thread{
    Handled mHandler;  //See the example linked above for how to use handlers
    int progress;
    //and whatever other variables it might need

    worker(Handled h){
        mHandler = h;
        //and any other initialisation you need
    }

    public void run(){
        //and all your code here
    }
}

Then nothing happens with this Thread until you instantiate it with the following, in your onClickListeners.

Worker worker = new Worker(handler)

Even after that it won't actually start until you call worker.start(). Define your handler along the lines of

final Handler handler = new Handler() {
    public void handleMessage(Message msg) {
        int progress = msg.getData().getInt("progress");
        loadingDialog.setProgress(progress);
        if (progress >= 100){
            dismissDialog(LOADING_DIALOG);
        }
    }
};

Hope that helps you get started! Do read the link above, as I imagine you'll want some kind of progress dialog as well when it's actually doing the loading from the website. Or perhaps it would be done in a background service, but I couldn't help you with that.

Steve H
I'm actually having a go at AsyncTask which is exactly what I need and is nicely implemented in Android, and if I don't find, I'll go back to your advice. thanks
Sephy
+3  A: 

Below is a quick explanation of how wait() and notify() works but might I suggest that you just don't create the worker thread unless the user clicks ok? You may still want to cancel the thread later if they want to stop the download but creating the thread before you even know if it going to be used doesn't seem like the best approach.

In order to call wait(), notify(), or notifyAll() on an object you must first own the monitor of the object you wish to call the method on, so in you case within the runnable this would be how you would need to do it:

Runnable runnable = new Runnable() {
    public void run() {
      // wait(); This call wouldn't work
      syncronized (this) {
        wait();  // This call will work
      }
    }
};

To notify that runnable you would also have to have the monitor

// runnable.notifyAll(); this call will not work
syncronized (runnable) {
    runnable.notifyAll(); // this call will work
}

For more information about threads and concurrency in Java I would suggest Java Concurrency in Practice


There may be some built in framework for background tasks in Android that I don't know about but using pure java the easiest approach to this seems like it would be something like this:

private Thread downloadThread;

OnClickListener okListener = new OnClickListener() {
    public void onClick(DialogInterface dialog, int which) {
        dialog.cancel();
        Runnable download = new Runnable() {
            public void run() {
                // Create your input streams and such
                boolean downloadComplete = false;
                while(!downloadComplete  && !Thread.currentThread().isInterruped()) {
                    // Do some downloading
                }
                if (!Thread.currentThread().isInterruped()) {
                    // Alert user of success.
                }
            }
        };
        downloadThread = new Thread(download);
        downloadThread.start();
    }
};
OnClickListener cancelListener = new OnClickListener() {
    public void onClick(DialogInterface dialog, int which) {
        downloadThread.interrupt();
    }
};
Yanamon
mm, I think if you create your new Thread in the oklistener, you can't interrupt it from the cancellistener... One excludes the other.Thanks for the explanation (I'll have a closer look in the evening, I need to do some work on threads), I finally got a workaround from the AsyncTask class of android:http://developer.android.com/intl/fr/reference/android/os/AsyncTask.html
Sephy
@Sephy: AsyncTask is the way to go for background tasks. It provides quite a nice api.
Casebash