I know probably there is no clear answer for this question.
But I would like to know Your opinions and maybe new ideas.
I'm wondering which of the following options is the best/right/correct way to build the app-level Dagger Component in Application class.
Example 1:
public class MyApp extends Application {
private NetComponent mNetComponent;
#Override
public void onCreate() {
super.onCreate();
mNetComponent = DaggerNetComponent.builder()
.appModule(new AppModule(this))
.netModule(new NetModule("https://api.github.com"))
.build();
}
public NetComponent getNetComponent() {
return mNetComponent;
}
}
Usage:
((MyApp) getApplication()).getNetComponent().inject(this);
Example 2:
class MyApplication extends Application {
private static MyComponent component;
#Override
void onCreate() {
component = DaggerMyComponent.builder()
.contextModule(new ContextModule(getApplicationContext()))
.build();
}
public static MyComponent getMyComponent() {
return component;
}
}
Usage:
MyApplication.getMyComponent().inject(this)
Example 3:
class CustomApplication: Application() {
lateinit var component: SingletonComponent
private set
override fun onCreate() {
super.onCreate()
INSTANCE = this
component = DaggerSingletonComponent.builder()
.contextModule(ContextModule(this))
.build()
}
companion object {
private var INSTANCE: CustomApplication? = null
#JvmStatic
fun get(): CustomApplication = INSTANCE!!
}
}
Then:
class Injector private constructor() {
companion object {
#JvmStatic
fun get() : SingletonComponent = CustomApplication.get().component
}
}
Usage:
Injector.get().catRepository()
Example 4:
class App : Application() {
var repositoryComponent: RepositoryComponent? = null
var appComponent: AppComponent? = null
override fun onCreate() {
super.onCreate()
instance = this
appComponent = DaggerAppComponent.builder().application(this).build()
repositoryComponent = DaggerRepositoryComponent.builder().build()
}
companion object {
private var instance: App? = null
fun get(): App {
return instance!!
}
}
}
Usage:
App.get().repositoryComponent!!.inject(this)
What do you think about this? Is there any better / cleaner way to do this? Maybe provided examples are fine? Or maybe just one of them?
I will be grateful for any good examples / tips / advices.
Thanks!
Okay, no one answered in 5 days so it's my turn, despite my bias :p
Option #1
((MyApp) getApplication()).getNetComponent().inject(this);
It's an "ok" version of doing things, except for two things.
First, the name. NetComponent isn't really for networking, it's the app-global singleton component, so it should be either called SingletonComponent or AppComponent. But naming it NetComponent is disingenuous, it's typically responsible for everything else too.
Second problem is that you need a reference to Context to access your dependency graph, making Context actually be a dependency rather than it being provided to you.
Option #2
MyApplication.getMyComponent().inject(this)
This is a perfectly fine way of doing things, but you need to know that to reach your object graph, you need to access the static method of MyApplication.
Option #3
Injector.get().inject(this)
Internally, this solution actually just calls over to get the app component, public static AppComponent get() { return MyApplication.getInstance().getComponent(); }
The benefit is that getComponent() is exposed via an instance method of Application, so it could be theoretically swapped out.
Also, invoking a method on something called Injector.get() is more obviously an "injector" than, well, an application class.
As for whether you use .catRepository() or .inject(this), it's up to you; but I personally prefer calling the provision methods to get the deps in Activity/Fragment, because listing the member-injection targets adds a lot of clutter to the component over time.
4.)
App.get().repositoryComponent!!.inject(this)
You can ditch the !! if repositoryComponent is a lateinit var.
Having two components for the same scope (and therefore two different object graphs) will only cause trouble, out of all of the options, this is the worst.
In my opinion, the 3rd option is the best. Technically it's the same as option #2 with an additional "indirection" through the instance method of Application that actually returns the component.
Related
I'm a new one in android dev, so I have an app which contain viewPager with 2 UI fragments and 1 nonUIFragment in which operations are performed (i used "setRetainInstance(true)", it deprecated, but i must use it). In this nonUIFragment i have Handler which accepts messages from operations started with ExecutorServices.
But now my task is test this app with Mockito and i'm totaly confused.
Mentor said "you have to mock the operation that produces the result, is performed in a nonUIFragment, and its result is stored in a collection."
How must look this test, I can't create spy() class NonUIFragment and use real methods because of "Method getMainLooper in android.os.Looper not mocked."
All of my methods are void, they don't returne something, how can i trace this chain.
NonUIFragment.java
private NonUIToActivityInterface nonUIInterface;
private final Map<DefOperandTags, HashMap<DefOperationTags, String>> allResultsMap
= new HashMap<>();
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
//Handler pass result to here
public void passAndSaveResult(DefOperandTags operandTag, DefOperationTags operationTag, String result) {
allResultsMap.get(operandTag)).put(operationTag, result);
}
private final Handler handler = new Handler(Looper.getMainLooper()) {
public void handleMessage(Message msg) {
if (msg.what != null)
passAndSaveResult(defOperandTags, defOperationTag, msg.obj.toString());
};
OneOfOperation.java (add value to the List)
public class AddToStartList extends Operation {
public AddToStartList(List list, DefOperationTags operationTag) {
super(list);
key = operationTag;
}
#Override
public void operation(Object collection) {
((List)collection).add(0, "123");
}
So, how can I implement what my mentor said?
This is going to be tricky, because your Android testing library has no implementations, and static methods are generally more difficult to mock safely and effectively.
Recent versions of Mockito have added the ability to mock static methods without using another library like PowerMock, so the first choice would be something like that. If at all possible, use mockStatic on Looper::getMainLooper to mock.
Another solution is to add some indirection, giving you a testing seam:
public class NonUIFragment extends Fragment {
/** Visible for testing. */
static Looper overrideLooper;
// ...
private final Handler handler = new Handler(
overrideLooper != null ? overrideLooper : Looper.getMainLooper()) {
/* ... */
};
}
Finally, if you find yourself doing this kind of mock a lot, you can consider a library like Robolectric. Using Robolectric you could simulate the looper with a ShadowLooper, which would let you remote-control it, while using Mockito for any classes your team has written. This would prevent you from having to mock a realistic Looper for every test, for instance.
I decided to split the last part of that question here into a new question here: https://softwareengineering.stackexchange.com/questions/411738/extension-of-classes-where-to-put-behaviour-how-much-direct-access-is-allowe
If i have a lib and i want to use it, i wrote mostly a own class. This class has one method. In that there is the code how to instantiate the lib/framework. Sometimes there are a few more methods, with them i not only instantiate the class but use it. For example if i want to start a http-server i have there a start-method.
class Container
{
TheLib theLib;
public void init() //or a constructor
{
//some init of the theLib
}
public void start() //
{
theLib.doSomething(...)
theLib.doSomethingmore(...);
theLib.start(...);
}
//important!
public TheLib getTheLib()
{
return this.theLib; //after i started configured it and so on, i want of course use all methods,
which the lib have in some other parts in my application
}
}
But it seems not to be the best solution.
Are there any better solutions, that OO is?
Often i also use only one method, a own class for this seems to be here a big overhead?
Exposing the lib breaks encapsulation? Tell-Dont-Ask is also violated?
Everything depend on what you actually need or how you have access to your 'the lib' instance.
public class Container {
private TheLib theLib;
/* #1: Do you already created the instance before? */
public Container(TheLib theLib) {
this.theLib = theLib;
}
/* #2: Do you need to created the instance each time? */
public Container() {
this.theLib = new TheLib();
}
public void start() {
theLib.doSomething(...)
theLib.doSomethingmore(...);
theLib.start(...);
}
public TheLib getTheLib() {
return this.theLib;
}
public static void main(String[] args) {
/* #1 */
TheLib theLib = ...;
Container container = new Container(theLib);
/* #2 */
Container container = new Container();
/* Continue the flow of your program */
container.start();
container.getTheLib().doSomethingEvenMore();
}
}
Or maybe you actually need only one instance of your 'Container' class. In this case, you should look on how to make a singleton: Java Singleton and Synchronization
Anwser: Often i also use only one method, a own class for this seems to be here a big overhead?
Well, in Java, you cannot do formal programming like in C, so everything line of code that you write, or will be using, has to be in a class of some sort.
If your piece of code is small and don't really need an object, static function might do the work.
My installer is storing some information in a singleton class during the installation process. Now, I have noticed that in elevated action, the singleton class does not have the same instance. So far, I have not found any workaround/solution so that they share the same instance. So, I have decided to make sure that if anyone wants to get an instance of the singleton, they must call from an unelevated environment. Let's say the singleton looks like the following:
public class InvestigatorReport {
private final List<Report> reports = new ArrayList<>();
private final static InvestigatorReport INSTANCE = new InvestigatorReport();
private InvestigatorReport() {
MyLogger.logInfo(getClass(), "initiating...");
}
public static InvestigatorReport getInstance(Context context) {
if (context.hasBeenElevated()) {
throw new IllegalAccessError(
"this method must be called unelevated!");
}
return INSTANCE;
}
private boolean addReport(Report report) {
return reports.add(report);
}
}
But the problem is, There are some cases when I have to call this add report from an action class that is elevated. So I have tried the following in my elevated action class:
if (context.hasBeenElevated()) {
return (Boolean) context.runUnelevated(new RemoteCallable() {
#Override
public Serializable execute() {
return getInstance(context).addReport(report);
}
});
}
But, as you can see if I am passing the same context object from the elevated action class to the RemoteCallable class so, even though I am running the class unelevated, the context.hasBeenElevated() still returns true.
Is there any other way that I can check the elevation level other than the context? If you have any other better idea on preventing anyone from calling the singleton getInstance() method, I am all ears.
I would use a different pattern. Make all methods of your singleton static and wrap the data access with runUnelevated calls:
public static boolean addReport(Report report, Context context) {
context.runUnelevated(new RemoteCallable() {
#Override
public Serializable execute() {
InvestigatorReport.reports.add(report);
return null;
}
});
}
In that way, you can call the methods from both elevated and unelevated code without having to check anything at the call site.
I'm doing some big refactoring operations relative to some performance improvements in an android app which is using a class with lot of static variables and even static activity references which are then use through the app ! So I was looking for some best practices in Android to store data and give to these data a global access in my app.
First I removed all the activity references to avoid any memory leak, but I'm still looking to know what is the best practice regarding static variables which need to be used anywhere in the android app.
I read many times (example1, exemple2) : using static variables is not necessary a good practices and it's better/cleaner to use one singleton class with getter and setter to have access to my global variables whatever the activity where I am. So what I've started to think is a class which could looks like this one :
public class AppSingleton extends Application {
private static AppSingleton appInstance;
// different stored data, which could be relative to some settings ..
private String setting1;
private String setting2;
private AppSingleton() {
super();
appInstance = new AppSingleton();
}
public static AppSingleton getAppInstance() {
if (appInstance == null) {
appInstance = new AppSingleton();
}
return appInstance;
}
// Getter and Setter for global access
public String getSetting1() {return setting1;}
public void setSetting1(String setting1) {this.setting1 = setting1;}
public String getSetting2() {return setting2;}
public void setSetting2(String setting2) {this.setting2 = setting2;}
}
Then I can use for example :
// Get the application instance
AppSingleton appS = (App) getApplication();
// Call a custom application method
appS.customAppMethod();
// Call a custom method in my App singleton
AppSingleton.getInstance().customAppSingletonMethod();
// Read the value of a variable in my App singleton
String var = AppSingleton.getInstance().getCustomVariable;
For me AppSingleton sounds good because this singleton which restrics ths instantiation of this class to one object, also this class is not destroyed until there are any undestroyed Activity in the application so it means I can keep my global data in the current lifecycle of my app for example from a 'Log in'. But also I can maintain the state of my global variables from my getters/setters.
But then I also had a look on the official android documentation about Performance Tips which say it's good to use static variable it's faster and don't forget to avoid internal getter and setter it's too expansive !
I'm a bit confused about all of these and I'm really keen to learn more about that topic. What is the best practices about using one class to provide an access to some variables which are needed in different part of my code ? Is the class above AppSingeleton is something which could be interesting to use in terms of architecture and performance ?
Is it a good idea to use a singleton pattern for managing global variables in android ?
those lines are completely wrong on your code:
private AppSingleton() {
super();
appInstance = new AppSingleton();
}
public static AppSingleton getAppInstance() {
if (appInstance == null) {
appInstance = new AppSingleton();
}
return appInstance;
}
you cannot instantiate new Application, the Android framework instantiates it. Change to this:
private AppSingleton() {
super();
appInstance = this; // keep ref to this application instance
}
public static AppSingleton getAppInstance() {
return appInstance;
}
Regarding the accessing of global variables. I believe it's more organized to have those singletons somewhere else on your application. The application class have different responsibilities you should not overload it with different tasks. That's OO clean coding.
Also, sometimes there's not that much reason in an Android app to have getters/setters for everything, because u don't need as much access control as in bigger projects. But this should be considered case-by-case about the necessity and not be used a general rule.
So you could for example have it like:
public class Globals {
private static final Globals instance = new Globals();
public static Globals get() { return instance; }
public String value1 = "Hello"
public int value2 = 42;
}
then on your code call as needed:
Log.d(TAG, Globals.get().value1);
Globals.get().value1 = "World";
Log.d(TAG, Globals.get().value1);
Log.d(TAG, "Value2 = " + Globals.get().value2);
Could some explain me something. Here is some scenario.
Let assume i have a class template and use Gin/Guice in the app.
#Singleton
public class Template extends Compose
{
private HorizontalPanel header;
private HorizontalPanel content;
private VerticalPanel menu;
public Template()
{
this.add(initHeader());
this.add(initMenu());
this.add(initContent());
}
public void setContent(Widget widget)
{
content.clear();
content.add(widget);
}
.............
......
}
and in the entry class
........
public void onModuleLoad()
{
RootPanel.get().add(new Template());
....
}
Every time i need to reload the content i do..
For example
HorizontalPanel hp = new HorizontalPanel();
hp.add ....
...
Template template = injector.getTemplate(); // return singleton instance using gin
template.setContent(hp)
and so on..
So, Template is singleton and as far as i know singleton instance is one per VM meaning shared by entire application, right?
Template class has header, menu and content, the idea is to reload only the content part as cleaning and adding widgets.
But is this a good approach?
For example, could we have a situation like user "A" setContent(widgetA) ,but in the same time user "B" use method setContent(widgetB) ,so what is going to happen here?
Thanks, if anyone could share with me a good approach eventually and comment that one.
Regards
#Singleton is scoped to the Ginjector instance (yes, if you GWT.create() your GInjector twice, you'll get two "singletons"). There's no single mean GIN can somehow "intercept" your new Template() in onModuleLoad, so injector.getTemplate() will return a distinct template instance.
(this is totally different from the "singleton code anti-pattern" that Stein talks about, using static state)
There's no magic: GIN is a code generator, it only writes code that you could have typed by hand.
As for your other questions:
You client code obviously run on the client, i.e. on the browser. There's one "application instance" per browser tab/window displaying your app. There's no "user A" and "user B" at the same time.
JavaScript is single-threaded, so you don't have to fear for concurrent accesses either.
I have injected the class with common RPC code for our app.
Here's how:
#Singleton
public class SomeService {
/** The real service. */
private static final RealServiceAsync realService;
...
}
Our Gin module:
public class MyGinModule extends AbstractGinModule {
#Override
protected void configure() {
bind( SomeService .class ).in(Singleton.class);
...
...
}
}
And it's injected as singleton as follows:
public class ApplicationInfoPresenter {
#Inject
private SomeService service;
...
...
}
I'm pretty sure the annotation is ignored by the GWT compiler.
When I need a Singleton in gwt i just create a class with a private/protected constructor, and a private static NameOfSingletonClass instance; and a getInstance() method that initializes the instance if null and returns the instance.