Order feeds by number of unread items (descending)
This commit is contained in:
parent
406dab0a24
commit
6f5d23c557
|
@ -706,5 +706,10 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
|
|||
public int getNumberOfUnreadItems() {
|
||||
return (navDrawerData != null) ? navDrawerData.numUnreadItems : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfUnreadFeedItems(long feedId) {
|
||||
return (navDrawerData != null) ? navDrawerData.numUnreadFeedItems.get(feedId) : 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -511,6 +511,11 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
|
|||
return (navDrawerData != null) ? navDrawerData.numUnreadItems : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfUnreadFeedItems(long feedId) {
|
||||
return (navDrawerData != null) ? navDrawerData.numUnreadFeedItems.get(feedId) : 0;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private void loadData() {
|
||||
|
|
|
@ -27,7 +27,6 @@ import de.danoeh.antennapod.R;
|
|||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.fragment.AddFeedFragment;
|
||||
import de.danoeh.antennapod.fragment.AllEpisodesFragment;
|
||||
import de.danoeh.antennapod.fragment.DownloadsFragment;
|
||||
|
@ -266,12 +265,13 @@ public class NavListAdapter extends BaseAdapter
|
|||
|
||||
holder.title.setText(feed.getTitle());
|
||||
|
||||
int feedUnreadItems = DBReader.getNumberOfUnreadItems(context, feed.getId());
|
||||
|
||||
if(feed.hasLastUpdateFailed()) {
|
||||
holder.failure.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.failure.setVisibility(View.GONE);
|
||||
}
|
||||
int feedUnreadItems = itemAccess.getNumberOfUnreadFeedItems(feed.getId());
|
||||
if(feedUnreadItems > 0) {
|
||||
holder.count.setVisibility(View.VISIBLE);
|
||||
holder.count.setText(String.valueOf(feedUnreadItems));
|
||||
|
@ -301,6 +301,7 @@ public class NavListAdapter extends BaseAdapter
|
|||
int getSelectedItemIndex();
|
||||
int getQueueSize();
|
||||
int getNumberOfUnreadItems();
|
||||
int getNumberOfUnreadFeedItems(long feedId);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,9 +43,7 @@ import de.danoeh.antennapod.core.storage.DBTasks;
|
|||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.core.storage.DownloadRequester;
|
||||
import de.danoeh.antennapod.core.util.LongList;
|
||||
import de.danoeh.antennapod.core.util.QueueAccess;
|
||||
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
|
||||
import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
|
||||
|
||||
/**
|
||||
* Shows unread or recently published episodes
|
||||
|
@ -70,14 +68,13 @@ public class AllEpisodesFragment extends Fragment {
|
|||
private TextView txtvEmpty;
|
||||
private ProgressBar progLoading;
|
||||
|
||||
private List<FeedItem> unreadItems;
|
||||
private List<FeedItem> recentItems;
|
||||
private List<FeedItem> episodes;
|
||||
private LongList queueAccess;
|
||||
private List<Downloader> downloaderList;
|
||||
|
||||
private boolean itemsLoaded = false;
|
||||
private boolean viewsCreated = false;
|
||||
private boolean showOnlyNewEpisodes = false;
|
||||
private final boolean showOnlyNewEpisodes;
|
||||
|
||||
private AtomicReference<MainActivity> activity = new AtomicReference<MainActivity>();
|
||||
|
||||
|
@ -225,7 +222,7 @@ public class AllEpisodesFragment extends Fragment {
|
|||
if (itemsLoaded) {
|
||||
MenuItem menuItem = menu.findItem(R.id.mark_all_read_item);
|
||||
if (menuItem != null) {
|
||||
menuItem.setVisible(unreadItems != null && !unreadItems.isEmpty());
|
||||
menuItem.setVisible(episodes != null && !episodes.isEmpty());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -345,7 +342,7 @@ public class AllEpisodesFragment extends Fragment {
|
|||
@Override
|
||||
public int getCount() {
|
||||
if (itemsLoaded) {
|
||||
return (showOnlyNewEpisodes) ? unreadItems.size() : recentItems.size();
|
||||
return episodes.size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -353,7 +350,7 @@ public class AllEpisodesFragment extends Fragment {
|
|||
@Override
|
||||
public FeedItem getItem(int position) {
|
||||
if (itemsLoaded) {
|
||||
return (showOnlyNewEpisodes) ? unreadItems.get(position) : recentItems.get(position);
|
||||
return episodes.get(position);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -436,10 +433,17 @@ public class AllEpisodesFragment extends Fragment {
|
|||
protected Object[] doInBackground(Void... params) {
|
||||
Context context = activity.get();
|
||||
if (context != null) {
|
||||
return new Object[]{
|
||||
DBReader.getUnreadItemsList(context),
|
||||
DBReader.getRecentlyPublishedEpisodes(context, RECENT_EPISODES_LIMIT),
|
||||
DBReader.getQueueIDList(context)};
|
||||
if(showOnlyNewEpisodes) {
|
||||
return new Object[] {
|
||||
DBReader.getNewItemsList(context),
|
||||
DBReader.getQueueIDList(context)
|
||||
};
|
||||
} else {
|
||||
return new Object[]{
|
||||
DBReader.getRecentlyPublishedEpisodes(context, RECENT_EPISODES_LIMIT),
|
||||
DBReader.getQueueIDList(context)
|
||||
};
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
@ -452,9 +456,8 @@ public class AllEpisodesFragment extends Fragment {
|
|||
progLoading.setVisibility(View.GONE);
|
||||
|
||||
if (lists != null) {
|
||||
unreadItems = (List<FeedItem>) lists[0];
|
||||
recentItems = (List<FeedItem>) lists[1];
|
||||
queueAccess = (LongList) lists[2];
|
||||
episodes = (List<FeedItem>) lists[0];
|
||||
queueAccess = (LongList) lists[1];
|
||||
itemsLoaded = true;
|
||||
if (viewsCreated && activity.get() != null) {
|
||||
onFragmentLoaded();
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
package de.danoeh.antennapod.core.util;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
public class LongLongMapTest extends AndroidTestCase {
|
||||
|
||||
public void testEmptyMap() {
|
||||
LongIntMap map = new LongIntMap();
|
||||
assertEquals(0, map.size());
|
||||
assertEquals("LongLongMap{}", map.toString());
|
||||
assertEquals(0, map.get(42));
|
||||
assertEquals(-1, map.get(42, -1));
|
||||
assertEquals(false, map.delete(42));
|
||||
assertEquals(-1, map.indexOfKey(42));
|
||||
assertEquals(-1, map.indexOfValue(42));
|
||||
assertEquals(1, map.hashCode());
|
||||
}
|
||||
|
||||
public void testSingleElement() {
|
||||
LongIntMap map = new LongIntMap();
|
||||
map.put(17, 42);
|
||||
assertEquals(1, map.size());
|
||||
assertEquals("LongLongMap{17=42}", map.toString());
|
||||
assertEquals(42, map.get(17));
|
||||
assertEquals(42, map.get(17, -1));
|
||||
assertEquals(0, map.indexOfKey(17));
|
||||
assertEquals(0, map.indexOfValue(42));
|
||||
assertEquals(true, map.delete(17));
|
||||
}
|
||||
|
||||
public void testAddAndDelete() {
|
||||
LongIntMap map = new LongIntMap();
|
||||
for(int i=0; i < 100; i++) {
|
||||
map.put(i * 17, i * 42);
|
||||
}
|
||||
assertEquals(100, map.size());
|
||||
assertEquals(0, map.get(0));
|
||||
assertEquals(42, map.get(17));
|
||||
assertEquals(42, map.get(17, -1));
|
||||
assertEquals(1, map.indexOfKey(17));
|
||||
assertEquals(1, map.indexOfValue(42));
|
||||
for(int i=0; i < 100; i++) {
|
||||
assertEquals(true, map.delete(i * 17));
|
||||
}
|
||||
}
|
||||
|
||||
public void testOverwrite() {
|
||||
LongIntMap map = new LongIntMap();
|
||||
map.put(17, 42);
|
||||
assertEquals(1, map.size());
|
||||
assertEquals("LongLongMap{17=42}", map.toString());
|
||||
assertEquals(42, map.get(17));
|
||||
map.put(17, 23);
|
||||
assertEquals(1, map.size());
|
||||
assertEquals("LongLongMap{17=23}", map.toString());
|
||||
assertEquals(23, map.get(17));
|
||||
}
|
||||
|
||||
}
|
|
@ -8,6 +8,7 @@ import org.apache.commons.lang3.StringUtils;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -23,6 +24,7 @@ import de.danoeh.antennapod.core.feed.SimpleChapter;
|
|||
import de.danoeh.antennapod.core.feed.VorbisCommentChapter;
|
||||
import de.danoeh.antennapod.core.service.download.DownloadStatus;
|
||||
import de.danoeh.antennapod.core.util.DownloadError;
|
||||
import de.danoeh.antennapod.core.util.LongIntMap;
|
||||
import de.danoeh.antennapod.core.util.LongList;
|
||||
import de.danoeh.antennapod.core.util.comparator.DownloadStatusComparator;
|
||||
import de.danoeh.antennapod.core.util.comparator.FeedItemPubdateComparator;
|
||||
|
@ -489,6 +491,29 @@ public final class DBReader {
|
|||
return items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a list of FeedItems that are considered new.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @return A list of FeedItems that are considered new.
|
||||
*/
|
||||
public static List<FeedItem> getNewItemsList(Context context) {
|
||||
Log.d(TAG, "getNewItemsList()");
|
||||
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
|
||||
Cursor itemlistCursor = adapter.getNewItemsCursor();
|
||||
List<FeedItem> items = extractItemlistFromCursor(adapter, itemlistCursor);
|
||||
itemlistCursor.close();
|
||||
|
||||
loadFeedDataOfFeedItemlist(context, items);
|
||||
|
||||
adapter.close();
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the IDs of the FeedItems whose 'read'-attribute is set to false.
|
||||
*
|
||||
|
@ -966,15 +991,15 @@ public final class DBReader {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the number of unread items.
|
||||
* Returns a map containing the number of unread items per feed
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @return The number of unread items.
|
||||
* @return The number of unread items per feed.
|
||||
*/
|
||||
public static int getNumberOfUnreadItems(final Context context, long feedId) {
|
||||
public static LongIntMap getNumberOfUnreadFeedItems(final Context context, long... feedIds) {
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
final int result = adapter.getNumberOfUnreadItems(feedId);
|
||||
final LongIntMap result = adapter.getNumberOfUnreadFeedItems(feedIds);
|
||||
adapter.close();
|
||||
return result;
|
||||
}
|
||||
|
@ -1103,9 +1128,31 @@ public final class DBReader {
|
|||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
List<Feed> feeds = getFeedList(adapter);
|
||||
long[] feedIds = new long[feeds.size()];
|
||||
for(int i=0; i < feeds.size(); i++) {
|
||||
feedIds[i] = feeds.get(i).getId();
|
||||
}
|
||||
final LongIntMap numUnreadFeedItems = adapter.getNumberOfUnreadFeedItems(feedIds);
|
||||
Collections.sort(feeds, new Comparator<Feed>() {
|
||||
@Override
|
||||
public int compare(Feed lhs, Feed rhs) {
|
||||
long numUnreadLhs = numUnreadFeedItems.get(lhs.getId());
|
||||
Log.d(TAG, "feed with id " + lhs.getId() + " has " + numUnreadLhs + " unread items");
|
||||
long numUnreadRhs = numUnreadFeedItems.get(rhs.getId());
|
||||
Log.d(TAG, "feed with id " + rhs.getId() + " has " + numUnreadRhs + " unread items");
|
||||
if(numUnreadLhs > numUnreadRhs) {
|
||||
// reverse natural order: podcast with most unplayed episodes first
|
||||
return -1;
|
||||
} else if(numUnreadLhs == numUnreadRhs) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
int queueSize = adapter.getQueueSize();
|
||||
int numUnreadItems = adapter.getNumberOfUnreadItems();
|
||||
NavDrawerData result = new NavDrawerData(feeds, queueSize, numUnreadItems);
|
||||
NavDrawerData result = new NavDrawerData(feeds, queueSize, numUnreadItems, numUnreadFeedItems);
|
||||
adapter.close();
|
||||
return result;
|
||||
}
|
||||
|
@ -1114,11 +1161,14 @@ public final class DBReader {
|
|||
public List<Feed> feeds;
|
||||
public int queueSize;
|
||||
public int numUnreadItems;
|
||||
public LongIntMap numUnreadFeedItems;
|
||||
|
||||
public NavDrawerData(List<Feed> feeds, int queueSize, int numUnreadItems) {
|
||||
public NavDrawerData(List<Feed> feeds, int queueSize, int numUnreadItems,
|
||||
LongIntMap numUnreadFeedItems) {
|
||||
this.feeds = feeds;
|
||||
this.queueSize = queueSize;
|
||||
this.numUnreadItems = numUnreadItems;
|
||||
this.numUnreadFeedItems = numUnreadFeedItems;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import de.danoeh.antennapod.core.feed.FeedItem;
|
|||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.feed.FeedPreferences;
|
||||
import de.danoeh.antennapod.core.service.download.DownloadStatus;
|
||||
import de.danoeh.antennapod.core.util.LongIntMap;
|
||||
import de.danoeh.antennapod.core.util.flattr.FlattrStatus;
|
||||
|
||||
;
|
||||
|
@ -181,8 +182,8 @@ public class PodDBAdapter {
|
|||
+ KEY_PASSWORD + " TEXT,"
|
||||
+ KEY_IS_PAGED + " INTEGER DEFAULT 0,"
|
||||
+ KEY_NEXT_PAGE_LINK + " TEXT,"
|
||||
+ KEY_HIDE + " TEXT)";
|
||||
|
||||
+ KEY_HIDE + " TEXT,"
|
||||
+ KEY_LAST_UPDATE_FAILED + " INTEGER DEFAULT 0)";
|
||||
|
||||
public static final String CREATE_TABLE_FEED_ITEMS = "CREATE TABLE "
|
||||
+ TABLE_NAME_FEED_ITEMS + " (" + TABLE_PRIMARY_KEY + KEY_TITLE
|
||||
|
@ -207,7 +208,8 @@ public class PodDBAdapter {
|
|||
+ " INTEGER," + KEY_SIZE + " INTEGER," + KEY_MIME_TYPE + " TEXT,"
|
||||
+ KEY_PLAYBACK_COMPLETION_DATE + " INTEGER,"
|
||||
+ KEY_FEEDITEM + " INTEGER,"
|
||||
+ KEY_PLAYED_DURATION + " INTEGER)";
|
||||
+ KEY_PLAYED_DURATION + " INTEGER,"
|
||||
+ KEY_AUTO_DOWNLOAD + " INTEGER)";
|
||||
|
||||
public static final String CREATE_TABLE_DOWNLOAD_LOG = "CREATE TABLE "
|
||||
+ TABLE_NAME_DOWNLOAD_LOG + " (" + TABLE_PRIMARY_KEY + KEY_FEEDFILE
|
||||
|
@ -1065,7 +1067,27 @@ public class PodDBAdapter {
|
|||
Cursor c = db.query(TABLE_NAME_FEED_ITEMS, new String[]{KEY_ID},
|
||||
KEY_READ + "=0", null, null, null, KEY_PUBDATE + " DESC");
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a cursor which contains all feed items that are considered new.
|
||||
* The returned cursor uses the FEEDITEM_SEL_FI_SMALL selection.
|
||||
*/
|
||||
public final Cursor getNewItemsCursor() {
|
||||
final String query = "SELECT " + SEL_FI_SMALL_STR + " FROM " + TABLE_NAME_FEED_ITEMS
|
||||
+ " INNER JOIN " + TABLE_NAME_FEED_MEDIA + " ON "
|
||||
+ TABLE_NAME_FEED_ITEMS + "." + KEY_ID + "="
|
||||
+ TABLE_NAME_FEED_MEDIA + "." + KEY_FEEDITEM
|
||||
+ " LEFT OUTER JOIN " + TABLE_NAME_QUEUE + " ON "
|
||||
+ TABLE_NAME_FEED_ITEMS + "." + KEY_ID + "="
|
||||
+ TABLE_NAME_QUEUE + "." + KEY_FEEDITEM
|
||||
+ " WHERE "
|
||||
+ TABLE_NAME_FEED_ITEMS + "." + KEY_READ + " = 0 AND " // unplayed
|
||||
+ TABLE_NAME_FEED_MEDIA + "." + KEY_DOWNLOADED + " = 0 AND " // undownloaded
|
||||
+ TABLE_NAME_FEED_MEDIA + "." + KEY_POSITION + " = 0 AND " // not partially played
|
||||
+ TABLE_NAME_QUEUE + "." + KEY_ID + " IS NULL"; // not in queue
|
||||
Cursor c = db.rawQuery(query, null);
|
||||
return c;
|
||||
}
|
||||
|
||||
public final Cursor getRecentlyPublishedItemsCursor(int limit) {
|
||||
|
@ -1223,13 +1245,20 @@ public class PodDBAdapter {
|
|||
return result;
|
||||
}
|
||||
|
||||
public final int getNumberOfUnreadItems(long feedId) {
|
||||
final String query = "SELECT COUNT(DISTINCT " + KEY_ID + ") AS count FROM " + TABLE_NAME_FEED_ITEMS +
|
||||
" WHERE " + KEY_FEED + " = " + feedId + " AND " + KEY_READ + " = 0";
|
||||
public final LongIntMap getNumberOfUnreadFeedItems(long... feedIds) {
|
||||
final String query = "SELECT " + KEY_FEED + ", COUNT(" + KEY_ID + ") AS count "
|
||||
+ " FROM " + TABLE_NAME_FEED_ITEMS
|
||||
+ " WHERE " + KEY_FEED + " IN (" + StringUtils.join(feedIds, ',') + ") "
|
||||
+ " AND " + KEY_READ + " = 0"
|
||||
+ " GROUP BY " + KEY_FEED;
|
||||
Cursor c = db.rawQuery(query, null);
|
||||
int result = 0;
|
||||
LongIntMap result = new LongIntMap(c.getCount());
|
||||
if (c.moveToFirst()) {
|
||||
result = c.getInt(0);
|
||||
do {
|
||||
long feedId = c.getLong(0);
|
||||
int count = c.getInt(1);
|
||||
result.put(feedId, count);
|
||||
} while(c.moveToNext());
|
||||
}
|
||||
c.close();
|
||||
return result;
|
||||
|
|
|
@ -0,0 +1,252 @@
|
|||
package de.danoeh.antennapod.core.util;
|
||||
|
||||
|
||||
/**
|
||||
* Fast and memory efficient long to long map
|
||||
*/
|
||||
public class LongIntMap {
|
||||
|
||||
private long[] keys;
|
||||
private int[] values;
|
||||
private int size;
|
||||
|
||||
/**
|
||||
* Creates a new LongLongMap containing no mappings.
|
||||
*/
|
||||
public LongIntMap() {
|
||||
this(10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new SparseLongArray containing no mappings that will not
|
||||
* require any additional memory allocation to store the specified
|
||||
* number of mappings. If you supply an initial capacity of 0, the
|
||||
* sparse array will be initialized with a light-weight representation
|
||||
* not requiring any additional array allocations.
|
||||
*/
|
||||
public LongIntMap(int initialCapacity) {
|
||||
if(initialCapacity < 0) {
|
||||
throw new IllegalArgumentException("initial capacity must be 0 or higher");
|
||||
}
|
||||
keys = new long[initialCapacity];
|
||||
values = new int[initialCapacity];
|
||||
size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases size of array if needed
|
||||
*/
|
||||
private void growIfNeeded() {
|
||||
if (size == keys.length) {
|
||||
// Resize.
|
||||
long[] newKeysArray = new long[size * 3 / 2 + 10];
|
||||
int[] newValuesArray = new int[size * 3 / 2 + 10];
|
||||
System.arraycopy(keys, 0, newKeysArray, 0, size);
|
||||
System.arraycopy(values, 0, newValuesArray, 0, size);
|
||||
keys = newKeysArray;
|
||||
values = newValuesArray;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the long mapped from the specified key, or <code>0</code>
|
||||
* if no such mapping has been made.
|
||||
*/
|
||||
public int get(long key) {
|
||||
return get(key, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the long mapped from the specified key, or the specified value
|
||||
* if no such mapping has been made.
|
||||
*/
|
||||
public int get(long key, int valueIfKeyNotFound) {
|
||||
int index = indexOfKey(key);
|
||||
if(index >= 0) {
|
||||
return values[index];
|
||||
} else {
|
||||
return valueIfKeyNotFound;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the mapping from the specified key, if there was any.
|
||||
*/
|
||||
public boolean delete(long key) {
|
||||
int index = indexOfKey(key);
|
||||
|
||||
if (index >= 0) {
|
||||
removeAt(index);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the mapping at the given index.
|
||||
*/
|
||||
public void removeAt(int index) {
|
||||
System.arraycopy(keys, index + 1, keys, index, size - (index + 1));
|
||||
System.arraycopy(values, index + 1, values, index, size - (index + 1));
|
||||
size--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a mapping from the specified key to the specified value,
|
||||
* replacing the previous mapping from the specified key if there
|
||||
* was one.
|
||||
*/
|
||||
public void put(long key, int value) {
|
||||
int index = indexOfKey(key);
|
||||
|
||||
if (index >= 0) {
|
||||
values[index] = value;
|
||||
} else {
|
||||
growIfNeeded();
|
||||
keys[size] = key;
|
||||
values[size] = value;
|
||||
size++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of key-value mappings that this SparseIntArray
|
||||
* currently stores.
|
||||
*/
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an index in the range <code>0...size()-1</code>, returns
|
||||
* the key from the <code>index</code>th key-value mapping that this
|
||||
* SparseLongArray stores.
|
||||
*
|
||||
* <p>The keys corresponding to indices in ascending order are guaranteed to
|
||||
* be in ascending order, e.g., <code>keyAt(0)</code> will return the
|
||||
* smallest key and <code>keyAt(size()-1)</code> will return the largest
|
||||
* key.</p>
|
||||
*/
|
||||
public long keyAt(int index) {
|
||||
if (index >= size) {
|
||||
throw new IndexOutOfBoundsException("n >= size()");
|
||||
} else if(index < 0) {
|
||||
throw new IndexOutOfBoundsException("n < 0");
|
||||
}
|
||||
return keys[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an index in the range <code>0...size()-1</code>, returns
|
||||
* the value from the <code>index</code>th key-value mapping that this
|
||||
* SparseLongArray stores.
|
||||
*
|
||||
* <p>The values corresponding to indices in ascending order are guaranteed
|
||||
* to be associated with keys in ascending order, e.g.,
|
||||
* <code>valueAt(0)</code> will return the value associated with the
|
||||
* smallest key and <code>valueAt(size()-1)</code> will return the value
|
||||
* associated with the largest key.</p>
|
||||
*/
|
||||
public int valueAt(int index) {
|
||||
if (index >= size) {
|
||||
throw new IndexOutOfBoundsException("n >= size()");
|
||||
} else if(index < 0) {
|
||||
throw new IndexOutOfBoundsException("n < 0");
|
||||
}
|
||||
return values[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index for which {@link #keyAt} would return the
|
||||
* specified key, or a negative number if the specified
|
||||
* key is not mapped.
|
||||
*/
|
||||
public int indexOfKey(long key) {
|
||||
for(int i=0; i < size; i++) {
|
||||
if(keys[i] == key) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an index for which {@link #valueAt} would return the
|
||||
* specified key, or a negative number if no keys map to the
|
||||
* specified value.
|
||||
* Beware that this is a linear search, unlike lookups by key,
|
||||
* and that multiple keys can map to the same value and this will
|
||||
* find only one of them.
|
||||
*/
|
||||
public int indexOfValue(long value) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (values[i] == value) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all key-value mappings from this SparseIntArray.
|
||||
*/
|
||||
public void clear() {
|
||||
keys = new long[10];
|
||||
values = new int[10];
|
||||
size = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == this) {
|
||||
return true;
|
||||
}
|
||||
if (! (other instanceof LongIntMap)) {
|
||||
return false;
|
||||
}
|
||||
LongIntMap otherMap = (LongIntMap) other;
|
||||
if (size != otherMap.size) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (keys[i] != otherMap.keys[i] ||
|
||||
values[i] != otherMap.values[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashCode = 1;
|
||||
for (int i = 0; i < size; i++) {
|
||||
long value = values[i];
|
||||
hashCode = 31 * hashCode + (int)(value ^ (value >>> 32));
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (size() <= 0) {
|
||||
return "LongLongMap{}";
|
||||
}
|
||||
|
||||
StringBuilder buffer = new StringBuilder(size * 28);
|
||||
buffer.append("LongLongMap{");
|
||||
for (int i=0; i < size; i++) {
|
||||
if (i > 0) {
|
||||
buffer.append(", ");
|
||||
}
|
||||
long key = keyAt(i);
|
||||
buffer.append(key);
|
||||
buffer.append('=');
|
||||
long value = valueAt(i);
|
||||
buffer.append(value);
|
||||
}
|
||||
buffer.append('}');
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
|
@ -32,7 +32,6 @@ public final class LongList {
|
|||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
Arrays.hashCode(values);
|
||||
int hashCode = 1;
|
||||
for (int i = 0; i < size; i++) {
|
||||
long value = values[i];
|
||||
|
|
Loading…
Reference in New Issue