The following is my situation:
I have a library project and a project based on it. Now in the library I have two classes A and B, whereby A uses B. In the project using the library, I have another class B, which should override the class B from the library.
But every time class A makes a call, it ends up in the class B from the library.
How can I tell Android that class B from my project should be used INSTEAD of class B from the library?
That does not work with the current layout. You have to use the strategy pattern. In your library define LibA with a constructor that takes a object of type LibB in the constructor:
class LibA{
LibB b;
public LibA(LibB b)
this.b = b;
}
}
Then you can override LibB in your project and create LibA with the class that extends LibB:
class ProjectB extends LibB{
}
LibA a = new LibA(new ProjectB());
Answer to Turbos question:
You want to start Project-Activities from your Library. So then move the code that creates the Intent into your Projects, because only in your project you know the type or name of the Activity to be started.
The solution you mentioned in your comment (here) creates the Intent in the library project, by guessing the name of the Activity that should be started. There is nothing really wrong with that but it's not an elegant solution. You can only start Activities that follow that special naming scheme. And because of that you cannot start arbitrary Activities that are visible in your projects like Activities from other libraries, where you cannot change the name of the class.
To move the Intent creation into your libraries you can i.e. use the strategy, template or factory-method pattern. See Design Patterns on Wikipedia for even more (creational) patterns that match your library design.
A simple solution would be:
Create an abstract LibraryActivity and extend your ProjectActivities from it. The LibraryActivity defines an abstract method that returns the Intent. The implementation of that abstract method is done in your ProjectActivities.
abstract class LibActivity{
private void doSomething(){
//Library does something
//and finally calls createIntent() to start an project specific Activity
startActivity(this.createIntent());
}
protected abstract Intent createIntent();
}
class ProjectActivity extends LibActivity{
protected Intent createIntent(){
return new Intent(ProjectActivity.this, AnyActivityYouWant.class);
}
}
I dont know if this is the best way to do it but i do it this way;
I create a class A from the project and this class extends form the library project
public class A extends libraryProject_A{
//here i put all methods from the new class B to override methods from library class B
}
As I see from your comment you have class A that uses class B
But class B should be different according to which project you're using.
I think you need to create a base class say BaseB that will be an instance variable in class A, and you might have a setter and getter for this Or you can make it a parameter passed to the constructor of class A. and when instantiating A you should choose which one to use.
Let's have a look at code
Class A {
private BaseB b;
public A(BaseB aB) {
b = aB;
}
public void set(BaseB aB) {
b = aB;
}
public BaseB get() {
return b;
}
}
interface BaseB {
}
// in the library have this
class B implements BaseB {
}
// in your project have the other implementation
class B implements BaseB {
}
// you can then instantiate A like this
A a = new A(new B());
// you can choose which one to use here in the previous statement.
Related
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>
Well, I'm at a dilemma here. I made my own class that uses the Bluetooth class from android but I'm not sure where to put it. Extending the android Bluetooth class seems like a good idea but I need to override the onActivityResult() which is only available to an activity class. So, where would I put my class so that I have access to onActivityResult() (keeping in mind the idea here is to use as few dependencies as possible)?
In other words, I want to move the Bluetooth code from the main activity to a separate class.
You should to use separate file for each class. You can create a folder "engine". For example: com.mycorp.myapp.engine. You can get access to onActivityResult() very simple. For example: MainActivity.onActivityResult(). Note: function should be public.
Or you can pass your activity to your CustomBluetooth's constructor.
public class CustomBluetooth {
private Activity mActivity;
/* Constructor */
public CustomBluetooth (Activity pActivity ) {
super();
this.mActivity = pActivity;
}
/* Your functions */
public int getResult() {
return this.mActivity.onActivityResult();
}
}
Alex. P.S. Sorry for my English:)
Add an interface to your Bluetooth class and implement the interface in your activity.
In my Android app project, I am using RoboGuice .
In my project, I have a singleton Class A:
#ContextSingleton
public class A{
…
public void method1(){…}
}
Then, I have another class B which needs an instance of A, so, in RoboGuice way, I normally declare the instance of A inside class B with injection :
public class B {
#Inject private A a ;
public void action(){
a.method1(); // call method1() of class A's instance
}
}
Sometimes, I got NullPointerException for the instance of A declared in class B. I just want to verify one concept of RoboGuice:
Is it so that in order to inject an instance of a custom class (e.g. class A) in class B, the class B has to be either injected in RoboActivity or be injected into another class (e.g. Class C) which has injected in RoboActivity?
You probably instantiate B somewhere yourself (new B()) and then you need to call the Injector manually.
When RoboGuice creates the instance B it will automatically inject the dependency A, but when you create B yourself, RoboGuice wil not know about it and you have to call the inject code yourself. This can be done by calling:
RoboInjector injector = RoboGuice.getInjector(context);
injector.injectMembersWithoutViews(yourObjectB);
In my android project, I have many activities and some of them already extend other stuff like map activity or BroadcastReceiver.
How do I create a function that I can call from any activity, because I don't want to have to repeat any code in multiple activities.
thanks.
If I have useful functions that perform little helpful tasks that I want to invoke from several Activities, I create a class called Util and park them in there. I make them static so that I don't need to allocate any objects.
Here is an example of part of one such class I wrote:
public final class Util {
public final static int KIBI = 1024;
public final static int BYTE = 1;
public final static int KIBIBYTE = KIBI * BYTE;
/**
* Private constructor to prevent instantiation
*/
private Util() {}
public static String getTimeStampNow() {
Time time = new Time();
time.setToNow();
return time.format3339(false);
}
}
To use these constants and methods, I can access them from the class name, rather than any object:
int fileSize = 10 * Util.KIBIBYTE;
String timestamp = Util.getTimeStampNow();
There's more to the class than this, but you get the idea.
You can extend the Application class, then in your activities call the getApplication method and cast it to your application class in order to call the method.
You do this by creating a class that extends android.app.Application:
package your.package.name.here;
import android.app.Application;
public class MyApplication extends Application {
public void doSomething(){
//Do something here
}
}
In your manifest you must then find the tag and add the android:name="MyApplication" attribute.
In your activity class you can then call the function by doing:
((MyApplication)getApplication()).doSomething();
There are other ways of doing something similar, but this is one of the ways. The documentation even states that a static singleton is a better choice in most cases. The Application documentation is available at: http://developer.android.com/reference/android/app/Application.html
You could create a static method or an object that contains this method.
You can create a class extending Activity, and then make sure your real activities are subclasses of that activity, instead of the usual built-in one. Simply define your common code in this parent activity.
Shachar
Create a new Java class BaseActivity with abstract Modifiers and extends it with AppCompatActivity.
Move all your methods under Java class BaseActivity.
package com.example.madbox;
public abstract class BaseActivity extends AppCompatActivity {
protected void YourClass() {
}
}
Extends your Activities with BaseActivity but not AppCompatActivity.
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)