Search code examples
javaandroidhashmap

Inserting into HashMap messes with sorting


Based on this class

public class Record {
    public static final String TABLE_NAME = "records";

    public static final String COLUMN_ID = "id";
    public static final String COLUMN_LONGITUDE = "longitude";
    public static final String COLUMN_LATITUDE = "latitude";
    public static final String COLUMN_SPEED = "speed";
    public static final String COLUMN_TIMESTAMP = "timestamp";

    private int id;
    private String longitude;
    private String latitude;
    private String speed;
    private String timestamp;

    public static final String CREATE_TABLE =
            "CREATE TABLE " + TABLE_NAME + "("
                + COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
                + COLUMN_LONGITUDE + " TEXT,"
                + COLUMN_LATITUDE + " TEXT,"
                + COLUMN_SPEED + " TEXT,"
                + COLUMN_TIMESTAMP + " TIMESTAMP DEFAULT (DATETIME('now','localtime'))"
            + ")";

    public Record(){
    }

    public Record(int id, String longitude, String latitude, String speed, String timestamp){
        this.id = id;
        this.longitude = longitude;
        this.latitude = latitude;
        this.speed = speed;
        this.timestamp = timestamp;
    }

    public int getId(){
        return id;
    }

    public String getLongitude(){
        return longitude;
    }

    public String getLatitude(){
        return latitude;
    }

    public String getSpeed(){
        return speed;
    }

    public String getTimestamp(){
        return timestamp;
    }

    public void setId(int id){
        this.id = id;
    }

    public void setLongitude(String longitude){
        this.longitude = longitude;
    }

    public void setLatitude(String latitude){
        this.latitude = latitude;
    }

    public void setSpeed(String speed){
        this.speed = speed;
    }

    public void setTimestamp(String timestamp){
        this.timestamp = timestamp;
    }
}

I have created my SQLite model

public class DatabaseHelper extends SQLiteOpenHelper {

    private static final int DATABASE_VERSION = 1;

    // Database Name
    private static final String DATABASE_NAME = "speeds";

    public DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(Record.CREATE_TABLE);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP TABLE IF EXISTS " + Record.TABLE_NAME);

        onCreate(db);
    }

    public void insertRecord(String longitude, String latitude, String speed){
        SQLiteDatabase db = this.getWritableDatabase();
        ContentValues values = new ContentValues();

        values.put(Record.COLUMN_LONGITUDE, longitude);
        values.put(Record.COLUMN_LATITUDE, latitude);
        values.put(Record.COLUMN_SPEED, speed);

        System.out.println("VALUEEEEEEEES" + values);

        db.insert(Record.TABLE_NAME, null, values);
        db.close();
    }

    public List<Record> getAllRecords(){
        List<Record> records = new ArrayList<>();

        String selectQuery = "SELECT * FROM " + Record.TABLE_NAME + " ORDER BY " + Record.COLUMN_TIMESTAMP + " DESC";

        SQLiteDatabase db = this.getWritableDatabase();
        Cursor cursor = db.rawQuery(selectQuery, null);

        if(cursor.moveToFirst()){
            do{
                Record record = new Record();
                record.setId(cursor.getInt(cursor.getColumnIndex(Record.COLUMN_ID)));
                record.setLongitude(cursor.getString(cursor.getColumnIndex(Record.COLUMN_LONGITUDE)));
                record.setLatitude(cursor.getString(cursor.getColumnIndex(Record.COLUMN_LATITUDE)));
                record.setSpeed(cursor.getString(cursor.getColumnIndex(Record.COLUMN_SPEED)));
                record.setTimestamp(cursor.getString(cursor.getColumnIndex(Record.COLUMN_TIMESTAMP)));

                records.add(record);
            } while (cursor.moveToNext());
        }
        db.close();

        return records;
    }

    public List<Record> getLastTenRecords(){
        List<Record> records = new ArrayList<>();

        String selectQuery = "SELECT * FROM " + Record.TABLE_NAME + " ORDER BY " + Record.COLUMN_TIMESTAMP + " DESC LIMIT 10";

        SQLiteDatabase db = this.getWritableDatabase();
        Cursor cursor = db.rawQuery(selectQuery, null);

        if(cursor.moveToFirst()){
            do{
                Record record = new Record();
                record.setId(cursor.getInt(cursor.getColumnIndex(Record.COLUMN_ID)));
                record.setLongitude(cursor.getString(cursor.getColumnIndex(Record.COLUMN_LONGITUDE)));
                record.setLatitude(cursor.getString(cursor.getColumnIndex(Record.COLUMN_LATITUDE)));
                record.setSpeed(cursor.getString(cursor.getColumnIndex(Record.COLUMN_SPEED)));
                record.setTimestamp(cursor.getString(cursor.getColumnIndex(Record.COLUMN_TIMESTAMP)));

                records.add(record);
            } while (cursor.moveToNext());
        }
        db.close();

        return records;
    }
}

Now, I am trying to show some data inside an ExpandableListView. In my scenario i sort the response of the sql query by the COLUMN_TIMESTAMP and trying to parse it in the type of HashMap<String , List<String> in order for the ExpandableListView to recognize it.

The problem is that even tho the result is sorted(and I can see it when looping and printing one by one), after I use this method to parse and put into HashMap, the sorting is gone.

public static HashMap<String, List<String>> getLastTenData(Context context) {
        HashMap<String, List<String>> expandableListDetail = new HashMap<>();

        DatabaseHelper databaseHelper = new DatabaseHelper(context);

        List<Record> recordList = databaseHelper.getLastTenRecords();
        for(int i=0; i<recordList.size(); i++){
            List<String> myList = new ArrayList<>();
            myList.add("Y: "+recordList.get(i).getLatitude());
            myList.add("X: " + recordList.get(i).getLongitude());
            myList.add("Km/h: "+recordList.get(i).getSpeed());
            expandableListDetail.put(recordList.get(i).getTimestamp(), myList);
            System.out.println("check "+String.valueOf(i)+"    "+recordList.get(i).getTimestamp());
        }

        System.out.println(expandableListDetail);

        return expandableListDetail;
    }

What I mean is that expandableListDetail is not sorted by key when it should be. Any help?


Solution

  • If have already ansered a similar question (regarding HashSet) here.

    Similar, a HashMap is unordered, so adding values to it and then iterating over the map will not yield items in the order you initially added them.

    Why does LinkedHashMap solve the issue? (picking up on the idea from @Deadpool)

    Hash table and linked list implementation of the Map interface, with predictable iteration order. This implementation differs from HashMap in that it maintains a doubly-linked list running through all of its entries. This linked list defines the iteration ordering, which is normally the order in which keys were inserted into the map (insertion-order).

    Why does TreeMap solve the issue? (picking up on the idea from @tomgeraghty3)

    The map is sorted according to the natural ordering of its keys