I was working on integrating Google Analytics (GA) into existing Android application.
If you want to track your activities in GA, you need to put stop and start reports in your activities onStart and onStop
lifecycle events. You need to do this in _every_ activity.
I don't like this approach, it doesn't feel right (I hate copy paste code in any form).
Luckily there is another approach.
You can implement ActivityLifecycleCallbacks and then you can override onActivityStopped and onActivityStarted methods and by doing so, you will
put start and stop method in every activity. Here is how to do it:
public class CustomActivityLifeCycleListener implements Application.ActivityLifecycleCallbacks {
@Override
public void onActivityStopped(Activity activity) {
GoogleAnalytics.getInstance(activity).reportActivityStop(activity);
}
@Override
public void onActivityStarted(Activity activity) {
GoogleAnalytics.getInstance(activity).reportActivityStart(activity);
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
}
You need to register this LifeCycle listener in you application class (by extending Application) and initialize your GA tracker.
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(new CustomActivityLifeCycleListener());
//R.xml.global_tracker is my tracker configuration, you can also initialize tracker
//by passing your GA property in String constructor.
GoogleAnalytics.getInstance(getContext()).newTracker(R.xml.global_tracker);
}
}
You can also save this tracker (instance) in your app class because you will need tracker if you want to send events or whatever.
One more thing. You need to register your tracker resource in your AndroidManifest or else your GA configuration will not work.
It took me something like 3h until I figure this out!
Also you need to update yours Google Play Service lib and install Google Analytics libs in your Android SDK tool.
I found very interesting and nice blocking queue implementation.
Off course you can use Java BlockingQueue (http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html) implementation,
but if you want to learn something new along the way why not implement it by yourself?
I left some original comments and add some of my own.
Enjoy!
public class BlockingQueueTest {
private final BlockingQ bq = new BlockingQ();
/**
The Worker thread is not very robust. If a RuntimeException
occurse in the run method, the thread will stop.
*/
private class Worker extends Thread {
public Worker(String name) { super(name); start(); }
public void run() {
try {
//This loop will continue to take next runnable task from queue or
//will block on pop() method.
while(!isInterrupted()) {
((Runnable)bq.pop()).run();
}
//This will spit out the "poison pill". :)
} catch(InterruptedException ex) {}
System.out.println(getName() + " finished");
}
}
public BlockingQueueTest() {
// We create 10 threads as workers
Thread[] workers = new Thread[10];
for (int i=0; i < workers.length; i++)
workers[i] = new Worker("Worker Thread " + i);
// We then push 100 commands onto the queue
for (int i=0; i<100; i++) {
final String msg = "Task " + i + " completed";
bq.push(new Runnable() {
public void run() {
System.out.println(msg);
// Sleep a random amount of time, up to 1 second
try { Thread.sleep((long)(Math.random()*1000)); }
catch(InterruptedException ex) { }
}
});
}
// We then push one "poison pill" onto the queue for each
// worker thread, which will only be processed once the other
// tasks are completed.
for (int i=0; i < workers.length; i++) {
bq.push(new Runnable() {
public void run() {
Thread.currentThread().interrupt();
}
});
}
// Lastly we join ourself to each of the Worker threads, so
// that we only continue once all the worker threads are
// finished.
for (int i=0; i < workers.length; i++) {
try {
workers[i].join();
} catch(InterruptedException ex) {}
}
System.out.println("BlockingQueueTest finished");
}
public static void main(String[] args) throws Exception{
new BlockingQueueTest();
}
}
class BlockingQ {
/**
It makes logical sense to use a linked list for a FIFO queue,
although an ArrayList is usually more efficient for a short
queue (on most VMs).
*/
private final LinkedList queue = new LinkedList();
/**
This method pushes an object onto the end of the queue, and
then notifies one of the waiting threads.
*/
public void push(Object o) {
synchronized(queue) {
queue.add(o);
//This will notify blocked thread (on queue.wait() bellow) to continue.
queue.notify();
}
}
/**
The pop operation blocks until either an object is returned
or the thread is interrupted, in which case it throws an
InterruptedException.
*/
public Object pop() throws InterruptedException {
//Racing condition starts here.
synchronized(queue) {
//Thread will wait if queue is empty.
while (queue.isEmpty()) {
queue.wait();
}
return queue.removeFirst();
}
}
}
This implementation was taken from: http://www.javaspecialists.eu/archive/Issue016.html
Passing arrays instance arguments in single line of code is very useful. For example you can do something like this:
addNumbers(new int[] {1,2,3});
And it will work perfectly, but for collections you can't to that. However using anonymous inner classes with instance initialization we can get similar effect:
private static int addNumbers(int[] numbers) {
int result = 0;
for (int number : numbers) {
result += number;
}
return result;
}
private static Integer addNumbers(Collection<Integer> numbers) {
Integer result = 0;
for (Integer number : numbers) {
result += number;
}
return result;
}
There are two ways you can create new Thread in Java. First one is to implement Runnable. This is more common way of doing this, but if you look at the Thread's code, you will see that Thread only calls run() on Runnable object, so you basically don't need it here. Second way is not to use Runnable, but instead just implement Thread'srun() ant that's it!
Using Runnable:
Thread secondMethod = new Thread(new Runnable() {
int index = 0;
@Override
public void run() {
try {
while (index < 100) {
int interval = (int) ((Math.random() * 500) + 500);
Thread.sleep(interval);
System.out.print("*");
index++;
}
} catch (InterruptedException exc) {
//Empty
}
}
});
Without Runnable:
Thread firstMethod = new Thread() {
int index = 0;
@Override
public void run() {
try {
while (index < 100) {
int interval = (int) ((Math.random() * 500) + 500);
sleep(interval);
System.out.print(".");
index++;
}
} catch (InterruptedException exc) {
//Empty
}
}
};
This book "Refactoring: Improving the Design of Existing Code" is really good reading for everyone that want to upgrade his coding mojo with some new tricks. This are basically "old" tricks, but it good to know them by name. :) Happy reading!
Ward Cunningham - the guy that developed first wiki and is also know as a pioneer in both design patterns and Extreme Programming gave a great interview on QCon.
On 18 minute he start speaking about Agile, code review, knowledge sharing and how through Agile We (IT guys) overcome software crisis and now other departments in organization want to learn lessons from IT and Agile.
Also here you can find interview with Barbara Liskov that she gave on Qcon. She's talking about Liskov substitution principle and distributed system.
If you don't know her, She is Turing Award winner and first person (with her students) that join abstracted data types with operations (basically she paved roads for OOP as we know it today).
Static factories and constructors share a limitation: they do not scale well to large numbers of optional parameters.
Consider the case of computer configuration builder. There are parts that are essential in this build, but also there are optional parts.
There number of ways that developers usually try to approach this problem. First is telescopic constructors where you need to create constructor for each of optional parameter. This approach has obvious disadvantages (ugly code, lot of work). Second approach is to use JavaBeans in which you call a parameterless constructor to create the object and
then call setter methods to set each required parameter and each
optional parameter of interest. There are two problems with this approach. First is that JavaBean may be in an inconsistent state partway through its construction. Second is that this pattern pre-cludes the possibility of making a class immutable.
There is however third approach that is very elegant and can create immutable objects. It is a form of the Builder pattern.Instead of making the desired object directly, the client calls a constructor (or static factory) with all of the required parameters and gets a builder object. Here is how it looks like:
public class ComputerConfigurator {
private final int sizeOfRam;
private final int sizeOfHdd;
private final int processorSpeed;
private final int dedicatedGpuSpeed;
private final boolean waterCooling;
public static class Builder {
//Required params
private final int sizeOfRam;
private final int sizeOfHdd;
private final int procesorSpeed;
//Optional params
private int dedicatedGpuSpeed;
private boolean waterCooling;
public Builder(int sizeOfRam, int sizeOfHdd, int procesorSpeed) {
this.sizeOfRam = sizeOfRam;
this.sizeOfHdd = sizeOfHdd;
this.procesorSpeed = procesorSpeed;
}
public Builder dedicatedGpuSpeed(int val) {
dedicatedGpuSpeed = val;
return this;
}
public Builder waterCooling(boolean val) {
waterCooling = val;
return this;
}
public ComputerConfigurator build() {
return new ComputerConfigurator(this);
}
}
private ComputerConfigurator(Builder builder) {
sizeOfRam = builder.sizeOfRam;
sizeOfHdd = builder.sizeOfHdd;
processorSpeed = builder.procesorSpeed;
dedicatedGpuSpeed = builder.dedicatedGpuSpeed;
waterCooling = builder.waterCooling;
}
}
The builder’s setter methods return the builder itself so that invocations can be chained. Here’s how the client code looks:
public class Main {
public static void main(String[] args) {
ComputerConfigurator firstComputerConfigurator = new ComputerConfigurator.
Builder(2, 40, 3000).
dedicatedGpuSpeed(1000).build();
ComputerConfigurator secondComputerConfigurator = new ComputerConfigurator.
Builder(2, 40, 3000).
dedicatedGpuSpeed(1000).waterCooling(true).build();
}
}
Visitor lets you define a new operation (method) on object without changing the classes (interface) of the elements on which it operates. This is the essence of visitor patter. The name "Visitor" is misleading and this pattern has noting to do with visiting, iteration or something like that. If you need to perform operations across a disparate set of objects, Visitor might be the pattern for you. Let see how does it work.
So let's presume we have have some disparate object structure and we want to run one operation on each object of this structure.
Here is how it works then:
The core of this pattern is Visitor interface. This interface defines a visit operation for each type in the object structure. The object (one object from structure) interface simply defines an accept method to allow the visitor to run some action over that object. This operation is here to to allow the visitor access to the object.
Here we have example that will calculate average Per Seat Fuel Economy for different type of vehicles. Calculation is quite simple: consumption / number of seats. Each of vehicle is represented with simple POJO's. Each of this object have one accept method so we have access to object through unified interface.
public class Bike implements Visitable {
private int consumption;
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public Bike(int consumption) {
this.consumption = consumption;
}
public int getConsumption() {
return consumption;
}
}
public class Bus implements Visitable {
private int numberOfSeats;
private int litersConsumption;
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public Bus(int numberOfSeats, int litersConsumption) {
this.numberOfSeats = numberOfSeats;
this.litersConsumption = litersConsumption;
}
public int getNumberOfSeats() {
return numberOfSeats;
}
public int getLitersConsumption() {
return litersConsumption;
}
}
public class Car implements Visitable {
private int consumption;
private int weight;
private int seats;
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public Car(int consumption, int weight, int seats) {
this.consumption = consumption;
this.weight = weight;
this.seats = seats;
}
public int getConsumption() {
return consumption;
}
public int getWeight() {
return weight;
}
public int getSeats() {
return seats;
}
}
Although this objects don't know how to calculate average per seat consumption we will learn them how to do that without even touching them:
public class EfficiencyVisitor implements Visitor {
private int efficiency;
@Override
public void visit(Bike bike) {
efficiency += bike.getConsumption() / 2;
}
@Override
public void visit(Bus bus) {
efficiency += bus.getLitersConsumption() / bus.getNumberOfSeats();
}
@Override
public void visit(Car car) {
efficiency += car.getConsumption() / car.getSeats() ;
}
public int getEfficiency() {
return efficiency;
}
}
Client:
public class Main {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
int averageConsumptionPerSeat = 0;
List <Visitable> vehicles = new ArrayList<>();
Car mazda = new Car(6, 1024, 5);
vehicles.add(mazda);
Car skoda = new Car(7, 1200, 4);
vehicles.add(skoda);
Bus merc = new Bus(60, 30);
vehicles.add(merc);
Bike suzuki = new Bike(4);
vehicles.add(suzuki);
EfficiencyVisitor efficiencyVisitor = new EfficiencyVisitor();
for (Visitable vehicle : vehicles) {
vehicle.accept(efficiencyVisitor);
averageConsumptionPerSeat += efficiencyVisitor.getEfficiency();
}
System.out.println(averageConsumptionPerSeat / vehicles.size());
}
}
Best thing about this is that we can easily add new vehicle types or change existing methods without changing interface or methods on "old" vehicle types.
The whole point of this pattern is to clean up your code. It allow you to separate certain logic from the elements themselves, keeping your data classes simple.
Google App Engine uses long polling as a push technology.
It uses two HTTP connections to the server. When the client has data to send to the server, it initiates an HTTP connection and posts the data to the server. The client also maintains a long-lived HTTP connection to the server that the server uses to return data back to the client. We refer to the first type of connection as the send channel and the second type of connection as the receive channel. Together these two unidirectional channels provide a bidirectional channel of communication between the browser and the server.
In this example we will use GAE push technology support (it however doesn't support full duplex communication, client send HTTP POST request on the server). It is kind of slow, but I think that it is sufficient for non-aggressive client state refresh.
I created some example on GAE, here is youtube video. In this example you can see update of four separate clients. Each client paints canvas with different color.
There are several moving parts you need to orchestrate when developing push capable application. Client side should listen for changes and to update view. Second responsibility for client is off course to send messages to server when client state changes.
It should look something like this:
//some demolib for this example
var demolib = {};
demolib.sendMessage = function(path, opt_params) {
if (opt_params) {
path += opt_params;
}
var xhr = new XMLHttpRequest();
console.log("Posting: " + path)
xhr.open('POST', path, true);
xhr.send();
};
demolib.writeCircle = function(xPos, yPos, color) {
var canvas = document.getElementById('simpleCanvas');
var context = canvas.getContext('2d');
var radius = 10;
context.beginPath();
context.arc(xPos-radius, yPos-radius, radius, 0, 2 * Math.PI, false);
context.fillStyle = color;
context.fill();
context.lineWidth = 5;
context.strokeStyle = '#003300';
context.stroke();
};
demolib.onOpened = function() {
demolib.sendMessage('/opened');
};
demolib.onMessage = function(m) {
var newState = JSON.parse(m.data);
if (newState.color != '${color}') {
demolib.writeCircle(newState.x, newState.y, newState.color);
}
};
demolib.openChannel = function() {
var token = "${token}";
var channel = new goog.appengine.Channel(token);
var handler = {
'onopen': demolib.onOpened,
'onmessage': demolib.onMessage,
'onerror': function() {},
'onclose': function() {}
};
var socket = channel.open(handler);
'onopen' = demolib.onOpened;
socket.onmessage = demolib.onMessage;
};
demolib.init = function() {
demolib.openChannel();
var canvas = document.getElementById('simpleCanvas');
canvas.onclick = function(e) {
var centerX = e.pageX - canvas.offsetLeft;
var centerY = e.pageY - canvas.offsetTop;
var token = "${token}";
var color = "${color}";
console.log(centerX + ' ' + centerY);
demolib.writeCircle(centerX, centerY, color);
demolib.sendMessage('/play', '?x='+centerX+'&y='+centerY+'&color='+color);
};
demolib.onMessage();
}();
Then on server side, you need to create channel for each client. In this example we are using user session to manage clients.
Only new clients from same IP are allowed (to differentiate between clients and to make this example simple as it can be).
Facade Pattern is structural pattern. It basically hide complexity, so I tend to call it "good sense pattern". It also decouples code, which is good thing. But you should not overuse Facade pattern in your applications.
Similar like to much abstraction is considered harmful for code readability, same thing apply to too much simplification (because you basically add layer on top layer and you introduce complexity).
Session facade is useful in situations where it encapsulate the complexities between the client and the server interactions. It manages business objects and provides uniform service access layer to clients. It basically represent centralized peace that minimize method calls over network, exposes uniform interface and managing security and transactions in one place.