2016-12-18 4 views
2

Я обновляю набор внутри onResponse обратного вызова залпа как это:сделать Java установить THREADSAFE

@Override 
public void onResponse(String response) 
{ 
    if (!response.equals(Properties.PRODUCT_NOT_FOUND) || !response.equals(Properties.USER_NOT_FOUND)) 
    { 
     if (user.getFavoriteProducts().contains(product.getId())) 
     { 
      user.getFavoriteProducts().remove(product.getId()); 

     } else { 
      user.getFavoriteProducts().add(product.getId()); 
     } 

     mSharedPreferencesManager.insertUser(user); 
    } 
} 

Когда два ответа принимаются в то же время этот набор accesed одновременно. Я пытаюсь сделать этот набор поточно, но я не могу заставить его работать, это то, что я пытался до сих пор:

Используйте SynchronizedSet:

user.setFavoriteProducts(Collections.synchronizedSet(new HashSet<Long>())); 

Используйте CopyOnWriteArraySet:

user.setFavoriteProducts(new CopyOnWriteArraySet<Long>()); 

Синхронизировать код внутри обратного вызова:

private static final Object object = new Object(); 

@Override 
public void onResponse(String response) 
{ 
    synchronized (object) 
    { 
     if (!response.equals(Properties.PRODUCT_NOT_FOUND) || !response.equals(Properties.USER_NOT_FOUND)) 
     { 
      if (user.getFavoriteProducts().contains(product.getId())) 
      { 
       user.getFavoriteProducts().remove(product.getId()); 

      } else { 
       user.getFavoriteProducts().add(product.getId()); 
      } 

      mSharedPreferencesManager.insertUser(user); 
     } 
    } 
} 

Ни один из этих продуктов не работал, любая помощь была бы оценена!

EDIT: Не работает, что вставлен только один элемент.


EDIT 2: Я пробовал подход N0un и до сих пор только один элемент вставлен

Это код, который я использовал:

@Override 
public void onResponse(final String response) 
{ 
    Log.d(Properties.TAG, "[REST_CLIENT] Response received: " + response); 

    AsyncTask.execute(new Runnable() 
    { 
     @Override 
     public void run() 
     { 
      synchronized (RestClient.class) 
      { 
       if (!response.equals(Properties.PRODUCT_NOT_FOUND) || !response.equals(Properties.USER_NOT_FOUND)) 
       { 
        if (user.getFavoriteProducts().contains(product.getId())) 
        { 
         Log.d(Properties.TAG, "[REST_CLIENT] Removing product from favorites: " + product.getId()); 
         user.getFavoriteProducts().remove(product.getId()); 

        } else { 
         Log.d(Properties.TAG, "[REST_CLIENT] Adding product to favorites: " + product.getId()); 
         user.getFavoriteProducts().add(product.getId()); 
        } 

        Log.d(Properties.TAG, "[REST_CLIENT] Updating user"); 
        mSharedPreferencesManager.insertUser(user); 

        Log.d(Properties.TAG, "[REST_CLIENT] Set size: " + user.getFavoriteProducts().size()); 
       } 
      } 
     } 
    }); 
} 

Эти журналы I «получаю:

D/CUOKA: [REST_CLIENT] Response received: ACCEPTED 
D/CUOKA: [REST_CLIENT] Adding product to favorites: 3921 
D/CUOKA: [REST_CLIENT] Updating user 
D/CUOKA: [REST_CLIENT] Response received: ACCEPTED 
D/CUOKA: [REST_CLIENT] Set size: 1 
D/CUOKA: [REST_CLIENT] Adding product to favorites: 2361 
D/CUOKA: [REST_CLIENT] Updating user 
D/CUOKA: [REST_CLIENT] Set size: 1 

РЕДАКТИРОВАТЬ 3: это код для вставки пользователя в SharedPreferences:

public synchronized boolean insertUser(final User user) 
{ 
    mEditor = mSharedPreferences.edit(); 

    Gson gson = new Gson(); 
    String json = gson.toJson(user); 

    mEditor.putString(KEY_USER, json); 

    return mEditor.commit(); 
} 
+0

* но я не могу заставить его работать *? Что происходит? – GurV

+0

Просьба представить информацию о том, что не сработало. Как вы протестировали и какое неправильное поведение вы видите. – gba

+0

@GurwinderSingh Извините, я редактировал вопрос. В комплект входит только один из элементов. – cuoka

ответ

0

Ну, слушатели Volley вызываются в потоке пользовательского интерфейса, используя классическую Java Executor. Я думаю, что есть механизм, который отменяет некоторые вызовы слушателя, когда в потоке пользовательского интерфейса слишком много работы.

Попробуйте это:

@Override 
public void onResponse(String response) 
{ 
    AsyncTask.execute(new Runnable() { 

     @Override 
     public void run() 
     { 
      synchronized (MyClassName.class) { 
       if (!response.equals(Properties.PRODUCT_NOT_FOUND) 
         || !response.equals(Properties.USER_NOT_FOUND)) { 
        if (user.getFavoriteProducts().contains(product.getId())) { 
         user.getFavoriteProducts().remove(product.getId()); 

        } else { 
         user.getFavoriteProducts().add(product.getId()); 
        } 

        mSharedPreferencesManager.insertUser(user); 
       } 
      } 
     } 
    }); 
} 

Смотрите эти ответы тоже: here и here для более подробного объяснения.

Просто перемещайте эту обработку данных, которая выполняется внутри ваших слушателей, в фоновый поток/AsyncTask, чтобы освободить ваш поток пользовательского интерфейса и предотвратить блокировку.

EDIT: После некоторого обсуждения и проверки кода, я нашел (второй) проблемы: user извлекается до запроса и проблема безопасности потоков здесь. Данные user еще не были сохранены во время выполнения нового запроса. Таким образом, второй запрос работает на том же Set, что и первый, а не в новом обновленном Set. Таким образом, user должен быть найден в блоке synchronized, который я предложил, перед другими обработками.

+0

Попробуй, как только смогу! – cuoka

+0

Я пытаюсь разобраться в этом. Таким образом, ответы обрабатываются в потоке пользовательского интерфейса, но что происходит, когда два ответа принимаются одновременно? – cuoka

+0

@cuoka Когда вы используете свой 'synchronized', он является потокобезопасным. Это означает, что только один поток может обрабатывать блок команд в то время, поэтому никаких проблем в вашем примере с 'synchronized'. Но без него, если два потока одновременно выполнят ваш код, один из них может изменить список (например, «добавить»), в то время как другой читает («содержит»), и это может вызвать непредвиденные действия, такие как повреждение данных или отсутствуют некоторые процессы. Но почему ваш код не работает в потоке пользовательского интерфейса, я действительно не знаю. Я предполагаю, что есть какая-то блокировка, и некоторые задачи отменены для предотвращения задержки UI. – N0un

-1

Слушатели используют Main Thread (UI нити), так что, вероятно, какое-то блокировка происходит. Вы должны перенести обработку данных в фоновый поток или выполнить обработку async.

Что касается установки синхронизации, вы должны использовать ConcurentHashMap и просто обернуть вокруг, используя метод newSetFromMap() из Коллекций.