(De)Serializing objects automatically to a bundle

2019-09-18 16:18发布

问题:

I've seen some libraries in Scala that can (de)serialize automatically any case class that has supported member types automatically to i.e. JSON.

In the Android world, I'd like to be able to do so with Intent and Bundle.

Example, I'd like this boilerplate code to be generated:

case class Ambitos(idInc: Long, idGrupo: String, ambitos: Map[String, Seq[String]])
    def serialize(b: Bundle) {
        b.putString("grupo", idGrupo)
        b.putLong("inc", idInc)
        b.putStringArray("ambitos", ambitos.keys.toArray)
        ambitos.foreach { case (a, det) ⇒
            b.putStringArray(a, det.toArray)
        }
    }

    def serialize(b: Intent) {
        b.putExtra("grupo", idGrupo)
        b.putExtra("inc", idInc)
        b.putExtra("ambitos", ambitos.keys.toArray)
        ambitos.foreach { case (a, det) ⇒
            b.putExtra(a, det.toArray)
        }
    }
}

object Ambitos {
    def apply(b: Intent): Ambitos =
        Ambitos(b.getLongExtra("inc", -1), b.getStringExtra("grupo"),
            b.getStringArrayExtra("ambitos").map{ a ⇒ (a, b.getStringArrayExtra(a).toSeq) }.toMap)

    def apply(b: Bundle): Ambitos =
        Ambitos(b.getLong("inc"), b.getString("grupo"),
            b.getStringArray("ambitos").map{ a ⇒ (a, b.getStringArray(a).toSeq) }.toMap)
}

Does exist such a library or do I have to make it by myself?

For passing complex information between Activities and for handling Activity onSaveInstanceState() and onRestoreInstanceState(), this tool would be awesome.

回答1:

you can use GSON lib to do something different, I assume you have some complex object and you want to pass from one activity to another activity.

just use GSON

Gson gson = new Gson();     
// convert java object to JSON format,  
// and returned as JSON formatted string  
String jsonString = gson.toJson(complexJavaObj);

and then just use

i.putExtra("objectKey",jsonString);

and read as in second activity

Bundle extras = getIntent().getExtras();
if (extras != null) {
String jsonString = extras.getString("objectKey");

 if(jsonString!=null){
   Gson gson = new Gson();
   ComplexJavaObj complexJavaObj= gson.fromJson(jsonString, ComplexJavaObj .class);
  }
}

Hope this will give you the basic idea.



回答2:

This is the answer that Nick has provided me in a Android Scala forum:

It should be relatively straightforward if you know your way around macros :) Here’s one that serializes pairs (key, value).

From there, you just need to add the case class inspection bit. Example (a bit convoluted), see also line 89 for usage. On a final note, I would make it typeclass-based rather than inheritance-based:

trait Bundleable[A] {
  def toBundle(x: A): Bundle
  def fromBundle(b: Bundle): Try[A]
}

implicit def genBundleable[A]: Bundleable[A] = macro ???

def bundle[A: Bundleable](x: A) =
  implicitly[Bundleable[A]].toBundle(x)

This way you can define instances of Bundleable[A] both manually and automatically. And your data model is not polluted with Android nonsense.