访问Sqlite数据库的AsyncTask导致崩溃

时间:2011-06-23 22:24:43

标签: android listview synchronization android-asynctask

我有一个ListView,我需要使用后台线程填充。列表需要在检索每个项目时更新。下面是我如何实现这个的一个非常简单的例子。

  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]);
         }
    }

在上面的例子中,'adapter'是MyAdapterClass类型的对象,其fillList()方法是启动线程的方法。在onPostExecute()中调用notifyDataSetChanged()是在数据到达时更新我的​​ListView。

问题是,我在“doStackground”中调用的“DownloadStuff()”中访问我的sqlite数据库,并且有多个线程访问数据库导致它崩溃。(如果我在这里注释掉所有数据库活动,然后它运行良好)。下面是我尝试解决这个问题的方法,但它仍然崩溃。有关如何将我的ListView更新作为数据的任何建议从后台线程检索?

 Semaphore semaphore = new Semaphore(1, true);

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

2 个答案:

答案 0 :(得分:1)

我认为你的方法从一开始就是错误的。为什么要为必须添加到适配器的每个项目启动单独的AsyncTask。使用onProgressUpdate通知gui适配器中新添加的项目。在这种情况下,您希望同时访问您的数据库。

答案 1 :(得分:0)

我不确定(因为我真的很累)但我认为你的使用正确地同步了。

每次执行异步任务时都会创建一个不同的MyUserObject实例,这意味着您从未在同一个实例上实际调用Downloadstuff,因此没有冲突,但另一方面,您的数据库是唯一的,由多个MyUserObject调用因此冲突。

你想要做的是在你的所有异步任务中都有相同的muo实例,这样他们都可以在同一个实例上调用downloadstuff,然后synchronized会阻止多次访问。

你也不需要这里的信号灯。


编辑:

Mojo Risin的答案也非常好,如果你可以通过将所有异步任务集中到一个你应该(你运行的并发线程越少越好)来节省自己的麻烦。