pardom-zz / ActiveAndroid

Active record style SQLite persistence for Android
http://www.activeandroid.com
4.7k stars 1.03k forks source link

How to put a model into bundle extras #60

Open josuemontano opened 11 years ago

josuemontano commented 11 years ago

Hi, folks! I'm a newbie with Android and ActiveAndroid. So I'm really sorry if this is a fool issue :( I just cant figure it out

I wrote a Book class which has Chapter objects (a one to many relationship). It implements the method public List chapters(), as stated in the docs. This is the Book.java

@Table(name = "Books")
public class Book extends Model implements Serializable {

    private static final long serialVersionUID = 1L;

    @Column(name = "Name", unique = true, onUniqueConflict = Column.ConflictAction.IGNORE)
    public String name;

    @Column(name = "Sort")
    public int sort;

    public Book() {
        super();
    }

    public Book(String name, int sort) {
        super();
        this.name = name;
        this.sort = sort;
    }

    public List<Chapter> chapters() {
        return getMany(Chapter.class, "Book");
    }

    @Override
    public String toString() {
        return name;
    }

On the main activity I can get the Chapter objects successfully. However, I have to pass a book object to another activity, which has a fragment, and though I get the object's stated attributes (String name and int sort) it throws an exception when I call to chapters():

Bundle bundle = getIntent().getExtras();
Book book = (Book) bundle.getSerializable("BOOK");

// This line is executed successfully
Log.d("TAGGED", "Recovered book: " + book.name + " has " + book.sort + " as its sort");

// This is the line that throws an exception 
ArrayList<Chapter> chapters = book.chapters();

Any ideas what is wrong? Thanks!!!

SeanPONeil commented 11 years ago

Instead of implementing Serializable, I recommend serializing your model to JSON with Gson, and then passing the JSON representation as a String extra in the Intent. Example:

Serialization:

Gson gson = new Gson();
String json = gson.toJson(book);

Deserialization:

String json = getIntent().getStringExtra("BOOK");
Book book = gson.fromJson(json, Book.class);
marcosanson commented 11 years ago

gson.toJson() of a Model object doesn't work. it return an erro like this:

10-02 13:03:22.140: E/StoriesActivity_(5415): A runtime exception was thrown while executing code in a runnable 10-02 13:03:22.140: E/StoriesActivity_(5415): java.lang.UnsupportedOperationException: Attempted to serialize java.lang.Class: [your model]. Forgot to register a type adapter?

joshuapinter commented 10 years ago

@marcosanson Hey Marcos, I'm having a similar issue and a similar problem witih Gson not being able to serialize my object.

Did you manage to find a solution?

Thanks.

rothschild86 commented 10 years ago

same problem here... (Attempted to serialize java.lang.Class: [your model]. Forgot to register a type adapter?)

zhakid commented 10 years ago

Same here!

k0shk0sh commented 10 years ago

any solution???

heatherSnepenger commented 9 years ago

Anyone find any solution to this? I'm running into a similar issue.

jlhonora commented 9 years ago

What I usually do is just pass the model's id through the bundle. That way when you recreate the next activity you just query by the model's id, with the added benefit that you're getting a fresh copy from the DB (if background processes that affect the DB are running).

If you do need the whole JSON representation you could do the following:

public JsonObject jsonSerialize(SomeModel yourModel) {
    Gson gson = new GsonBuilder()
    .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
    .create();

    JsonObject modelJson = gson.toJsonTree(yourModel).getAsJsonObject();
}

public void goToActivity() {
    String modelJsonString = jsonSerialize(yourModel).toString();
    Intent i = new Intent(this, SomeActivity.class);
    i.putExtra(SomeActivity.KEY_SOME_MODEL_JSON, modelJsonString);
    startActivity(i);
}

And then in your activity:

Gson gson = new GsonBuilder()
    .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
    .create();
gson.fromJson(extras.getString(KEY_SOME_MODEL_JSON), SomeModel.class);

Here's an example for a custom JSON deserialization:

public class SomeModelTypeAdapter implements JsonDeserializer<SomeModel> {

    @Override
    public SomeModel deserialize(JsonElement je, Type type, JsonDeserializationContext jdc)
            throws JsonParseException
    {
        // Do something with your model

        // Deserialize it
        return new Gson().fromJson(je, SomeModel.class);
    }
}

In that case you will need to specify this type adapter in the Gson instance:

Gson gson = new GsonBuilder()
                .registerTypeAdapter(SomeModel.class, new SomeModelTypeAdapter())
                .create();

I recommend as well to have a utility class that provides the Gson instance so that you don't have the gson specification scattered around in many places.

A few extra comments:

Gregliest commented 9 years ago

Gson can't serialize some of the fields in Active Android's base Model class by default. The best solution I found was to use Gson's excluedFieldsWithoutExposeAnnotation() option to ignore those fields, as follows:

Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
String json = gson.toJson(new Book());

Modifying the Book class with the @Expose annotation to indicate which fields should be serialized:

@Table(name = "Books")
public class Book extends Model implements Serializable {

    @Expose
    @Column(name = "Name", unique = true, onUniqueConflict = Column.ConflictAction.IGNORE)
    public String name;

    @Expose
    @Column(name = "Sort")
    public int sort;

    ...
}

My stack overflow post on the topic is here

neosarchizo commented 9 years ago

@Gregliest Thanks!! It works well!

bisonfute commented 9 years ago

I had the same issue and the @Gregliest hint works for me as well! A big thank!

waylife commented 8 years ago

Because Model neither implement Serializable nor Parcelable, so the parameters serialization and deserialization can not work properly. All parameters in Model, not including its child's parameters, will lost. Such as id, which the update, save , delete and other actions depend on. image

So we know the reasons, how to solve this? Two solutions: One is to rewrite the model to implement either Serializable or Parcelable, the other is to wrapper it with some Serializable or Parcelable (like Gson, which you all mentioned above) and then dewrapper it to use.

khoatd92 commented 8 years ago

I got the same issue. Any solution? :(

khoatd92 commented 8 years ago

So the hint of @Gregliest is only way to do it? :( By the way, Thank @Gregliest