@Override public void run() { // We make a copy to avoid synchronization issues and needless locks ArrayList<ProviderConnection> providers; synchronized (mProviders) { providers = new ArrayList<>(mProviders); } // Then we query the providers for (ProviderConnection conn : providers) { try { IMusicProvider binder = conn.getBinder(); if (binder != null && binder.isSetup() && binder.isAuthenticated()) { List<Playlist> playlist = binder.getPlaylists(); ensurePlaylistsSongsCached(conn, playlist); // Cache all songs in batch int offset = 0; int limit = 100; boolean goForIt = true; while (goForIt) { try { List<Song> songs = binder.getSongs(offset, limit); if (songs == null || songs.size() == 0) { goForIt = false; } else { cacheSongs(conn, songs); if (songs.size() < limit) { goForIt = false; } offset += limit; } } catch (TransactionTooLargeException ignore) { limit -= 10; Log.w(TAG, "Got transaction size error, reducing limit to " + limit); } } cacheAlbums(conn, binder.getAlbums()); cacheArtists(conn, binder.getArtists()); } else if (conn.getBinder() != null) { Log.i( TAG, "Skipping a providers because it is not setup or authenticated" + " ==> binder=" + binder + " ; isSetup=" + binder.isSetup() + " ; isAuthenticated=" + binder.isAuthenticated()); } else { unregisterProvider(conn); } } catch (RemoteException e) { Log.e(TAG, "Unable to get data from " + conn.getProviderName(), e); unregisterProvider(conn); } } }