AsyncTask, который обращается к базе данных Sqlite, вызывает сбой - PullRequest
0 голосов
/ 24 июня 2011

У меня есть 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]);
         }
    }

В приведенном выше примере «адаптер» - это объект типа MyAdapterClass, а его метод fillList () - это то, что запускает потоки. Вызов notifyDataSetChanged () в onPostExecute () - это то, что обновляет мой ListView по мере поступления данных.

Проблема в том, что я обращаюсь к своей базе данных sqlite в «DownloadStuff ()», которая вызывается в «doInBackground», и наличие нескольких потоков, обращающихся к БД, приводит к ее аварийному завершению (если я закомментирую все действия БД здесь , затем он работает нормально. Ниже описывается, как я пытаюсь обойти эту проблему, однако она все еще дает сбой. Любой совет, как можно получить обновление ListView при получении данных из фонового потока?

 Semaphore semaphore = new Semaphore(1, true);

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

Ответы [ 2 ]

1 голос
/ 24 июня 2011

Я думаю, что ваш подход неверен с самого начала.Почему вы хотите начать отдельную AsyncTask для каждого элемента, который вы должны добавить в свой адаптер.Используйте onProgressUpdate , чтобы уведомить графический интерфейс о новых добавленных элементах в адаптере.В этом случае вы хотите иметь параллельный доступ к вашей базе данных.

0 голосов
/ 24 июня 2011

Я не уверен (потому что я очень устал), но я думаю, что вы не используете вас правильно синхронизированы.

вы создаете новый экземпляр MyUserObject каждый раз, когда выполняете асинхронную задачу, это означает, что вы на самом деле никогда не вызываете Downloadstuff для одного и того же экземпляра, следовательно, нет конфликта, но, с другой стороны, ваша база данных уникальна, так как вызывается несколькими объектами MyUserObject и, следовательно, конфликтует.

что вы хотите сделать, это иметь один и тот же экземпляр muo во всех ваших асинхронных задачах, так что все они вызывают downloadstuff для одного и того же экземпляра и затем синхронизируются, что предотвращает множественный доступ.

вам также не нужно семафо здесь.


редактировать:

Ответ Mojo Risin также очень хорош, если вы можете избавить себя от проблем, объединив все свои асинхронные задачи в одну, какую вы должны (чем меньше параллельных потоков, работающих вокруг, тем лучше)

...