ActiveAndroid
ActiveAndroid copied to clipboard
Added hooks for save and delete, allow simple change tracking
Added two hooks onSaved() and onDeleted(), to allow derived classes to do something useful after being either saved or deleted (e.g. trigger an update of the UI), since save() and delete() methods are final.
Also added methods that allow derived classes to do a simple form of change tracking. A derived class can use markAsChanged() to track if it was changed, the flag is reset once the model is saved. For example, this can be used to only invoke save() on a model if isChanged() returns true.
This was discussed on another issue here, I realy not know why the save and delete methods are final, but if your case is get when the models are edited just go and change the final modifier of the save and/or delete method.
You always can perform a check on the Model.getId() if the model is saved this will not return null and will return the correct ID, I think this merge is just a work around and merge is not required.
I think you misunderstand the intention of this change. I do not want to detect whether a model was previously saved or not. I want to perform an action whenever a model is saved (i.e. more than once).
Removing 'final' from save() would be an option, but I think the intention is to prevent implementers from accidentally forgetting to call super.save() in the override. So adding onSaved() which in turn is overridable is imho a better option.
As far as I see it, using "getId() != null" (potentially in combination with polling) is the workaround (and does not work with instances that were loaded from the DB). Providing an override that lets derived classes do 'whatever' whenever a model is saved to the DB is the clean solution imho.
In my case, I trigger an update of the UI by sending a 'changed'-Message from onSaved(), which guarantees that what the UI sees in-memory is consistent with what has been written to the database and allows me to update the UI without having to read from the DB again. I'm sure there are other use cases where such an override would be useful.
I proposed a similar change in #28, but we seem to be the minority.
Just thinking, but if we want hooks for specific actions (insert, update, delete), would it be more elegant to introduce some sort of a callback mechanism? You could then just implement a listener that would perform the desired action and just register it with the library without the need to hardcode your actions into your models.
Callbacks wouldn't work for my case. Models are created/modified on a background thread and need to notify the UI of changes (via messages). Hooking up the UI to a model's callback doesn't work since you don't know it has been created until you receive a message that it has. Also, the callback might then be invoked from a background thread. However, hooks would allow you to implement callbacks very easily. As far as I see it hooks are more flexible.
However, after further testing I've noticed that callbacks still aren't flexible enough to serve all my needs. I'll remove the final modifiers, as leonardoxh suggested, from save() and delete() to give me full control. For example, a call to delete() can then decide whether to actually delete a row or set a model's "deleted" column to true based on its internal state.
So I guess I'll add my voice to removing the final modifiers instead (sorry vonloxley).
My idea was that this would not be on the model at all. You would have an external callback repository, so you would do something like this:
IModelCallback callback = new IModelCallback<YourModel>() {
@Override
public Class<YourModel> getModelClass() { //to know which class should trigger this callback
return YourModel.class;
}
@Override
public void onBeforeAction(ActionType action, YourModel model) throws InterruptModelOperationException {
//do whatever before model action happens
if (ActionType.Save.equals(action) && preventSave) {
throw new InterruptModelOperationException("YOU SHALL NOT SAVE!");
}
}
@Override
public void onAfterAction(ActionType action, YourModel model) {
//do something
}
};
ModelCallbacks.registerCallback(callback);
Then, upon the operations (save, update, delete, you could even add the "change" operation although you'd have to mark the model "changed" yourself).
Like this, you can also very easily put a Handler into the callbacks, much as you would probably inject one into the model when you are creating it in the background. You could inject and remove the callbacks along with Activity lifecycle.
As for removing final modifiers, I'm also all the way for it, also for the getId() method. Final methods cripple the possibilities to extend quite a bit.
No need to apologize @markuspfeiffer . But I’d really like to see this resolved, one way or another. @vsigler ’s solution has it’s merits too.
My idea was that this would not be on the model at all. You would have an external callback repository, so you would do something like this:
IModelCallback callback = new IModelCallback<YourModel>() { @Override public Class<YourModel> getModelClass() { //to know which class should trigger this callback return YourModel.class; } @Override public void onBeforeAction(ActionType action, YourModel model) throws InterruptModelOperationException { //do whatever before model action happens if (ActionType.Save.equals(action) && preventSave) { throw new InterruptModelOperationException("YOU SHALL NOT SAVE!"); } } @Override public void onAfterAction(ActionType action, YourModel model) { //do something } }; ModelCallbacks.registerCallback(callback);
Then, upon the operations (save, update, delete, you could even add the "change" operation although you'd have to mark the model "changed" yourself).
Like this, you can also very easily put a Handler into the callbacks, much as you would probably inject one into the model when you are creating it in the background. You could inject and remove the callbacks along with Activity lifecycle.
As for removing final modifiers, I'm also all the way for it, also for the getId() method. Final methods cripple the possibilities to extend quite a bit.
@vsigler in which class we should write your code and it can show/log the error, whether the record is saved or not?