So my problem is that when i try to sort the albums, the album title and album art are wrong.
I tried sorting the album ids but that doesn't fix it because album id have nothing to do with sorting the art apparently.
When i leave out the sorting everything is correct, but when i try to sort them the album names don't match the album art.
How can i sort my albums in the fragment?
Beneath here you can find my code.
Thanks in advance,
Vince
SONG MODEL
// Columns I'll retrieve from the song table
String[] columns = {
SONG_ID,
SONG_TITLE,
SONG_ARTIST,
SONG_ALBUM,
SONG_ALBUMID,
SONG_FILEPATH,
};
// Limits results to only show music files.
//
// It's a SQL "WHERE" clause - it becomes `WHERE IS_MUSIC=1`.
//
final String musicsOnly = MediaStore.Audio.Media.IS_MUSIC + "=1";
// Querying the system
cursor = resolver.query(musicUri, columns, musicsOnly, null, null);
if (cursor != null && cursor.moveToFirst())
{
do {
// Creating a song from the values on the row
Song song = new Song(cursor.getInt(cursor.getColumnIndex(SONG_ID)),
cursor.getString(cursor.getColumnIndex(SONG_FILEPATH)));
song.setTitle (cursor.getString(cursor.getColumnIndex(SONG_TITLE)));
song.setArtist (cursor.getString(cursor.getColumnIndex(SONG_ARTIST)));
song.setAlbumID (cursor.getInt(cursor.getColumnIndexOrThrow(SONG_ALBUMID)));
song.setAlbum (cursor.getString(cursor.getColumnIndexOrThrow(SONG_ALBUM)));
// Using the previously created genre and album maps
// to fill the current song genre.
String currentGenreID = songIdToGenreIdMap.get(Long.toString(song.getId()));
String currentGenreName = genreIdToGenreNameMap.get(currentGenreID);
song.setGenre(currentGenreName);
// Adding the song to the global list
songs.add(song);
}
while (cursor.moveToNext());
}
else
{
// What do I do if I can't find any songs?
}
cursor.close();
public ArrayList<String> getArtists() {
ArrayList<String> artists = new ArrayList<String>();
for (Song song : songs) {
String artist = song.getArtist();
if ((artist != null) && (! artists.contains(artist)))
artists.add(artist);
}
// Making them alphabetically sorted
Collections.sort(artists, new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
return artists;
}
/**
* Returns an alphabetically sorted list with all the
* albums of the scanned songs.
*
* #note This method might take a while depending on how
* many songs you have.
*/
public ArrayList<String> getAlbums() {
ArrayList<String> albums = new ArrayList<String>();
for (Song song : songs) {
String album = song.getAlbum();
if ((album != null) && (! albums.contains(album)))
albums.add(album);
}
SONG CLASS
public class Song implements Serializable {
private long id;
private String data;
private String title = "";
private String artist = "";
private int albumid = -1;
private String album = "";
private String genre = "";
public Song(long songId, String songData){
this.id = songId;
this.data = songData;
}
public long getId(){
return id;
}
public String getData(){return data;}
//Optional meta data
public void setTitle(String title){
this.title = title;
}
public String getTitle() {
return title;
}
public void setArtist(String artist){
this.artist = artist;
}
public String getArtist() {
return artist;
}
public int getAlbumID() {
return albumid;
}
public void setAlbumID(int albumid) { this.albumid = albumid; }
public void setAlbum(String album){
this.album = album;
}
public String getAlbum() { return album; }
public void setGenre(String genre) {
this.genre = genre;
}
public String getGenre() {
return genre;
}
}
First, I'm not sure why you are trying to sort by album when you are storing your returned values by song (see #Usman Rafi above), but..
Add a global arraylist to the top of your fragment
ArrayList<Song> Albums = new Arraylist<>();
don't try to add genre information--you don't need it for your purpose
I tried sorting the album ids but that doesn't fix it because album id have nothing to do with sorting the art apparently.
Album art Uri's can be written as:
ContentUris.withAppendedId(Uri.parse("content://media/external/audio/albumart"),
cursor.getInt(cursor.getInt(cursor.getColumnIndexOrThrow(SONG_ALBUMID))));
So album art and album_id are actually inextricably linked.
So my problem is that when i try to sort the albums...
Use MediaStore.Audio.Media.IS_MUSIC + "=1 ) GROUP BY (" + MediaStore.Audio.Media.ALBUM in the selection variable of your query...
This will return unique album names (it will also only return one song within the album), if the album is repeated (by having several songs from the same album) in your mediastore database, only the first instance which matches your query will be added to your cursor.
to sort the albums...
Use the sort order to sort cursor rows which are returned by album; I personally sort them using sql's alphabetical order (symbols, numbers, a, b, c....)
You should note here that sorting is case sensitive unless you specify "COLLATE NOCASE"
to write your query and sort it I would use the following code:
String[] projection = {"DISTINCT " + MediaStore.Audio.Media.ALBUM_ID,
MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.DATA,
MediaStore.Audio.Media.ALBUM,
MediaStore.Audio.Media.IS_MUSIC};
String selection = MediaStore.Audio.Media.IS_MUSIC +
"=1 ) GROUP BY (" + MediaStore.Audio.Media.ALBUM_ID;
String sort = MediaStore.Audio.Media.ALBUM + " COLLATE NOCASE ASC";
Cursor cursor = context.
getContentResolver().
query(MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI,
projection,
selection,
null,
sort);
After this you can simply move through your cursor adding each row to the data object you built, there is no need for further sorting, and things should be in the proper order.
I personally just loop through
if(cursor != null && cursor.getCount >0){
while(cursor.moveToNext()){
//create new song item and add the album information you need
Song album = new Song(cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Media._ID)),
cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA)));
album.setAlbumId(cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID)));
album.setAlbumId(cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM)));
//add the Song item to the global arraylist
Albums.add(album)
}
}
cursor.close();
you can now access the sorted album info by position in the arraylist... you can get to the album art using the Uri builder i showed you at the top...
like this
Song Album = Albums.get(position);
imageView.setURI(ContentUris.withAppendedId(Uri.parse("content://media/external/audio/albumart"),
Album.getAlbumID());
I hope this is useful to you.
i still think you should build a data class called Album
First of all, you should make a class Album that holds the information of one specific album. Then either implement Comparable or Comparator Interface.
Comparable if the albums are always sorted based on the same
field.
Comparator if you need to implement multiple sorting logic
If I understand your code correctly, you're creating a list of strings which contains albums, then sorting this list independent of the original Query songs list. This means the album art remains untouched. I'd suggest implementing a comparable or comparator.
The reason why the 2, coverart and title mismatch is because you sort one and leave out the other as is.
Consider the below example :
Album before sort -
World
Hello
Id before sort-
1
2
Album after sort
1. Hello
2. World
But id remains as such.
So when you build the uri for the coverart using the id list, id picked at position 0 is of album at position 1.
Without changing much in your code, you can achieve what you intend by sorting the Songs using a Comparator. Comparator can be used whenever you need to sort the objects using one of its properties (which is album name in your case for the QuerySongs object)
In your getAlbumsId method, add following
public ArrayList<Long> getAlbumsId() {
ArrayList<Long> albumids = new ArrayList<Long>();
Collections.sort(songs, new Comparator<QuerySongs>() {
#Override
public int compare(QuerySongs o1, QuerySongs o2) {
return o1.getAlbum().compareTo(o2.getAlbum());
}
});
for (QuerySongs song : songs){
Long albumid = song.getAlbumID();
if (! albumids.contains(albumid)) {
albumids.add(albumid);
}
}
return albumids;
}
Above will mutate the songs object, if you don't want that to happend, make a copy of it. Crux is to use comparator to sort the songs.
Related
I want to create this data stricture:
Map<String, Country> table = new HashMap<>();
table.put("AF", new Country("Afghanistan", "AFG", "004"));
// 300 more
class Country {
private String country;
private String alpha3;
private String number;
public Country(String country, String alpha3, String number) {
this.country = country;
this.alpha3 = alpha3;
this.number = number;
}
}
Second way:
Map<String, Country> table = new HashMap<>();
Table<String, String, Integer> table2 = HashBasedTable.create();
table.put("AF", HashBasedTable.create().put("Afghanistan", "AFG", "004"));
// 300 more
I want to search values into the data structure values based on keys that I send:
numeric code from country name
country code from country name
alpha3 code from country name
What is the bast way to implement this search into the second data structure?
HashMap contains a method called forEach(BiConsumer<? super K,? super V> action) which can be used to iterate through each key-value pair in your HashMap.
Therefore, using a lambda you can do something like this:
//Search a HashMap of employee ID/name records by name, for their ID number.
public int getID(HashMap<Integer, String> employees, String name) {
//Iterate through every key-value pair, performing the lambda's operation on it.
employees.forEach((Integer j, String k) -> {
if(k.equals(name)) return Integer.valueOf(j); //If the value matches the name, return the ID
}
return -1;
}
I am struggling with making this work properly. So I have two CSV Files.
And this One
So the main thing is. I have SearchTerms in 2nd CSV. In first CSV I have SearchTerms also, which should work as a "tag".
What I need is to get product ids from first CSV saved to a List < String > based on, what searchterm from 2nd csv is used. So when Akt (pan) is used, one set of List of IDS is exported. If there is more Akt (pan) sets of ids, they are saved to one list as array I guess.
I tried to read it with CSVloaders and searching it with lookup() method
private final Map<List<String>, Comparison> data = Maps.newHashMap();
public Comparison lookup(String searchTerm) {
return data.get(searchTerm);
}
Where Comparison Class is
public class Comparison {
#Parsed(field = "ProductId1")
private String productId1;
#Parsed(field = "ProductId2")
private String productId2;
#Parsed(field = "ProductId3")
private String productId3;
#Parsed(field = "SearchTerm")
private String SearchTerm;
public String getProductId1() {
return productId1;
}
public String getProductId2(){
return productId2;
}
public String getProductId3(){
return productId3;
}
public List<String> getProductIds(){
List<String> ids = new ArrayList<>();
Collections.addAll(ids, productId1, productId2, productId3);
return ids;
}
}
My solution was bad. I was getting NullPointerException constantly whenever I tried to use lookup() method.
Do you have any ideas how to make this work? Thank oyu
Problem is with the data type of key in your HashMap. It should be a string as per your data, not a List<>.
private final Map<String, Comparison> data = Maps.newHashMap();
public Comparison lookup(String searchTerm) {
return data.get(searchTerm);
}
Then the returning object(typed Comparison) would have the all products Ids for the given search Term.
I have the array list ArrayList doctors which stores objects that store the details of some doctors. Each doctor has a unique id field. Is there a way to search through the array list for a doctor with a certain ID value?
You can just use streams on the ArrayList like so:
Optional<Doctor> getUniqueDoctorById(List<Doctor> list, String id) {
return list.stream()
.filter(doctor -> doctor.getId().equals(id))
.findFirst();
}
Here you see streaming the list and filtering all doctors where doctor id equals the id you are searching for.
Try something like this.
private static Doctor queryDoctorById(List<Doctor> doctors, int id) {
Doctor doctor = null;
for (Doctor doc : doctors) {
if (doc.id == id) {
doctor = doc;
break;
}
}
return doctor;
}
// is a sample object representing doctor
protected static class Doctor {
public String name;
public int id;
}
Simplest, but probably not the most efficient solution, I'm assuming you set up "doctors" with setters/getters for all the fields, otherwise you would use d.id instead of d.getId() but that's not a good practice:
I'm also assuming ID might contain letters and numbers and is represented as a string. If it is a number, you would use == instead of .equals
public Doctor findDoctorById(desiredID) {
for(Doctor d : doctors) {
if (d.getId().equals(desiredID) {
return d;
}
}
System.out.println("No doctors with that ID!");
return null;
}
I am attemping to populate a JComboBox with the names of cities.
My program has a class called 'Country'. The Country object contains a HashMap of objects called 'City' with a method getName, returning a String value.
public class Country {
private final Map<String, City> cities = new HashMap<>();
public Collection<City> getCities() {
return cities.values();
}
}
public class City {
String cityName;
public String getName() {
return cityName;
}
}
Is it possible to return an String array of cityName without using a loop? I was trying the following but it did not work:
Country country 1 = new Country();
String[] cityNames = country1.getCities().toArray();
JComboBox cityChoice = new JComboBox(cityNames);
This returns an Array of City objects, however I am not sure how to use the City getName method in conjunction with this.
You can not avoid looping. Either, you will loop, or Java will loop in the background.
You can avoid writing your own loop if keys in your map are city names. Then, you could only ask .keySet() from the map. But, even in that case, Java would loop in the background and copy the keys.
Other way is that you loop, but hide the loop in some method (lets say getCitiesArray()) in the class. So, you could do country1.getCitiesArray(); in the calling method. Code would look better and be easier to read, but you would still need to have loop inside of the class.
You can store Map key as CityName then do below to get Names.
cities.keySet();
The city object can be used directly in the combobox with some minor alterations.
public class City {
String cityName;
public String getName() {
return cityName;
}
#Override
public String toString() {
return getName();
}
}
Then the population code
Country country1 = new Country();
City[] cities = country1.getCities().toArray();
JComboBox<City> cityChoice = new JComboBox<City>(cities);
You should probably override hashCode and equals also.
If you are using Java 8, you can use the Stream API to map the names of the cities to a String:
String []cityNames = country1.getCities().stream().map(City::getName).toArray(String[]::new);
I've got an array coming in from a cursor in a function from a sqlite database. I'd like to add multiple items to the array to make it easier to bring data in from other pages. I.e. I'd like to do mArray("ID"), mArray("Name") (i'll be populating a listview from an array of the function, and would like to have easy access to name from ID)
Here is my code at the moment which only saves the ID in the array:
public static Array GetRooms(String StationID) {
File dbfile = new File(Global.currentDBfull);
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(dbfile, null);
Cursor c = db.rawQuery("select * from StationObjects where ObjectID = 0 and StationID = " + StationID , null);
c.moveToFirst();
Log.e("TomDebug", c.getString(c.getColumnIndex("SubGroupName")));
ArrayList<String> mArrayList = new ArrayList<String>();
c.moveToFirst();
while(!c.isAfterLast()) {
mArrayList.add(c.getString(c.getColumnIndex("SubGroupName")));
c.moveToNext();
}
return null;
}
Edit: To give a bit of clarity;
In psudocode i'd like to be able to do:
while(!c.isAfterLast()) {
mArrayList.name.add(c.getString(c.getColumnIndex("Name")));
mArrayList.type.add(c.getString(c.getColumnIndex("Type")));
mArrayList.ID.add(c.getString(c.getColumnIndex("ID")));
c.moveToNext();
}
So that anywhere in the code i can do
Array curRooms = GetRooms("1234")
String name = curRooms.Name
String type = curRooms.Type
(i know the mix between array and string wont work there, but just an example)
It sounds like you want an actual data structure instead of a string. There are a few ways of doing this, with ORMs and whatnot, but a basic example would be something like this, that you can fill the fields in from the database.
public class StationObject
{
public String name;
public String type;
public String id;
}
//pseudocode
for each result in resultset
fill temp StationObject with fields
add temp to list