Create initialize methods in a compile time
hotchemi opened this issue ยท 10 comments
Proposal
My proposal is creating initialize methods in a compile time automatically.
public final class ExamplePrefs extends PrefsSchema {
private static ExamplePrefs prefs;
// guess double check pattern like Picasso.with is better for performance...
public static synchronized ExamplePrefs get(Context context) {
if (prefs == null) {
prefs = new ExamplePrefs(context);
}
return prefs;
}
}
Why
Now, we have to define like create
method in a schema class and maintain the state of generated class instance.
I can't figure out the appropriate reason for that. Any thoughts?
Thank you for your proposal!
Generating initialize method
Good point! Ideally, it should be like you said.
However, sometimes we want to change creation mode of SharedPreferences or use special SharedPreferences like below.
// CredentialPrefsSchema.java
public static synchronized CredentialPrefs get(Context context) {
if (prefs == null) {
EncryptedSharedPreferences encryptedSharedPreferences = EncryptedSharedPreferencesProvider.create(
context.getSharedPreferences(TABLE_NAME, Context.MODE_PRIVATE),
context);
prefs = new CredentialPrefs(encryptedSharedPreferences);
}
return prefs;
}
I can't think of a good interface for these cases for now ๐ Any thoughts?
Synchronization
IMHO, the synchronization cost wouldn't be a problem in most cases because *Schema.get
isn't called so many times in a event loop unlike Picasso. I like to reduce handwritten code as much as possible. So I'm not using double checked locking in my project. I don't force this way. It's up to each developer because they have different use cases.
However if we generate a initialize method, that's another story. Double checked locking should be generated by processor ๐
Umm, might be I miss the point but how about preparing below two methods? I think you already create two constructors.
public final class ExamplePrefs extends PrefsSchema {
private static ExamplePrefs prefs;
public static synchronized ExamplePrefs get(Context context) {
if (prefs == null) {
prefs = new ExamplePrefs(context);
}
return prefs;
}
public static synchronized ExamplePrefs get(SharedPreferences prefs) {
if (prefs == null) {
prefs = new ExamplePrefs(prefs);
}
return prefs;
}
}
And when it comes to the synchronization, I agree with you.
But yes, we have JavaPoet so we can generate whatever java code, even double checked locking!
how about preparing below two methods?
@hotchemi Does it mean that we have to give a SharedPreferences every time we get a Prefs instance?
CustomSharedPreferences customSharedPreferences = ...;
...
ExamplePrefs.get(customSharedPreferences).putValue(...)
...
ExamplePrefs.get(customSharedPreferences).getValue(...)
In this case, we have to keep custom SharedPreferences as a singleton (singleton for singleton ๐).
Hmm... I have 2 ideas.
1. Create Builder class
We may be able to build custom SharedPreferences by creating builder class or something like below.
// ExamplePrefsSchema.class
@Table(name = "example", builder = ExamplePrefsBuilder.class)
public abstract class ExamplePrefsSchema {
@Key("key") int value;
}
// ExamplePrefs.class
public final class ExamplePrefs extends PrefsSchema {
private static ExamplePrefs prefs;
public static synchronized ExamplePrefs get(Context context) {
if (prefs == null) {
prefs = new ExamplePrefsBuilder().build(context);
}
return prefs;
}
}
// ExamplePrefsBuilder.java
public class ExamplePrefsBuilder implements PrefsBuilder {
@Override
public ExamplePrefs build(Context context) {
...
return new ExamplePrefs(customSharedPreferences);
}
}
If builder is not specified in the Schema class, this library just generate get
method.
// ExamplePrefsSchema.class
@Table(name = "example")
public abstract class ExamplePrefsSchema {
@Key("key") int value;
}
// ExamplePrefs.class
public final class ExamplePrefs extends PrefsSchema {
private static ExamplePrefs prefs;
public static synchronized ExamplePrefs get(Context context) {
if (prefs == null) {
prefs = new ExamplePrefs(context);
}
return prefs;
}
}
2. Create Initializer class
It's like below.
// MyApplication.java
@Override
private void onCreate() {
....
PrefsSchemaInitializer
.initExamplePrefs(context)
.initCredentialsPrefs(customSharedPreferences);
}
I would like to avoid creating initializer class from the viewpoint of performance and maintainability. However, this way has an advantage that we don't have to give context when getting Prefs class.
ExamplePrefs.get().getValue(); // Already initialized!
What do you think?
Umm, IMO Builder idea is better! I definitely don't want to invite user to "initializing party".
We should provide it as an option, and it would be pretty nice ๐
Did you already kick off the development?
That's how I feel also.
I already started the implementation. My plan is
- Generate initialize methods: #11
- Bump version to 2.1.0
- Enable to specify builder
- Bump version to 3.0.0
- Due to breaking change
@Table("name")
=>@Table(name = "name")
- Due to breaking change
Gotcha!
@hotchemi 2 PRs were merged. kvs-schema became far better! Thank you ๐ป โจ
๐ We're trying to adopt it in production!
Great ๐