Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Entities implementing Parcelable #4

Closed
greenrobot opened this issue Nov 7, 2011 · 17 comments
Closed

Entities implementing Parcelable #4

greenrobot opened this issue Nov 7, 2011 · 17 comments

Comments

@greenrobot
Copy link
Owner

Annoying boiler plate code is just perfect for geenDAO...

@chrisjenx
Copy link

+1 for this, would be awesome

@deradam
Copy link

deradam commented Jun 29, 2012

I am actually exactly at the point where I would prefer to just pass the entity to another intent. Right now I am passing always the entity id and doing a query in the new Activity again. I guess that the DAO is doing some caching, thus this query should be quite quick. I heard that Serialization in Android is not very fast.

So what is finally the best way to do it?

@greenrobot
Copy link
Owner Author

@deradam: passing IDs is fine. greenDAO's load() tries to do a map lookup with the ID first (identity scope), so this should be very, very fast if the entity is available. This should be even faster than creating the parcel and making an object out of it again.

One thing to keep in mind: The identity scope holds only weak references to the entity, but usually the entities are referenced in the calling activity.

@gderaco
Copy link

gderaco commented Aug 4, 2014

Any news about this feature?

@bri822
Copy link

bri822 commented Aug 24, 2014

I too would get great use out of this feature. I want to eliminate a DB hit when the device is rotated and my Fragment is recreated to improve latency. Since all the fields and types are declared, it seems it would be possible...

@mominbuet
Copy link

This feature would certainly improve the generation process.

@darkosmoljo
Copy link

Any news about this feature, is it even in consideration? At least I'd like to be able to remove the "private" modifier so I can implement @parcel, but until then - poor serialization....

@gestinronan
Copy link

Hello no news about parcelable?

@theojalba
Copy link

You can add Parcelable support right now by using interfaces and keep sections. The downside is that the Parcelable code is not updated when the entity fields change, although the Parcelable code will be retained when you generate the entire schema again.

I would be interested in better parcelable support that automatically updates the parcelable code when the entity fields change.

Here is how to manually add Parcelable support:

  1. In your generator, enable keep sections on the schema:
    schema.enableKeepSectionsByDefault();
  2. For each Parcelable entity in the schema above, add the following:
    entity.implementsInterface("android.os.Parcelable");
  3. Run the generator to generate the files
  4. Go to each Parcelable entity file, find the KEEP METHODS section and add the Parcelable methods there.
// KEEP METHODS - put your custom methods here

@Override
public int describeContents()
{
    return 0;
}

...

// KEEP METHODS END

Find the KEEP INCLUDES section and move all the custom imports there:

// KEEP INCLUDES - put your custom includes here
import android.os.Parcel;

...

// KEEP INCLUDES END

HINT: You can use a plugin that automatically writes the Parcelable boilerplate.

https://github.com/mcharmas/android-parcelable-intellij-plugin

@ccaronls
Copy link

ccaronls commented Nov 6, 2015

I have modified our local branch to partially support this. It makes sense with dynamic to not have to use the KEEP blocks.

@MeherGh
Copy link

MeherGh commented Nov 18, 2015

in my case i add this to parcelable methode so we prevent the detached from DAO exception when you passe an object to a new Activity

protected Entity (Parcel in) {
this.daoSession = MainApplication.getInstance().getDaoSession();
......
}

@adjorno
Copy link

adjorno commented Nov 20, 2016

How to do it with greedDao gradle plugin?

  1. In your generator, enable keep sections on the schema:
    schema.enableKeepSectionsByDefault();
  2. For each Parcelable entity in the schema above, add the following:
    entity.implementsInterface("android.os.Parcelable");

@greenrobot-team
Copy link
Collaborator

@adjorno See my comment on #427 for an example. -ut

@adjorno
Copy link

adjorno commented Nov 21, 2016

Thanks, but I have just realized that its illegal to make greeanDao entities Parcelable:
I don't want to reload entities from DB on device rotation because it takes some time, that is why I was going to put them in Bundle as Parcelable in onSaveInstanceState. Android tries to reuse Parcelables if its possible and I got the same ones and everything works fine in this case. But!.. There is another more tricky case - magic "Don't keep activities" button. This case is like device rotation but all the data should be restored from scratch. Restored greenDao entities will contain all the data but they wont have daoSession and app crashes with exception something like "Entity is not attached to DAO context".

I see 2 solutions:

  • create real POJO entities and convert to them when I got result from DB request
  • drop greenDao and work with raw sqlite requests.

Is there any ways to save & restore greenDao entities?

@greenrobot-team
Copy link
Collaborator

greenrobot-team commented Nov 22, 2016

@adjorno Simple answer: don't. Just query for them again. greenDAO will hold onto entity instances in its session cache, so on config changes a query returns the same objects without having to re-create them.

Edit: Or use the Android Loader framework or something equivalent. -ut

@adjorno
Copy link

adjorno commented Nov 22, 2016

I guess the caching doesn't work for my case, because I query raw sqlite request:

SELECT TRACK_ID, ARTIST_ID, TRACK.TITLE, ARTIST_ID, ARTIST.NAME,
SUM((LIST_SIZE + 1 - RANK) * (LIST_SIZE + 1 - RANK)) AS RATING FROM CHART_LIST
INNER JOIN CHART_TRACK ON CHART_LIST._ID = CHART_TRACK.CHART_LIST_ID
INNER JOIN CHART ON CHART._ID = CHART_LIST.CHART_ID
INNER JOIN TRACK ON TRACK._ID = CHART_TRACK.TRACK_ID
INNER JOIN ARTIST ON ARTIST._ID = TRACK.ARTIST_ID
WHERE CHART_ID = %theChartId% AND date(DATE) > date('%theFrom%') AND date(DATE) < date('%theTo%')
GROUP BY TRACK_ID ORDER BY RATING DESC

...
final Cursor theCursor = daoSession.getDatabase().rawQuery(theQuery, new String[0]);
final List theTracks = daoSession.getTrackDao().loadAllDeepFromCursor(theCursor);
theCursor.close();
...

I do it via raw request since I could not find any support of aggregate functions (SUM) and grouping (GROUP BY) in greenDao. On some slow devices it takes up to 10 seconds to handle this request (~200K tracks) and I don't want to do it again on config changes. I'd like to have a possibility to get these entities fast that is why I wanted to put them into the Bundle. Now I see that it is illegal with greenDao.
I am going to create some manual caching to put the result to separate "CacheTrack" table and try to re-use it on config changes firstly, and if there is nothing in it than do the real request I described above.
Is there a way to customize greenDao caching mechanism to support my case?

@greenrobot-team
Copy link
Collaborator

As said, this is exactly what the Android loader framework is for. Just write your own AsyncTaskLoader. -ut

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests