views:

487

answers:

1

I am trying to display an indefinite ProgressDialog, while an AsyncTask binds to a RemoteService. The RemoteService builds a list of the users contacts when the service is first created. For a long list of contacts this may take 5~10 seconds.

The problem I am having, is that the ProgressDialog does not display until after the RemoteService has built it's list of contacts. I even tried putting a Thread.sleep in to give the ProgressDialog time to show up. With the sleep statement the ProgressDialog loads and starts spinning, but then locks up as soon as the RemoteService starts doing it's work.

If I just turn the AsyncTask into dummy code, and just let it sleep for a while, everything works fine. But when the task has to do actual work, it is like the UI just sits and waits.

Any ideas on what Im doing wrong ?

    @Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.d(IM,"Start Me UP!!");
    setContentView(R.layout.main);
    Log.d(IM, "Building List View for Contacts");
    restoreMe();
     if (myContacts==null){
         myContacts = new ArrayList<Contact>();
         this.contactAdapter = new ContactAdapter(this, 
                                                  R.layout.contactlist, 
                                                  myContacts);
         setListAdapter(this.contactAdapter);
         new BindAsync().execute();
     }
     else{
         this.contactAdapter = new ContactAdapter(this, 
                                                  R.layout.contactlist, 
                                                  myContacts);
         setListAdapter(this.contactAdapter);

     }
}

private class BindAsync extends AsyncTask<Void, Void, RemoteServiceConnection>{
    @Override
    protected void onPreExecute(){
        super.onPreExecute();
        Log.d(IM,"Showing Dialog");
        showDialog(DIALOG_CONTACTS);
    }
    @Override
    protected RemoteServiceConnection doInBackground(Void... v) {
        Log.d(IM,"Binding to service in BindAsync");
        try{
        Thread.sleep(2000);
        } catch (InterruptedException e){

        }

        RemoteServiceConnection myCon;
        myCon = new RemoteServiceConnection();
        Intent i = new Intent(imandroid.this,MyRemoteService.class);
       bindService(i, myCon, Context.BIND_AUTO_CREATE);
        startService(i);
        Log.d(IM,"Bound to remote service");
        return myCon;
    }
    @Override
    protected void onPostExecute(RemoteServiceConnection newConn){
        super.onPostExecute(newConn);
        Log.d(IM,"Storing remote connection");
        conn=newConn;
    }

};

EDIT: Added onCreateDialog

 protected Dialog onCreateDialog(int id){
    switch(id){
    case DIALOG_CONTACTS:
        ProgressDialog progDialog = new ProgressDialog(imandroid.this);
        progDialog.setMessage("Loading Contacts... Please Wait");
        progDialog.setCancelable(false);
        return progDialog;
    default:
        return super.onCreateDialog(id);
    }
}
A: 

Do NOT do a bindService() from doInBackground(). First, it is nearly instantaneous, so you do not need to have it in a background thread -- all you are doing is wasting CPU time and battery. Second, it needs to work with the Looper and message queue for your Context, and so putting it in a background thread is dangerous IMHO.

Also note that you are both binding to the service and starting the service. There are a few cases where that is appropriate, but normally you only need one or the other.

CommonsWare
Thats the thing, it's not instantaneous. I need the service to build and hold onto a list of the users contacts. So I have the service building the contacts in it's onCreate. Then after I am bound to it, I fetch the contacts from the service and display them.I didn't think there would be any concurrency issues since the AsyncTask exits after binding to the RemoteService. Maybe there is, and it's blocking the UI thread ?I bound and started the service because I plan on having multiple applications bind to the service. Is this not appropriate ?
tedwards
"So I have the service building the contacts in it's onCreate." Move *that* logic into an AsyncTask in the service, because `onCreate()` is called on the main application thread regardless of where you try binding to it.
CommonsWare
I tried something like that at as well, but I ran into the problem of having to wait for the contact producing thread to join before I could return the result for the call to consume them made by the RemoteServiceConnection.Sounds like I need to figure out how to pass a message back to the UI thread to let it know when the contacts are ready for consumption.Thanks for the help!By the way, I was considering buying your books. This sealed the deal (well that and payday when it comes around).
tedwards
"Sounds like I need to figure out how to pass a message back to the UI thread to let it know when the contacts are ready for consumption." -- Yes, that's the solution. You can either use a broadcast `Intent` or a callback/listener object to let the activity know of the work being done. Here is a sample project that demonstrates the former: http://github.com/commonsguy/cw-android/tree/master/Service/WeatherPlus/ And, if you buy them, enjoy the books!
CommonsWare