lost_bits1110
lost_bits1110

Reputation: 157

AsyncTask that accesses Sqlite database causes crash

I have a ListView which I need to populate using a background thread. The list needs to update as each item is retrieved. Below is a very simplified example of how I implement this.

  public class DownloadTask extends AsyncTask <MyUserObject, Integer, String>
  {
    @Override
    protected MyUserObject doInBackground(MyUserObject... myUserObj) 
    {
        MyUserObject muo = null;
        int nCount = myUserObj.length;
        if( nCount > 0 )
            muo = myUserObj[0];

        muo.DownloadStuff();
        return muo.getUserName();
    }

    protected void onPostExecute(String userName)
    {
        adapter.names.add(userName);
        adapter.notifyDataSetChanged();
    }
}

public class MyAdapterClass extends BaseAdapter 
{
    private ArrayList<String>names;

    public MyAdapterClass(Context context)
    {
        names = new ArrayList<String>();
    }

    public fillList()
    {
         for( int i=0; i<users.length; i++ )
         {
             DownloadTask task = new DownloadTask();
             task.execute(users[i]);
         }
    }

In the above example, 'adapter' is an object of type MyAdapterClass, and its fillList() method is what launches the threads. Calling notifyDataSetChanged() in onPostExecute() is what updates my ListView as data arrives.

The problem is, that I am accessing my sqlite database in "DownloadStuff()' which is called in 'doInBackground', and having multiple threads accessing the DB causes it to crash. (If I comment out all DB activities in here, then it runs fine). Below is how I try to workaround this problem, however it still crashes. Any advice on how I can have my ListView update as data is retrieved from a background thread?

 Semaphore semaphore = new Semaphore(1, true);

 public synchronized void DownloadStuff()
 {
     semaphore.acquire(1);
     // ... DB operations ... //
     semaphore.release(1);
 }

Upvotes: 0

Views: 1292

Answers (2)

Jason Rogers
Jason Rogers

Reputation: 19344

I'm not sure (because I'm really tired) but I think your ot using you synchronysed correctly.

you create a different instance of MyUserObject each time you do a async task, this means you never actually call Downloadstuff on the same instance hence no conflict, but on the other hand your database is unique being called by multiple MyUserObject hence conflict.

what you want to do is have the same instance of muo in all your async task, this way they all call downloadstuff on the same instance and then synchronized will work preventing multiple access.

you also don't need the semaphoe here.


edit:

Mojo Risin answer is also very good, if you can save yourself the trouble by centralizing all you async tasks into one you should(less concurrent threads running around you have the better)

Upvotes: 0

Mojo Risin
Mojo Risin

Reputation: 8142

I think your approach is wrong from it's beginning. Why do you want to start separate AsyncTask for each item you have to add to your adapter. Use onProgressUpdate to notify the gui for newly added items in the adapter. In this case you want have concurrent access to your db.

Upvotes: 1

Related Questions