/*
* Copyright 2016 Kejun Xia
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.shipdream.lib.android.mvc;
import com.shipdream.lib.poke.util.ReflectUtils;
/**
* A bean in AndroidMvc is a basic unit has a model that can be automatically saved and
* restored by the framework. Also, all beans have their life cycles. So when they are created on
* injection {@link #onCreated()} will be called so do {@link #onDestroy()} when the last object
* referencing them is not used any more.
* @param <MODEL>
*/
public abstract class Bean<MODEL> {
private MODEL model;
/**
* Bind model to Bean
* @param model non-null model
* @throws IllegalArgumentException thrown when null is being bound
*/
public void bindModel(MODEL model) {
if (model == null) {
throw new IllegalArgumentException("Can't bind null model explicitly.");
} else {
this.model = model;
}
}
/**
* Called when the Bean is injected for the first time or restored when a new instance of
* this Bean needs to be instantiated.
*
* <p>The model of the Bean will be instantiated by model's default no-argument constructor.
* However, if the Bean needs to be restored, a new instance of model restored by
* {@link #restoreModel(Object)} will replace the model created by this method.</p>
*/
public void onCreated() {
model = instantiateModel();
}
private MODEL instantiateModel() {
Class<MODEL> type = modelType();
if (type == null) {
return null;
} else {
try {
return new ReflectUtils.newObjectByType<>(type).newInstance();
} catch (Exception e) {
throw new RuntimeException(
String.format("Fail to instantiate model of %s by its default constructor", type.getName()), e);
}
}
}
/**
* Called when the Bean is disposed. This occurs when the Bean is de-referenced and
* not retained by any other objects.
*/
public void onDestroy() {
}
/**
* Model represents the state of this Bean.
* @return Null if the Bean doesn't need to get its model saved and restored automatically.
*/
public MODEL getModel() {
return model;
}
/**
* Provides the type class of the model.
* @return Implementing class should return the type class of the model that will be used by
* this Bean to instantiate its model in {@link #onCreated()} and restores model in
* {@link #restoreModel(Object)}. Returning null is allowed which means this Bean doesn't
* have a model needs to be automatically saved and restored.
*/
public abstract Class<MODEL> modelType();
/**
* Restores the model of this Bean.
* <p>
* Note that when {@link #modelType()} returns null, this method will have no effect.
* </p>
*
* @param restoredModel The restored model by {@link StateKeeper} that will be rebound to the
* Bean.
*/
public void restoreModel(MODEL restoredModel) {
if (modelType() != null) {
this.model = restoredModel;
onRestored();
}
}
/**
* Called after {@link #restoreModel(Object)} is called only when {@link #modelType()} returns
* a non-null type class.
*/
public void onRestored() {
}
}