Как преобразовать java.util.HashMap в android.content.ContentValues?

Есть ли простой способ конвертировать из java Map<String,Object> в android.content.ContentValues?

android.content.ContentValues используется в программировании базы данных Android для хранения данных строки базы данных в виде пар имя-значение.

Задний план:

Я пытаюсь перенести бизнес-логику существующего приложения для Android в приложение j2se-swing.

Моя цель - иметь специфичный для Android код и независимый от Android код, который входит в отдельную библиотеку, которая может использоваться как Android, так и Swing-GUI.

сейчас я анализирую

  • если мне нужно реализовать полный отдельный набор репозиторий с большим количеством избыточного кода
  • или если есть общий код, который можно использовать в обоих репозиториях (j2se-swing- и android-).

Repository-Database-Code использует пары "база данных-поле-имя-значение", в которых используется android.content.ContentValues.

Я думал, что моя независимая версия Android может использовать HashMap<String,Object> вместо ContentValues и создавать код для преобразования между ними.

Версия, зависящая от Android, будет выглядеть так

    // android dependant code in android-app
    class AndroidTimeSliceCategoryRepsitory implements ICategoryRepsitory {

        public long createTimeSliceCategory(final TimeSliceCategory category) {

            // get values from android independant layer
            Map<String, Object> columsToBeInserted = TimeSliceCategorySql.asHashMap(category);

// >>>> this is where i am stuck
            ContentValues androidColumsToBeInserted = DbUtils.asContentValues(columsToBeInserted);

            final long newID = AndroidTimeSliceCategoryRepsitory.DB.getWritableDatabase()
                    .insert(TimeSliceCategorySql.TIME_SLICE_CATEGORY_TABLE, null, androidColumsToBeInserted);
            category.setRowId((int) newID);
            return newID;
        }
    }

Это независимая часть Android:

    // android independant code in common jar
    class TimeSliceCategorySql {....

        /** converts {@link ....model.TimeSliceCategory}  to {@link java.util.HashMap} */
        public static Map<String, Object> asHashMap(final TimeSliceCategory category) {
            final Map<String, Object> values = new HashMap<String, Object>();
            values.put(TimeSliceCategorySql.COL_CATEGORY_NAME,
                    category.getCategoryName());
            values.put(TimeSliceCategorySql.COL_DESCRIPTION,
                    category.getDescription());

            // ... more values

            return values;
        }
    }

В настоящее время я застрял здесь:

    public class AndroidDatabaseUtil {
        /** converts from android independeant {@link java.util.Map} to android dependent {@link android.content.ContentValues} */
        public static ContentValues toContentValues(Map<String, Object> src) {
            ContentValues result = new ContentValues();

            for (String name : src.keySet()) {

// this is not possible because ContentValues does not define put(String name, Object value)
                result.put(name, src.get(name));

// using this would loose ContentValues.getAsLong() throw exception.
// result.put(name, src.get(name).toString());

            }
            src.entrySet()
            return result;
        }
    }

person k3b    schedule 02.08.2014    source источник
comment
Каков тип Object в вашей хэш-карте?   -  person Kyle Emmanuel    schedule 02.08.2014
comment
в настоящее время у меня есть String, Integer, Long, Double, Boolean   -  person k3b    schedule 02.08.2014


Ответы (3)


Как маршалировать/демаршалировать ContentValues вставить общий тип в ContentProvider?

Location loc = mLocationClient.getLastLocation();
HashMap hm = new HashMap();
hm.put("LOCATIONS", loc);
Parcel myParcel = Parcel.obtain();    
myParcel.writeMap(hm);
myParcel.setDataPosition(0);

ContentValues values = ContentValues.CREATOR.createFromParcel(myParcel);

getContentResolver().insert(MyDumbUri, values);

а потом

@Override
public Uri insert( final Uri uri, final ContentValues oldvalues ){
SQLiteDatabase db = GAELdatabase.getWritableDatabase();

Uri result = null;
Location loc = (Location)oldvalues.get("LOCATIONS");

ContentValues values = new ContentValues();

values.put("ALTITUDE", loc.getAltitude());//meters above sea level
values.put("LATITUDE", loc.getLatitude());
values.put("LONGITUDE", loc.getLongitude());

long rowID = db.insert( "MyTABLE_NAME", "", values);
db.close();
return result;
}
person JDOaktown    schedule 11.10.2014
comment
Хотел бы я увидеть этот подход до того, как решил реализовать решение для строкового представления ;-) - person k3b; 21.08.2015

Похоже, что значения, которые вы помещаете в свою карту, являются строками.

Поэтому вы можете изменить определение карты на

final Map<String, String> values = new HashMap<String, String>();

что позволит вам поместить значения в экземпляр ContentValues:

result.put(name, src.get(name));
person Eran    schedule 02.08.2014
comment
в моем примере я использовал только строку. В моем проекте в коде у меня также есть Integer, Long, Double и Boolean. - person k3b; 02.08.2014
comment
@k3b В этом случае вы можете использовать instanceof, чтобы проверить тип значения и привести его к Integer, Long, Double и т. д., прежде чем поместить его в ContentValues, используя соответствующий метод put. - person Eran; 02.08.2014
comment
я решил сопоставить все, кроме blob-s, со строкой, так как мне все равно нужно реализовать преобразование в другом направлении getInt (Map, key). вот почему я принял этот ответ вместо @ Кайл Эммануэль - person k3b; 04.08.2014
comment
Хотя я реализовал этот прагматичный подход, я просто изменил принятый ответ с этого на ответ @JDOaktown, который имеет общее решение, которое я искал - person k3b; 21.08.2015

Вы можете отфильтровать его, используя ключевое слово instanceof в операторе if.

Пример:

if( src.get(name) instanceof String){
  // convert to string
}

Вы также можете использовать метод getClass из объекта:

Объект ob = src.get(имя);

  if(ob instanceof ob.getClass()){
   // convert to type
  }
person Kyle Emmanuel    schedule 02.08.2014
comment
это решило бы мою проблему. давайте посмотрим, есть ли более элегантные решения, чем наличие одного if для каждого задействованного типа: String, Integer, Long, Double, Boolean - person k3b; 02.08.2014