In the RxAndroidBle sample application, the Application class is:
public class SampleApplication extends Application
private RxBleClient rxBleClient;
/**
* In practise you will use some kind of dependency injection pattern.
*/
public static RxBleClient getRxBleClient(Context context) {
SampleApplication application = (SampleApplication) context.getApplicationContext();
return application.rxBleClient;
}
#Override
public void onCreate() {
super.onCreate();
rxBleClient = RxBleClient.create(this);
RxBleClient.setLogLevel(RxBleLog.DEBUG);
}
}
Since we are guaranteed that there will only be one instance of Application, and we only want one instance of RxBleClient, isn't it simpler to write:
public class SampleApplication extends Application {
private static RxBleClient rxBleClient;
public static RxBleClient getRxBleClient() {
return rxBleClient;
}
#Override
public void onCreate() {
super.onCreate();
rxBleClient = RxBleClient.create(this);
RxBleClient.setLogLevel(RxBleLog.DEBUG);
}
}
What is the benefit of the more complex approach?
And what is meant by "some kind of dependency injection pattern"? Could we see an example? Again, what is the benefit?
As Marcos Vasconcelos said, the first approach could be slightly easier to test though it is not a good design anyway.
Dependency injection is a way to obtain a testable code which one could throughly test by (for instance) providing (mocked) dependencies at the construction time.
To see examples of dependency injection you can go to the sources of RxAndroidBle and check out how the classes are designed.
An example could be RxBleConnectionImpl class which has quite a lot of dependencies that are injected. Thanks to that it was possible to create extensive test suite for it.
RxAndroidBle sample application was written as a sample that is easy to comprehend. It does not necessarily follows the best patterns as these are not always easy to follow. The main goal of the sample is to show the usage of the library API.
Related
I'm using Room to implement database, code for working with database is located into Repository, to get instance of database Repository needs Application as class atribute, I want to get instance of Repository in class that extends IntentService and in class that extends Worker class, now, they don't need Application as atribute but to be able to use Repostiory into them I must add it, is this good programming practice? Maybe some other soluction?
public class SunshineSyncIntentService extends IntentService {
private Application mApplication;
public SunshineSyncIntentService(#NotNull Application application) {
super("SunshineSyncIntentService");
mApplication = application;
}
#Override
protected void onHandleIntent(Intent intent) {
SunshineSyncTask.syncWeather(mApplication);
}
}
In this case, is not a bad practice. But I rather use some dependency injection as a more robust solution. You can take a look on Dagger or Koin (for Kotlin).
I've stumpled upon an Android Application Class which implements the Singleton pattern and bind a static object to it.
public class App extends Application
{
public static BigObject myObj;
private static App instance;
public static App getInstance()
{
return instance;
}
#Override
public void onCreate() {
super.onCreate();
instance = this;
myObj = new BigObject(this);
}
}
Are there any problems with this implementation, regarding performance, memory leaks or maybe Exceptions, when getInstance().myObj.something() is called form BroadcastReceiver or Service?
The only drawback I see is somewhat ugly code, using dependency injection would be better. I don't know, but if OS guarantees that all other components will be launched after Application::onCreate than there is no issues. Even non-main threads will not cache value of bigObject. But if you want set value of bigObject after onCreate, or it's creation takes long time you can face issues with data racing or slow startup.
I don't see any problems with this implementation. The Application object is basically a singleton.
TL;DR;
Is it acceptable for a class to depend on the ObjectGraph itself?
I need this because I need to inject dependencies on some objects that I load at runtime - at a time that is disconnected from the point at which the ObjectGraph is initialized. Here is an example that illustrates how I use ServiceLoader framework to load concrete implementation classes of a Service at runtime, and then inject dependencies into the loaded implementation classes.
interface Plugin {
void doSomething();
}
class AwesomePlugin implements plugin {
#Inject DependencyOne dependencyOne;
#Inject DependencyTwo dependencyTwo;
void doSomething(){
// ...some implementation...
}
}
class PluginEngine{
public void start(){
ServiceLoader<Plugin> pluginLoader = ServiceLoader.load(Plugin.class);
for(Plugin plugin: pluginLoader){
//TODO: Inject plugin dependencies here
}
}
}
Doing this would require the PluginEngine class to have access to the ObjectGraph instance:
class PluginEngine{
private final ObjectGraph objectGraph;
public PluginEngine(ObjectGraph graph){
this.objectGraph = graph;
}
public void start(){
ServiceLoader<Plugin> pluginLoader = ServiceLoader.load(Plugin.class);
for(Plugin plugin: pluginLoader){
objectGraph.inject(plugin);
}
}
}
Is this a code smell? Is this pointing to some problem elsewhere in my code, or in the way my dependencies are set up?
While composing this question, I began to see the role of Dagger as a means of replacing arbitrary dependencies with a dependency on the ObjectGraph itself. On Android, you use a reference to the custom Application sub-class and use it to perform injection - which is basically just a means to get access to the ObjectGraph itself. Is this reasoning flawed?
To answer my own question, it looks like this is acceptable. The u2020 sample app does something roughly similar. In fact it makes some very clever use of getSystemService() to achieve this but that is Android specific. In particular, look at Injector.java and how it is used from within custom views like TrendingView
So, conceptually, one could do something like this - which basically abstracts the concrete ObjectGraph dependency behind an Injector interface.
class PluginEngine{
private final Injector injector;
public PluginEngine(Injector injector){
this.injector = injector;
}
public void start(){
ServiceLoader<Plugin> pluginLoader = ServiceLoader.load(Plugin.class);
for(Plugin plugin: pluginLoader){
injector.inject(plugin);
}
}
}
This can be refined/adjusted in various ways such that the injector dependency is provided via a constructor or obtained in other ways.
I want to test an Android activity CommentActivity that normally constructs and uses an instance of CommentsDataSource (both are classes that I wrote).
public class CommentActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
:
CommentsDataSource = new CommentsDataSource(..);
:
}
:
}
I'm willing to create MockCommentsDataSource myself and would like to avoid using a third-party mocking framework. (Why? Because I'm a teaching trying to reduce the amount of information I need to cram into the semester and the amount of software my students need to install. I've seen other posts that recommend Guice, roboguice, and Spring.)
My question is how to pass a CommentsDataSource (or MockCommentsDataSource) to the Activity. It doesn't seem practical to make them Serializable or Parcelable, which they would have to be in order to be passed in through the Intent that starts CommentActivity. While I could easily pass in a debug flag, using it would require CommentActivity to know about MockCommentsDataSource, which is really none of its business (and in a separate application):
public class CommentActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
:
debugMode = getIntent().getBooleanExtra(DEBUG_MODE, false);
// Get a connection to the database.
final CommentsDataSource cds = (debugMode ?
new MockCommentsDataSource() : // Abstraction violation
new CommentsDataSource(this));
:
}
:
}
How should I inject MockCommentsDataSource into CommentActivity? FWIW, I'm using Eclipse and am developing for recent SDK versions.
One solution that occurs to me is to use the abstract factory pattern, since it would be relatively easy to make the factories serializable. Is that the best approach, given my constraints?
Here are two ideas:
Not using factory:
This will probably work only for unit tests and not for integration tests:
Create a method that returns CommentsDataSource, e.g. getCommentsDataSource()
Create a class that inherits CommentActivity
Override the getCommentsDataSource() with a method that returns MockCommentsDataSource
Test the new class
Using factory:
As you mentioned, you can change the CommentActivity code to get the CommentsDataSource from a factory method. this way you can have the mock class returned by the factory method.
Hope this helps!
I have a simple and ugly solution to offer, using a private static field to inject the dependency:
private static Client client;
and set the field value from the test using reflection:
public static void setStaticFieldValue(final Class<?> clazz,
final String name, final Object value) throws Exception {
final Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
field.set(null, value);
}
then, in i.e. onCreate(), use that "injected" test instance if the field is set and use the regular one otherwise.
Ugly, but requires only few changes relevant to testing to the class under test.
That's probably part one of my question.
Basically I'm struggling with the actual injection for version 1.1.2. I've read the couple of pages on the site, and I feel I'm missing something.
Basically I've done the RoboApplication extension. I've overridden the addApplicationModules method. I've even made a module.
My module looks like this:
public class DataRepository extends AbstractAndroidModule
{
#Override
protected void configure() {
/*
* This tells Guice that whenever it sees a dependency on a TransactionLog,
* it should satisfy the dependency using a DatabaseTransactionLog.
*/
bind(IDataBaseAdapter.class).to(DataBaseAdapter.class);
}
}
In my adapter I have this:
public class DataBaseAdapter implements IDataBaseAdapter
{
private DataBaseHelper _dbHelper;
private SQLiteDatabase _db;
#Inject
protected static Provider<Context> contextProvider;
public DataBaseAdapter()
{
_dbHelper = new DataBaseHelper(contextProvider.get());
}
}
If I don't do there, where is the opportune place for the chunk of code to reside... where I associate injectors?
Finally... my Application has an injection of it like so:
public class MyApplication extends RoboApplication
{
public MyApplication()
{
super();
}
public MyApplication(Context context)
{
super();
attachBaseContext(context);
}
#Override
protected void addApplicationModules(List<Module> modules)
{
modules.add(new DataRepository());
}
#Inject
private IDataBaseAdapter adapter;
public IDataBaseAdapter getAdapter()
{
return adapter;
}
public void setAdapter(IDataBaseAdapter value)
{
adapter = value;
}
...
}
I'm trying to use the Inject attribute as shown. For example:
#Inject
private IDataProvider provider;
A couple of reasons why I'm lost is that I come from a .NET and Flash/ActionScript background plus I've only used StructureMap instead of Ninject (in the .NET world), which I've heard Guice is designed with some of the ideas of Ninject in mind. Could someone help me figure out this small piece?
I'd really like to focus on using 1.1.2 instead of jumping to 2.x of RoboGuice... especially since it is still in beta, so I hope you all don't mind.
Thanks again,
Kelly
Android is quite different from standalone / hosted java application. You do not have main() , but you have certain activity units, which are managed by android framework (activities, services , broadcast receivers)
DI is a technique which allows you to eliminate booler plate code by wiring together
parts in good object oriented way.
As your unit of work is mostly activity, you shall do wiring / creation of your collaborating objects in onCreate() method , and there are dedicated onResume() and onPause() methods (see actviity lifecycle)
Rule of thumb is, does this thing needs to be restarted every time activity loses it focus? If yes, initialize / destroy it in inResume() / onPause(), otherwise - in onCreate()
And if you like to share objects withing entire application ( running in same JVM ) , it is OK to use singleton pattern in android. So you may just have singleton injector factory , and cosult it from everywhere:
InjectorFactory.getInstance(<context if necessary?>).getInstance(whatever you need);
OK, I've figured out what was needed, but I'm not quite sure why after seeing all the information floating out there.
I basically made this change, and now my test passes.
public class DataBaseAdapter implements IDataBaseAdapter
{
private DataBaseHelper _dbHelper;
private SQLiteDatabase _db;
#Inject
public DataBaseAdapter(Provider<Context> contextProvider)
{
_dbHelper = new DataBaseHelper(contextProvider.get());
}
}
While I like using constructors as the tool for injecting, I wonder why it had to work this way, considering that examples I have seen are some kind of reflection class injection.
Anyway, that's this part. Hopefully someone else will find this useful.
Cheers,
Kelly