Should I create BaseActivity/Presenter and View in Mosby MvP concept? - android

I'm trying to understand concept of MvP design pattern. I mean, I get it, its quite easy. The main problem is optimal implementation. I tried to make my own BaseActivity, BasePresenter and BaseView just to extract part of a joint from all of my activities, I've done this this way:
BaseActivity
public abstract class BaseActivity<T extends BasePresenter<? extends IBaseView>> extends FragmentActivity implements IBaseView {
protected T presenter;
private ActivityConfig activityConfig;
#Override
final protected void onCreate(Bundle savedInstanceState) {
activityConfig = getConfig();
super.onCreate(savedInstanceState);
presenter = createPresenter();
setContentView();
initLibraries();
prepareView(savedInstanceState);
addFragments();
}
protected abstract ActivityConfig getConfig();
protected abstract T createPresenter();
protected abstract void prepareView(Bundle savedInstanceState);
protected abstract void addFragments();
private void setContentView(){
View root = View.inflate(this, activityConfig.layoutId, null);
setContentView(root);
}
private void initLibraries() {
ButterKnife.bind(this);
Timber.plant(new Timber.DebugTree());
}
#Override
public BaseActivity getCurrentContext() {
return this;
}
#Override
public T getPresenter() {
return presenter;
}
}
BasePresenter
public abstract class BasePresenter<T extends IBaseView> {
public abstract void loadData(boolean refresh);
}
BaseView
public interface IBaseView {
BaseActivity getCurrentContext();
BasePresenter getPresenter();
}
It works fine but I feel like this is bad designed so I want to use Mosby instead. The problem is that all of the tutorials don't touch aspect of base classes, they just use Mosby's ones as base (with is bad I suppose? couse I have to duplicate my code (Butterknife.bind() for example). So can you guys give me some good designed quickstart classes for Mosby MVP or give me some tips how should I divide my project? Thanks!

So I see two possibilities:
You could extend from Mosby's MvpActivity as your base class and add your staff like initView(), initLibraries() etc. So that BaseActivity<P extends BasePresenter<? extends BaseView>> extends MvpActivity<P> implements BaseView. Then MyFooActivity extends BaseActivity<FooPresenter>. So you include Butterknife once in BaseActivity and it should work. However, you might have to duplicate that code like Butterknife.bind()` for Fragments, as Activity and Fragments obviously don't have the same super class. I will show you how to solve that above.
Do the other way around: Integrate Mosby's functionality into your BaseActivity. Mosby is build with the principle of "favor composition over inheritance". So what does this actually mean? Mosby offers a ActivityMvpDelegate. As the name already suggests this delegate does all the work of instantiating Presenter etc. But instead of inheriting from MvpActivity you use this delegate and invoke the corresponding delegate methods. Actually Mosby's MvpActivity is doing exactly that if you have a look at the source code. So instead of extending from Mosby'sMvpActivity you simply use MvpActivityDelegate in your BaseActivity.
So what about duplicating code like Butterknife.bind() i.e. in Activity and Fragment. Well, Mosby can share his code like instantiating Presenter etc. between Activity and Fragment because both use the mosby delegate.
So you could apply the same principle: You could put the shared code into a delegate and call the delegate from both, activity and fragments.
The question is: is it worth i.e. Butterknife.bind() is just one single call. You would also have to make one single call yourDelegate.doSomething() ...
But if you have to reuse "critical code" between activity and fragments then favor composition like Mosby does.
If you know that you are only working with Activites then extending from Mosby's MvpActivity would also be a good option as described in 1. solution.

I just wanted to add to sockeqwe's first answer.
It is perfectly fine to create your own base class where it makes sense. It's also pretty straightforward.
For example, I needed to create a base Fragment with some default behavior. All you need to do is duplicate the base generic type signature and pass it along to the base class.
For example:
public abstract class MyBaseFragment<V extends MvpView, P extends MvpPresenter<V>> extends MvpFragment<V, P>

Related

Can I use two viewmodel for one fragment?

I am using MVVM in my Android project. I have Create and Edit fragments. This 2 fragments have largely the same function. If I write functions which they have the same function in a common view model, Can I use the common viewmodel with own viewmodel of fragments. For example Can I use like below;
CommonViewModel(){
void selectPriority()
.
.
.
otherthings...}
CreateViewModel(){
LiveData<CommonViewModel> cvm;
.
.
.
otherthings...}
EditViewModel(){
LiveData<CommonViewModel> cvm;
.
.
.
otherthings...}
Instead of this
CreateViewModel(){
void selectPriority()
.
.
.
otherthings...}
EditViewModel(){
void selectPriority()
.
.
.
otherthings...}
Or can you suggest to me different way which I can use?
You can do this through Inheritance,Make a common view model and extend it in edit and creat view model, like
class CreatEditViewModel{
public void selectPriority(){
//to something....
}
public void other(){
//to something....
}
}
class CreateViewModel extends CreatEditViewModel{
}
class EditViewModel extends CreatEditViewModel{
}
You can not put these logic in BaseViewModel because BaseViewModel is extended by all ViewModel.
You can with the help of Inheritance, create a base class and put all the common functionality there, then create two more classes which inherit the base class. this way you can achieve what you want.
e.g.
class BaseViewModel{
public void selectPriority(){
}
public void other(){
}
}
class CreateViewModel extends BaseViewModel{
}
class EditViewModel extends BaseViewModel{
}
With the above example, CreateViewModel and EditViewModel both inherit BaseViewModel hence they have access to all the functions of BaseViewModel class. All the common methods will be available wit BaseViewModel. The methods you would create in CreateViewModel and EditViewModel will not be visible to each other.

Dagger 2 - how to inject only to base activity/fragment

I am studying a Dagger 2 from many sources such as this one: http://fernandocejas.com/2015/04/11/tasting-dagger-2-on-android/
but I still haven't found an answer to my question.
I work on quite complex application with tens of fragments and several activities in which I want to use DI (dagger 2). For all of those fragments and activities I have one BaseActivity and one BaseFragment. However, as far as I read and tried, in order to use #Inject in my let's say MainActivity, I have to specify it in Component interface and also invoke getApplicationComponent().inject(this) in onCreate method. When I do this for BaseActivity only, #Inject annotated fields in MainActivity is never injected. And what is even worse, I do not find out about that until that specific part of code is executed and NPE is thrown.
So far it is a deal breaker for me, because this can be source of many crashes. I would need to specify tens of fragments and activities in Component interface and not forget to call inject in each onCreate method.
I would be very glad to hear any solution to this since I would really like to use DI..
code example:
#Singleton
#Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
void inject(BaseActivity baseActivity);
Analytics analytics();
}
public class BaseActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.getApplicationComponent().inject(this);
}
}
public class MainActivity extends BaseActivity {
#Inject
Analytics analytics;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
analytics.log("event1"); // THROWS NPE!
}
}
You can not inject properties in your subclass by injecting the super (since dagger2 works at compile time and there is no way to dynamically check subclasses for annotated properties.)
You can move analytics up to the super, then it will be injected there. To inject annotated fields in your subclass you will have to call the injection there again.
You can make an abstract method in your baseclass e.g. inject(App app)where you just handle the injection. That way you can't 'miss' it.
As stated in the official documentation:
While a members-injection method for a type will accept instances of its subtypes, only Inject-annotated members of the parameter type and its supertypes will be injected; members of subtypes will not.
move the
#Inject
Analytics analytics;
to your BaseActivity class, the Analytics object is initialized in the superclass and is inherited by sub-classes automatically, therefor u wouldn't get null any more.
public class MainActivity extends BaseActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
analytics.log("event1");
} }

can a singleton class extend Activity

I am using a singleton class to store global variables for the entire project. Also, to host some common functions which several classes/Activities may use, such as launching an alertBuilder window. But in order to do that... I need my singleton to extend Activity like this:
public class dataBaseObject extends Activity {
I tried to extend application, but that won't allow me to do this:
View view = context.getLayoutInflater().inflate(layoutType, null);
therefore, can someone tell me if there are any hidden pitfalls of extending Activity for a singleton ?
It doesn't make sense for an Activity class to be a singleton, because instances of Activity are instantiated by the android system.
What you can do is make an abstract class that extends Activity, like this
public abstract class AbstractActivity extends Activity {
public static final int EXAMPLE_CONSTANT = 345;
public final void exampleMethod() {
...
}
// This may not be needed
#Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
....
}
}
Then you can make all of your activity classes extend AbstractActivity. You do not need to declare an abstract class like this in manifest.xml.
An alternative solution is to make all of your utility methods have a parameter that is an Activity or a Context and pass this to these methods.

Common Code for Activity and PreferenceActivity

I'm using common code in my Activity like this:
abstract class CommonCode extends Activity {
//Common Code here...
}
then in my "Activity" I extend CommonCode instead of Activity and it all works fine.
My problem arise when I try to use commoncode in a PreferenceActivity, I tried:
abstract class CommonCode extends Activity {
class CommonCodePreferences extends PreferenceActivity {
}
//Common Code here...
}
but it isn't right.
How can I do it?
May I suggest that you prefer composition over inheritance and do something like this:
abstract class CommonCode {
Activity parent;
public CommonCode(Activity activity) {
parent = activity;
}
}
class MyActivity extends Activity {
CommonCode commonCode;
public MyActivity() {
commonCode = new CommonCode(this);
}
}
This is a little more code to write in each activity, but it has a lot of advantages:
It can also easily handle PreferenceActivity and other classes
It is easier to test and mock
I usually have one each since you can't mess with the existing hierarchy of the base classes.
For example, I have an ActivityBase, ServiceBase, ListActivityBase, etc. If you want to have common code that they all use, I would suggest using composition - each of your base classes has a single instance of your CommonCode class or something to that effect. Another possibility is to use static methods and/or use a custom Application class (requires declaring the custom Application class in the manifest in the name attribute of the application element)

Activity interceptor

Is there any way in android to intercept activity method calls (just the standart ones, like "onStart. onCreate")?
I have a lot of functionality that must be present in every activity in my app, and (since it uses different types of activities (List, Preferences)) the only way to do it is to create my custom extensions for every activity class, which sucks :(
P.S. I use roboguice, but since Dalvik doesn't support code generation at runtime, I guess it doesn't help much.
P.S.S. I thought about using AspectJ, but it's too much of a hassle since it requires a lot of complications (ant's build.xml and all that junk)
The roboguice 1.1.1 release includes some basic event support for components injected into a context. See http://code.google.com/p/roboguice/wiki/Events for more info.
For Example:
#ContextScoped
public class MyObserver {
void handleOnCreate(#Observes OnCreatedEvent e) {
Log.i("MyTag", "onCreated");
}
}
public class MyActivity extends RoboActivity {
#Inject MyObserver observer; // injecting the component here will cause auto-wiring of the handleOnCreate method in the component.
protected void onCreate(Bundle state) {
super.onCreate(state); /* observer.handleOnCreate() will be invoked here */
}
}
You could delegate all the repetitive work to another class that would be embedded in your other activities. This way you limit the repetitive work to creating this object and calling its onCreate, onDestroy methods.
class MyActivityDelegate {
MyActivityDelegate(Activity a) {}
public void onCreate(Bundle savedInstanceState) {}
public void onDestroy() {}
}
class MyActivity extends ListActivity {
MyActivityDelegate commonStuff;
public MyActivity() {
commonStuff = MyActivityDelegate(this);
}
public onCreate(Bundle savedInstanceState) {
commonStuff.onCreate(savedInstanceState);
// ...
}
}
This minimalises the hassle and factorises all common methods and members of your activities. The other way to do it is to subclasse all the API's XXXActivty classes :(
Take a look at http://code.google.com/p/android-method-interceptor/, it uses Java Proxies.

Categories

Resources