Wednesday, May 28, 2014

Busy developer Android Google Analytics guide

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.

Monday, May 5, 2014

Java Consumer Producer example (without using Java BlockingQueue)

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