Combine my own understanding of MVP, plus personal habits, put together such an Android MVP framework
- Inject Presenter dynamically through annotations
- Presenter has a full life cycle
- Support for multi-presenter injection
- State recovery
0 x00 preface
This framework can be said to Fork the nucleus, but with personal understanding and custom changes, put the framework link github.com/izyhang/Dam…
0 x01 is introduced
First, a brief introduction to Damon
Create View and Presenter
Presenters have the same life cycle as activities, part of which is shown here
interface MainView {
fun log(msg: String)
}
class MainPresenter : BasePresenter<MainView>() {
override fun onCreate(arguments: Bundle? , savedState:Bundle?). {
super.onCreate(arguments, savedState)
view.log("MainPresenter.onCreate")}override fun onResume(a) {
super.onResume()
view.log("MainPresenter.onResume")}override fun onPause(a) {
super.onPause()
view.log("MainPresenter.onPause")}override fun onDestroy(a) {
super.onDestroy()
view.log("MainPresenter.onDestroy")}}Copy the code
Modify the MainActivity
Bind a MainActivity to a Presenter. To get a Presenter, go to @bindPresenter
@RequiresPresenter(MainPresenter::class)
class MainActivity : BaseActivity(), MainView {
@BindPresenter
private var mainPresenter: MainPresenter? = null
override fun onCreate(savedInstanceState: Bundle?). {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mainPresenter.xxx()
}
override fun log(msg: String) {
println(msg)
}
}
Copy the code
Presenter into more
@RequiresPresenter(value = [MainPresenter::class, SecondPresenter::class])
class MainActivity : BaseActivity(), MainView, SecondView {
@BindPresenter
private var mainPresenter: MainPresenter? = null
@BindPresenter
private var secondPresenter: SecondPresenter? = null
override fun log(msg: String) {
println(msg)
}
}
Copy the code
0x02 Working principle
Here’s how Damon works
Dynamic injection and assignment for Presenter
Annotations instead of manually instantiating presenters are more convenient, and state recovery is implemented in encapsulated activities to avoid duplicate Presenter creation
Will pass into the current in the interface to create a class to ReflectionPresenterFactory, through the CLS. GetAnnotation get @ RequiresPresenter annotations and save, Members of the current class annotated by @bindPresenter are also saved here
@Nullable
public static ReflectionPresenterFactory fromViewClass(Object host, Class
cls) {
RequiresPresenter annotation = cls.getAnnotation(RequiresPresenter.class);
Class<? extends MvpPresenter>[] pClass = null! = annotation ? annotation.value() :null;
if (null == pClass) {
return null;
}
List<Field> fields = new ArrayList<>();
for (Field field : cls.getDeclaredFields()) {
Annotation[] annotations = field.getDeclaredAnnotations();
if (annotations.length < 1) {
continue;
}
if (annotations[0] instanceofBindPresenter) { fields.add(field); }}return new ReflectionPresenterFactory(host, pClass, fields);
}
Copy the code
The creation of a Presenter
The above said Damon Presenter is a complete life cycle, see enclosed Activity MvpAppCompatActivity. Java
The Activity of the life cycle through the method of controlling the Presenter PresenterLifecycleDelegate to call, given its life cycle. It also overloads the onSaveInstanceState helper Presenter state recovery mechanism
public class MvpAppCompatActivity extends AppCompatActivity implements MvpView {
private static final String PRESENTER_STATE_KEY = "presenter_state";
private PresenterLifecycleDelegate mPresenterDelegate =
new PresenterLifecycleDelegate(ReflectionPresenterFactory.fromViewClass(this, getClass()));
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPresenterDelegate.onCreate(this, getIntent().getExtras(), null! = savedInstanceState ? savedInstanceState.getBundle(PRESENTER_STATE_KEY) :null);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBundle(PRESENTER_STATE_KEY, mPresenterDelegate.onSaveInstanceState());
}
@Override
public void onStart(a) {
super.onStart();
mPresenterDelegate.onStart();
}
@Override
public void onResume(a) {
super.onResume();
mPresenterDelegate.onResume();
}
@Override
public void onPause(a) {
mPresenterDelegate.onPause();
super.onPause();
}
@Override
public void onStop(a) {
mPresenterDelegate.onStop();
super.onStop();
}
@Override
public void onDestroy(a) { mPresenterDelegate.onDestroy(! isChangingConfigurations());super.onDestroy(); }}Copy the code
PresenterLifecycleDelegate
The most important of these is the hub that connects the Activity to the Presenter and controls the Presenter’s creation, recovery, and lifecycle
public class PresenterLifecycleDelegate {
private static final String PRESENTER_KEY = "presenter - ";
private static final String PRESENTER_ID_KEYS = "presenter_ids";
@Nullable
private PresenterFactory mPresenterFactory;
@Nullable
private List<? extends MvpPresenter> mPresenters;
private boolean mPresenterHasView;
public PresenterLifecycleDelegate(@Nullable PresenterFactory presenterFactory) {
this.mPresenterFactory = presenterFactory;
}
public void onCreate(MvpView view, @Nullable Bundle arguments, @Nullable Bundle savedState) {
if (mPresenterFactory == null) {
return;
}
Bundle presenterBundle = null;
if(savedState ! =null) {
presenterBundle = ParcelFn.unmarshall(ParcelFn.marshall(savedState));
}
createPresenter(presenterBundle);
if(mPresenters ! =null && !mPresenters.isEmpty()) {
mPresenterFactory.bindPresenter(mPresenters);
for (MvpPresenter presenter : mPresenters) {
//noinspection unchecked
presenter.create(view, arguments, null! = presenterBundle ? presenterBundle.getBundle(PRESENTER_KEY.concat(presenter.getClass().getSimpleName())) :null); }}}private void createPresenter(Bundle presenterBundle) {
if(presenterBundle ! =null) {
mPresenters = PresenterStorage.INSTANCE.getPresenter(presenterBundle.getStringArray(PRESENTER_ID_KEYS));
}
if (mPresenters == null) {
//noinspection ConstantConditionsmPresenters = mPresenterFactory.createPresenter(); PresenterStorage.INSTANCE.add(mPresenters); }}public void onStart(a) {
if(mPresenters ! =null && !mPresenters.isEmpty()) {
for(MvpPresenter presenter : mPresenters) { presenter.start(); }}}public Bundle onSaveInstanceState(a) {
Bundle bundle = new Bundle();
if(mPresenters ! =null && !mPresenters.isEmpty()) {
String[] ids = new String[mPresenters.size()];
for (MvpPresenter presenter : mPresenters) {
Bundle presenterBundle = new Bundle();
presenter.save(presenterBundle);
bundle.putBundle(PRESENTER_KEY.concat(presenter.getClass().getSimpleName()), presenterBundle);
ids[mPresenters.indexOf(presenter)] = PresenterStorage.INSTANCE.getId(presenter);
}
bundle.putStringArray(PRESENTER_ID_KEYS, ids);
}
return bundle;
}
public void onResume(a) {
if(mPresenters ! =null&&! mPresenters.isEmpty() && ! mPresenterHasView) {for (MvpPresenter presenter : mPresenters) {
presenter.resume();
}
mPresenterHasView = true; }}public void onPause(a) {
if(mPresenters ! =null && !mPresenters.isEmpty() && mPresenterHasView) {
for (MvpPresenter presenter : mPresenters) {
presenter.pause();
}
mPresenterHasView = false; }}public void onStop(a) {
if(mPresenters ! =null && !mPresenters.isEmpty()) {
for(MvpPresenter presenter : mPresenters) { presenter.stop(); }}}public void onDestroy(boolean isFinal) {
if(isFinal && mPresenters ! =null && !mPresenters.isEmpty()) {
for (MvpPresenter presenter : mPresenters) {
presenter.destroy();
}
mPresenters.clear();
mPresenters = null; }}}Copy the code
0x03 is at the end
Presenterstorage.java implements presenterStorage.java. Presenterstorage.java implements presenterStorage.java
The Multi Presenter version of Damon is the 2.0.0-alpha version of the new variant, and has not undergone extensive testing. Damon, version 1.1.0 of Single Presenter, has been stable in development environments for a long time
Finally, the link to the project github.com/izyhang/Dam…
Welcome to point out the shortcomings, leave your opinion ~