An Introduction to Dagger 2 (Android DI) – Part 1

androidlogo1
Dagger 2 is a dependency injection framework that is built on the standard javax.inject annotations (JSR 330). Dependency injection is a software design pattern that implements inversion of control for resolving dependencies. Implementing proper dependency injection in our apps allows us to have:

  1. Testable classes.
  2. Re-usable and interchangeable components.

In Android, there are a lot of dependency injection frameworks that you can use. However, one of the greatest advantages of Dagger is that is based on Code generation not on Reflection like Google RoboGuice which makes Dagger more efficient.

In Dagger 2, you can inject dependencies on fields and constructors as shown in the following examples. Injecting dependencies on methods is also possible.

// Field Injection Example
@Inject
HelloService helloService;
// Constructor Injection Example
HelloService helloService;
	
@Inject
public MyClass(HelloService helloService) {
    this.helloService = helloService;
}

In order to understand Dagger, it is important to identify Dagger main terms:

  1. Module.
  2. Component.

Module

Before defining what a Dagger module is and since this is a first basic example to show how Dagger 2 works, assume that we have only one simple service interface (HelloService) that is defined below.

public interface HelloService {
    public String greet(String userName);
}

HelloServiceManager is the simple implementation for HelloService interface as shown below.

public class HelloServiceManager implements HelloService {

    @Override
    public String greet(String userName) {
        return "Hello " + userName + "!";
    }
}

In order to inject HelloService interface implementation, we need to define a Dagger module.

A dagger module provides the way that constructs the objects which will be injected. In order to define a dagger module, create a class and annotate it with @Module annotation and define the provider methods that return the instances. Provider methods have to be annotated by @Provider annotation as shown below.

@Module
public class MainModule {
    DaggerApplication app;

    public MainModule(DaggerApplication application) {
        app = application;
    }

    @Provides
    @Singleton
    protected Application provideApplication() {
        return app;
    }

    @Provides
    @Singleton
    HelloService provideHelloService() {
        return new HelloServiceManager();
    }
}

Here in this module, we provide two singleton instances of an Android application class (DaggerApplication will be discussed later) and the HelloService implementation class.

Component

A dagger component can be seen as an intermediate object which allows accessing to objects defined in Dagger modules.

One of the cool functions of a Dagger component is that it allows injecting non private field members to provided object as argument. In some cases, constructor injection is not possible, for example, the instances that are created and managed by the platform such as Android activity.

This is why we need to create a component interface that allows describing for which types we want to use members injection as shown below.

@Singleton
@Component(modules = {MainModule.class})
public interface DaggerGraphComponent {
    void inject(MainActivity mainActivity);

    static final class Initializer {
        private Initializer() {
        }

        public static DaggerGraphComponent init(DaggerApplication app) {
            return DaggerDaggerGraphComponent.builder()
                                             .mainModule(new MainModule(app))
                                             .build();
        }
    }
}

A dagger component can be created by annotating the class with @Component annotation, you need also to specify the component’s associated modules which is a single module MainModule in our case.

Since we have a single activity, we will have a single inject(MainActivity) method in our Dagger component interface.

Once you annotate your component class with @Component, Dagger will generate a builder class for our component class with the prefix (Dagger). Using the builder class you can initialize the Dagger 2 dependency graph as follows.

DaggerDaggerGraphComponent.builder()
                          .mainModule(new MainModule(app))
                          .build();

Now, let’s see how to initialize dependency graph and consume services.

Initializing Dependency Graph

In order to initialize the Dagger 2 Dependency graph, we need to create an application class to call the component init() method for initializing the Dagger 2 dependency graph and to keep the instance of created graph throughout application’s lifecycle.

The code below shows our Android Application class.

public class DaggerApplication extends Application {
    private static DaggerGraphComponent graph;
    private static DaggerApplication instance;

    @Override
    public void onCreate() {
        super.onCreate();
        instance = this;
        buildComponentGraph();
    }

    public static DaggerGraphComponent component() {
        return graph;
    }

    public static void buildComponentGraph() {
        graph = DaggerGraphComponent.Initializer.init(instance);
    }
}

Do not forget to register the application class in AndroidManifest.xml as follows.

    <application
	...
        android:name=".service.di.DaggerApplication">
	...
    </application>

Injecting HelloService in Activity

Finally, in order to inject HelloService in your activity, do not forget to call DaggerApplication.component().inject(this) in the Activity onCreate() method as shown below.

public class MainActivity extends AppCompatActivity ... {

    @Inject
    HelloService helloService;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        DaggerApplication.component().inject(this);	
	// ...
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.greet) {
            // you can call helloService.greet("user1") for example ...
        }
    }
}

Checkout the code

Check the sample app code in GitHub:
https://github.com/hazems/Dagger-Sample/tree/dagger-sample1

What is next?

So in the next articles, I will discuss how Dagger 2 DI can also be very useful if you are utilizing Android Build variants and how can we apply unit testing techniques for Dagger 2 applications.

iOS 9, Cordova, and jQuery mobile apps Integration tips

Unfortunately after having iOS 9 update, you may find your Cordova jQuery mobile app has the following problems:

  1. All of your app’s popups are suddenly closed after the first opening time!
  2. All your app’s back button are not working anymore!

The root cause of these problems is a bug in iOS9 UIWebView‘s window.location.hash as shown in the link below:
https://openradar.appspot.com/22186109

Fixes

In order to fix these issues, you can do the following workarounds.

Fixing the sudden closing pop-up

In order to fix this issue, make sure to set the data-history attribute of jQuery mobile popup to "false". An example of this is shown in the link below:
https://github.com/hazems/cordova-mega-app/blob/master/www/index.html

Fixing the broken back button

In order to fix this issue, make sure to disable the hash listening behaviour for jQuery mobile when the device is ready. You need to be careful when applying this fix, make sure that this fix will be applied for only iOS version 9 as shown in the code snippet below.

if (device.platform === "iOS"  && parseInt(device.version) === 9) {
  $.mobile.hashListeningEnabled=false;
} /* when the device is ready */

Checking a working Cordova jQuery mobile app in iOS 9

Finally, you can check a complete working Cordova jQuery mobile app in iOS 9. This app is one of the examples of the “JavaScript Mobile Application Development” book which can be reached at:
http://www.amazon.com/JavaScript-Native-Mobile-Apps-Development/dp/1783554177/
https://www.packtpub.com/web-development/javascript-native-mobile-apps-development

The example app uses Apache Cordova 5.3.3 and jQM 1.4.5. Enjoy!

Mobile and Cloud enablement in Nigeria

nigerian-flag-waving
I just came back from a Mobile and Cloud enablement lectures that I conducted in Lagos, Nigeria 01-07 November 2015. The cloud event organization was good and there were about more than 25 attendees during the enablement sessions.

During these enablement sessions, I really enjoyed the passion of the attendees for creating their cloud apps powered by IBM Bluemix.
DevOps

I had the chance to show the attendees how IBM Bluemix can be a good fit for creating a plenty of applications on different runtimes (Java, NodeJS, Ruby, PHP and finally ASP.NET). I also had the chance to show the attendees the power of Bluemix DevOps to plan, develop, build, and deploy apps in the Cloud.
final

Deploying your existing StrongLoop application to IBM Bluemix

If you are not familiar with StrongLoop, you may need to check my previous post:
http://www.technicaladvices.com/2015/09/12/build-and-customize-your-first-api-with-strongloop-in-less-than-7-minutes/

Deploying StrongLoop applications in Bluemix is tricky and requires you to do some modifications to your application. This post discusses the steps required to deploy a StrongLoop application that uses MongoDB to IBM Bluemix.

1. Create your StrongLoop Application in Bluemix

Before deploying your local Strongloop application in IBM Bluemix, make sure to create a Bluemix “StrongLoop Arc” application from the Bluemix Boilerplates as shown below.
StrongLoop Arc App

Then create and bind a MongoDB Service to your created StrongLoop application in IBM Bluemix.
Bind MongoDB to Bluemix app

Then download the application starter code from "Start Coding" page, extract the zip file, and then get the manifest.yml file which is as follows in my case.

applications:
- path: .
  memory: 512M
  instances: 1
  domain: mybluemix.net
  name: iReport
  host: iReport
  disk_quota: 1024M
  services:
  - iReport-MongoDB

Copy the manifest.yml file to your local StrongLoop application’s directory.

2. Use VCAP_APP_HOST and VCAP_APP_PORT inside server.js file

In server.js file under the server directory, make sure to Use process.env.VCAP_APP_HOST and process.env.VCAP_APP_PORT as shown in the code below.

...
boot(app, __dirname, function(err) {
  if (err) throw err;
	
  //Use Bluemix host and port ...  
  var host = process.env.VCAP_APP_HOST || 'localhost';
  var port = process.env.VCAP_APP_PORT || 1337;
  
  app.set('host', host);
  app.set('port', port);  

  // start the server if `$ node server.js`
  if (require.main === module)
    app.start();
});

3. Use the “start” attribute in package.json

If you do not use the "start" attribute in your package.json file, you may face the following exception when pushing your application to IBM Bluemix.

[App/0]  ERR npm ERR! Linux 3.19.0-25-generic
[App/0]  ERR npm ERR! argv "/home/vcap/app/vendor/node/bin/node" "/home/vcap/app/vendor/node/bin/npm" "start"
[App/0]  ERR npm ERR! node v0.12.7
[App/0]  ERR npm ERR! npm  v2.11.3
[App/0]  ERR npm ERR! missing script: start
[App/0]  ERR npm ERR! 
[App/0]  ERR npm ERR! If you need help, you may report this error at:
[App/0]  ERR npm ERR!     <https://github.com/npm/npm/issues>
[App/0]  ERR npm ERR! Please include the following file with any support request:
[App/0]  ERR npm ERR!     /home/vcap/app/npm-debug.log
[DEA/14] ERR Instance (index 0) failed to start accepting connections

This is my package.json file which uses the "start" attribute as follows.

{
  "name": "iReport-Services",
  "version": "1.0.0",
  "scripts": {
    "pretest": "jshint .",
    "start": "node server/server.js"
  },
  "dependencies": {
    "compression": "^1.0.3",
    "cors": "^2.5.2",
    "loopback": "^2.22.0",
    "loopback-boot": "^2.6.5",
    "loopback-component-explorer": "^2.1.0",
    "loopback-connector-mongodb": "^1.13.0",
    "loopback-datasource-juggler": "^2.39.0",
    "serve-favicon": "^2.0.1"
  },
  "devDependencies": {
    "jshint": "^2.5.6"
  },
  "repository": {
    "type": "",
    "url": ""
  },
  "description": "iReport-Services"
}

4. Update datasources.json file under the application’s server directory

Under the server directory, there is a file called datasources.json which holds the application’s data source configurations, edit this file to point your application to the Bluemix MongoDB instead of your old MongoDB.

Below is my datasources.json file.

{
  ...
  ,
  "iReport-db": {
    "connector": "mongodb",
    "url": "mongodb://xxx"
  }
}

You can get the "url" attribute from the MongoDB Bluemix configuration as shown in the screenshot below.
Bluemix MongoDB

After doing the previous steps, you can finally, cf push [your local strongloop application] to IBM Bluemix,

These are all the steps you need to do in order to have your StrongLoop application up-and-running in Bluemix, Enjoy!

Build and customize your first API with StrongLoop in less than 7 minutes

The StrongLoop API Platform features the popular open source LoopBack framework. LoopBack enables you to quickly compose scalable APIs, runs on top of the Express web framework and conforms to the Swagger 2.0 specification.

In this video, I showed how to quickly build and customize a REST API powered by LoopBack. Some things to make sure that they are there before applying this video:

  1. The model object (Cafeteria) used in this API is persistent in MongoDB. So make sure to start MongoDB before applying this video steps.
  2. Make sure to create an account in https://strongloop.com/register/ because you will use this account to access the API Composer.
  3. Make sure to have Node.JS installed in your machine: https://nodejs.org/en/
  4. Install StrongLoop by executing the following command:
    $ npm install -g strongloop
  5. Know the purpose of the following commands:
    $ slc loopback
    

    This command creates a Node.js application using the LoopBack framework.

    $ slc arc
    

    This command runs StrongLoop Arc (which provides a GUI to define the app model), by default opening it in a web browser window.

  6. The last part of this video shows how to customize the Cafeteria RESTful API by implementing a new attribute status. The cafeteria status can be accessed using "GET /api/Cafeteria/status".

Enjoy watching the video:

[JavaScript Quiz #16] Smallest number of flights

Consider you have a set of places (CAI, FRA, MAD, NYC, SFO) and there are available flights between some of these destinations as shown below.

CAI -> FRA
FRA -> MAD
MAD -> NYC
CAI -> MAD
NYC -> SFO
FRA -> CAI
MAD -> FRA

Design and develop a JavaScript function that can get the shortest possible path from a destination X to destination Y if there is any.
.
.
.
.
.
.
.
.
.
.
.
.
.
In order to develop a JavaScript function which can get the shortest path between two destinations, first of all, we need to think about the proper data structure which can represent these places and the connections between them. If we think about it, we will find that these placed can be represented as nodes and the connections between these places can be represented as edges which is typically a Graph. We can represent this Graph as a 2D N X N array as shown below.

    CAI FRA MAD NYC SFO
CAI  0   1   1   0   0
FRA  1   0   1   0   0
MAD  0   1   0   1   0
NYC  0   0   0   0   1
SFO  0   0   0   0   0

The previous matrix can be translated to the following JavaScript code.

var mapping = {
    "CAI": 0,
    "FRA": 1,
    "MAD": 2,
    "NYC": 3,
    "SFO": 4
};

var routeGraph = 
[
    [0, 1, 1, 0, 0],
    [1, 0, 1, 0, 0],
    [0, 1, 0, 1, 0],
    [0, 0, 0, 0, 1],
    [0, 0, 0, 0, 0]    
];

After make the proper representation, we need to think about how to get the shortest path between any two nodes in this unweighted graph. Since this graph is unweighted, we can use directly BFS (Breath First Search) in order to get the shortest path. For more information about BFS, check: https://en.wikipedia.org/wiki/Breadth-first_search.

In order to implement BFS, there are some notes for our implementation below:

  1. We utilized the Queue data structure for storing the nodes in a first-in, first-out (FIFO) style, we explore the oldest unexplored nodes first. Thus our explorations radiate out slowly from the starting node, defining a breadth-first search.
  2. In order to keep track of the shortest path, we have a JavaScript map nodeParent object which stores the first visited parent of the current visited node.
  3. Finally, when the search finds the destination then we construct the final path from the nodeParent object and stores it in the finalPath array.

The code below shows our BFS implementation in order to get the shortest path between the start and destination nodes.

var ShortestPathFinder = function() {
}

ShortestPathFinder.find = function (start, destination) {
    var visited = {}; // A map containing all of the visited nodes ...
    var nodeParent = {}; // An map containing the node parents ...
    var queue = [start], i, found = false, finalPath = [], neighbours = [];    
    
    nodeParent[start] = null;
    
    var current = queue.shift();
    
    while ((neighbours = ShortestPathFinder.getNeighbours(current)) != null) {
    
        for (i = 0; i < neighbours.length; ++i) {
            
            // If we find the destination then exit these loops ...
            if (neighbours[i] == destination) {
                found = true;
                nodeParent[neighbours[i]] = current;
                break;
            }
        
            if (! visited[neighbours[i]]) {
                
                // Mark this node as "visited" ...
                visited[neighbours[i]] = true;
            
                // Add element to the queue ...
                queue.push(neighbours[i]);
                nodeParent[neighbours[i]] = current;
            }
        }
        
        if (queue.length == 0) {
            break;
        }
        
        current = queue.shift();
    }
    
    if (! found) {
        console.error("No path is found between " + start + " and " + destination);
        
        return null;
    }
    
    // Construct the final path from the node parent map ...
    current = destination;
    
    finalPath.push(destination);
    
    while (nodeParent[current] != start) {
        finalPath.push(nodeParent[current]);
        
        current = nodeParent[current];
    }
    
    finalPath.push(start);    
    
    return finalPath.reverse();
}

In order to get the neighbours of the current node, a simple function is implemented to get the neighbours from the routeGraph matrix as follows.

ShortestPathFinder.getNeighbours = function(current) {
    var currentIndex = mapping[current], i, result = [];
    
    for (i = 0; i < routeGraph[currentIndex].length; ++i) {
        if (routeGraph[currentIndex][i] == 1) {
            result.push(mapping.getKey(i));
        }
    }
    
    return result;
}

Finally, we can test our developed JavaScript function by having the following test cases.

console.log(ShortestPathFinder.find("CAI", "NYC"));
console.log(ShortestPathFinder.find("CAI", "SFO"));
console.log(ShortestPathFinder.find("FRA", "NYC"));
console.log(ShortestPathFinder.find("SFO", "CAI"));
console.log(ShortestPathFinder.find("MAD", "CAI"));

Below is the output of the console.

["CAI", "MAD", "NYC"]
["CAI", "MAD", "NYC", "SFO"]
["FRA", "MAD", "NYC"]
No path is found between SFO and CAI
null
["MAD", "FRA", "CAI"]

Attached below, the complete solution code for your reference, if you have comments or a better solution, feel free to comment below.

/*
CAI -> FRA
FRA -> MAD
MAD -> NYC
CAI -> MAD
NYC -> SFO
FRA -> CAI
MAD -> FRA

    CAI FRA MAD NYC SFO
CAI  0   1   1   0   0
FRA  1   0   1   0   0
MAD  0   1   0   1   0
NYC  0   0   0   0   1
SFO  0   0   0   0   0
*/

var mapping = {
    "CAI": 0,
    "FRA": 1,
    "MAD": 2,
    "NYC": 3,
    "SFO": 4
};

var routeGraph = 
[
    [0, 1, 1, 0, 0],
    [1, 0, 1, 0, 0],
    [0, 1, 0, 1, 0],
    [0, 0, 0, 0, 1],
    [0, 0, 0, 0, 0]    
];

Object.prototype.getKey = function(value){
  for(var key in this){
    if(this[key] == value){
      return key;
    }
  }
  return null;
};


var ShortestPathFinder = function() {
}

ShortestPathFinder.find = function (start, destination) {
    var visited = {}; // A map containing all of the visited nodes ...
    var nodeParent = {}; // An map containing the node parents ...
    var queue = [start], i, found = false, finalPath = [], neighbours = [];    
    
    nodeParent[start] = null;
    
    var current = queue.shift();
    
    while ((neighbours = ShortestPathFinder.getNeighbours(current)) != null) {
    
        for (i = 0; i < neighbours.length; ++i) {
            
            // If we find the destination then exit these loops ...
            if (neighbours[i] == destination) {
                found = true;
                nodeParent[neighbours[i]] = current;
                break;
            }
        
            if (! visited[neighbours[i]]) {
                
                // Mark this node as "visited" ...
                visited[neighbours[i]] = true;
            
                // Add element to the queue ...
                queue.push(neighbours[i]);
                nodeParent[neighbours[i]] = current;
            }
        }
        
        if (queue.length == 0) {
            break;
        }
        
        current = queue.shift();
    }
    
    if (! found) {
        console.error("No path is found between " + start + " and " + destination);
        
        return null;
    }
    
    // Construct the final path from the node parent map ...
    current = destination;
    
    finalPath.push(destination);
    
    while (nodeParent[current] != start) {
        finalPath.push(nodeParent[current]);
        
        current = nodeParent[current];
    }
    
    finalPath.push(start);    
    
    return finalPath.reverse();
}

ShortestPathFinder.getNeighbours = function(current) {
    var currentIndex = mapping[current], i, result = [];
    
    for (i = 0; i < routeGraph[currentIndex].length; ++i) {
        if (routeGraph[currentIndex][i] == 1) {
            result.push(mapping.getKey(i));
        }
    }
    
    return result;
}

console.log(ShortestPathFinder.find("CAI", "NYC"));
console.log(ShortestPathFinder.find("CAI", "SFO"));
console.log(ShortestPathFinder.find("FRA", "NYC"));
console.log(ShortestPathFinder.find("SFO", "CAI"));
console.log(ShortestPathFinder.find("MAD", "CAI"));

Creating Cordova jQuery Mobile Apps Rapidly

Cordova jQuery npm plugin allows you to add jQuery mobile’s ready-made templates to your existing Apache Cordova app using a neat easy-to-use CLI.

You can install Cordova jQuery npm plugin using the following npm command:
npm install -g cordova-jquery

Once you install it, you can start using it by executing cordova-jquery command from your Apache Cordova app’s root directory. The next six videos shows you how to create six Cordova jQuery mobile apps with different templates (Multipages, Header Navigation Bar, Persistent Navigation Bar, External Panel, Accordion, and ListView).

As shown in the videos below, after executing cordova-jquery command, all what you need to do is to choose the template you would like to apply to your existing Cordova app. All of the examples below work on Apache Cordova version 5.1.1 (The latest Cordova release until the moment).

Cordova jQuery plugin supports the following templates.

  1. Multiple Pages
    This template will apply a simple two page jQuery mobile template to your index.html file.
  2. Header Navbar
    This template will apply a three page jQuery mobile template to your index.html file that includes a header navbar for the header on each page.
  3. Persistent Navbar
    This template will apply a three page jQuery mobile template to your index.html file that includes a persistent navbar for the footer on each page.
  4. External Panel
    This template will apply an external panel to jQuery mobile. When this option is selected you will also be prompted for additional information such as which side of the page you’d like the panel to open on (left, right) and which reveal style would you like (reveal, push, overlay)
  5. Accordion
    This template will apply three sections’ jQuery mobile accordion template to your index.html file. Your existing content will be placed as part of the first section. It is important to note that you have to make sure that your existing content parent element does not use CSS “absolute” position in order to be controlled by the accordion section.
  6. List View
    This template will apply a jQuery mobile list view template to your index.html file. The first item of the list view points to your existing content page, and the second and the third items of the list view point to two placeholder pages.

The main objective of this plugin is to facilitate the usage of the jQuery Mobile in Apache Cordova, so feel free to use it and submit any issues you are facing to:
https://github.com/Open-I-Beam/cordova-jquery-npm/issues

Related Plugin Videos:

DZone MVB (Most Valuable Blogger)

dzone-mvb
Today, I’m really glad and honored to be selected as a DZone MVB (Most Valuable Blogger). DZone’s MVB program brings together a group of highly talented bloggers, authors, and technologists actively writing about topics of interest to the developer community. These people are recognized in the industry for their contributions and deep technical knowledge on subjects ranging from software design and architecture to programming on a range of platforms including Java, .NET, Ruby and others.

One of my main passion areas is generally speaking, writing, and sharing my experience and ideas with people. This is why I find writing books and blogging an interesting activity. I think writing (and speaking) is a great way to communicate and exchange our ideas (as a part of the WW community) with each others, and it is a wonderful way to enhance our experiences.
Screen Shot 2015-07-09 at 12.00.33 AM
When I began writing, My main aim was (and still) sharing my experience with the WW community in order to help people rapidly resolving problems that are similar to the problems that I face during my daily job, and also in order to learn from the community if they have better solutions.

I hope that, if you do not have your own technical blog yet, to start creating your own one and share your technical experience because it will be definitely useful to at least someone in somewhere in this world.