Tuesday, March 19, 2013

Easy xml

Without going into pros and cons of XML-based data formats, we have to say, that they are very commonly used. So common, that probably everyone faced with them.
To deal with XML data Android Developer portal recommends to use XmlPullParser, which is an efficient and maintainable way to parse XML on Android. It's classic Pull Parser with its advantages and disadvantages. Obvious disadvantage here - you don't have DOM model, and with big complex xml file you will doomed to tedious work with infinite nextgetName and getText. On the other hand, standard DOM parser in java (Document object as an interface which represents serialized xml) can't boast with convenient API too. Of course, Google can help to find a tons of 3d party solutions for xml parsing, but let's have lightweight and simple xml parser with pseudo DOM model and convenient api for xml nodes access.
Let's called our utility class XmlNode. As you might guess XmlNode represents node of xml tree. Each Node must contains it's name, value and list of attributes. List of child nodes must be present too. Reference to parent node may also be useful. For easy search of the child elements by name is't useful to have map of node-name/XmlNode pairs. Of course, this approach (get child node by name) won't work correctly if we will have a few child nodes with the same name on the same level. But in most cases we know xml tree structure and can avoid this problem by getting all child nodes of current node (in most cases these nodes represents items of some list).
Sometimes some xml node may be present on certain level of xml tree or not. I do not like to deal with null data, so I propose to always return empty (not initialized) child node when it's requested from parent node. For this purpose we also will add initialization marker (which will be set to true) when node will be created during xml file parse. In case if node is not present in tree but it's requested from code user always will be able to check was this node initialized or not.
I won't leave pieces of code here, whole class can be found in github.

Sunday, September 9, 2012

Android Layout. Dot the i's and cross the t's.

Most likely, you met Android Layouts during your first hours of android development. Android Layouts are primary and most important part of UI toolkit and it's very important to understand 'background' details and be aware about pitfalls to use them most efficiently.
I guess everyone know basic theory about layouts and how to use them, so this part will be ignored. The only thing need to noted is that as the basis of all layouts is ViewGroup, which holds other views (children) and defines LayoutParams - information used by views to tell their parents how they want to be laid out.
Now I propose to go directly to certain layout and it's implementation details.


    AbsoluteLayout

The main idea of AbsoluteLayout is to place each control at an absolute position. Here is source code of onLayout method which which performs children positioning:

@Override  
   protected void onLayout(boolean changed, int l, int t,  
       int r, int b) {  
     int count = getChildCount();  
     for (int i = 0; i < count; i++) {  
       View child = getChildAt(i);  
       if (child.getVisibility() != GONE) {  
         AbsoluteLayout.LayoutParams lp =  
             (AbsoluteLayout.LayoutParams) child.getLayoutParams();  
         int childLeft = mPaddingLeft + lp.x;  
         int childTop = mPaddingTop + lp.y;  
         child.layout(childLeft, childTop,  
             childLeft + child.getMeasuredWidth(),  
             childTop + child.getMeasuredHeight());  
       }  
     }  
   }  

It's quite obvious: every child is positioning on specified position (or left top point f layout if coordinates is not specified explicitly) considering position of parent layout and padding inside layout. Absolutely positioning makes your UI inflexible, so in most cases, it's not acceptable due to fragmentation of android devices.
AbsoluteLayout is simplest to use (and to implement), but due to significant restrictions it's very rarely used.

    FrameLayout

FrameLayout is used to display a single item at a time. You can have a few elements within a FrameLayout, but each element will be positioned based on the top left point of the screen. Elements, that overlaped by 'top' element, will be displayed overlapping. Child views are drawn in a stack, with the most recently added child on top, i.e. first view added to the frame layout will display on the bottom of the stack, and the last view added will display on top.
Frame layouts  usually used when you need to overlap views another views of your user interface. For example, you have application, which rendering some graphical data. In our case it will be newspaper. You have preview, which can be loaded immediately, while image with good quality requires some time to load and prepare. While second image is loading you can place spinner at the corner of preview to show, that 'load' operation in progress, something like this:

<?xml version="1.0" encoding="utf-8"?>  
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"  
        android:orientation="vertical"  
        android:layout_width="fill_parent"  
        android:layout_height="fill_parent"  
        android:padding="20dp"  
     >  
   <!--  
     UI elements...  
   -->  
   <ProgressBar  
       android:layout_width="wrap_content"  
       android:layout_height="wrap_content"  
       android:layout_gravity="right"  
   />  
 </FrameLayout>  

And how it will looks like:



After image with good quality is ready we can hide progress spinner and replace image in layout:


As we can see, frame layout is perfect choice for such situations. It allows us to overlap 'underlying' layer, but not block it, so user can start to interact with application.
So, now let's take a look on layout algorithm. At first step borders of FrameLayout are calculated:

@Override  
   protected void onLayout(boolean changed, int left, int top, int right, int bottom) {  
     final int count = getChildCount();  
     final int parentLeft = getPaddingLeftWithForeground();  
     final int parentRight = right - left - getPaddingRightWithForeground();  
     final int parentTop = getPaddingTopWithForeground();  
     final int parentBottom = bottom - top - getPaddingBottomWithForeground();  

Next, start loop through layout children to place them. For every non GONE element we will calculate left top point considering element's gravity:

for (int i = 0; i < count; i++) {  
       final View child = getChildAt(i);  
       if (child.getVisibility() != GONE) {  
         final LayoutParams lp = (LayoutParams) child.getLayoutParams();  
         ...

Left point is calculated according to horizontal gravity.

  final int layoutDirection = getResolvedLayoutDirection();  
     final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);  
     final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;  
     switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {  
        case Gravity.LEFT:  
           childLeft = parentLeft + lp.leftMargin;  
           break;  
        case Gravity.CENTER_HORIZONTAL:  
           childLeft = parentLeft + (parentRight - parentLeft - width) / 2 +  
           lp.leftMargin - lp.rightMargin;  
           break;  
        case Gravity.RIGHT:  
           childLeft = parentRight - width - lp.rightMargin;  
           break;  
        default:  
           childLeft = parentLeft + lp.leftMargin;  
     }  

As we can see, by default, view is positioned to left corner (of course, margins included). Element width and parent borders are used if element must be positioned to the right corner or centered horizontally. Almost the same picture we have for top point of view (in this case default vertical gravity is TOP):

         switch (verticalGravity) {  
           case Gravity.TOP:  
             childTop = parentTop + lp.topMargin;  
             break;  
           case Gravity.CENTER_VERTICAL:  
             childTop = parentTop + (parentBottom - parentTop - height) / 2 +  
             lp.topMargin - lp.bottomMargin;  
             break;  
           case Gravity.BOTTOM:  
             childTop = parentBottom - height - lp.bottomMargin;  
             break;  
           default:  
             childTop = parentTop + lp.topMargin;  
         }  
         child.layout(childLeft, childTop, childLeft + width, childTop + height);  

and in the end, after we know coordinate of top left point of child view, will will call layout method to assign size and position to a view and all of its descendants.
So, FrameLayout is quite obvious and predictable. It's also really flexible, that's why it's used much often than AbsoluteLayout.

LinearLayout

The linear layout works as its name implies: it places elements in linear or vertical direction. When the layout’s orientation is set to vertical, all child elements within it are organized in a single column; when the layout’s orientation is set to horizontal, all child elements within it are placed in a single row. Due to its obviousness and simplicity LinearLayout is most commonly used layout manager. Unfortunately, linear layouts quite often used in situations, where another layout managers can solve this problem easily. LinearLayout may lead to a more complex and cumbersome layout description (your xml resources), which means creation of useless UI elements. Example will be considered below. 
Moment with size of elements within linear layout should be considered separately. Generally speaking, linear layout doesn't guarantee rubber layout. If elements have precise size (not one of FILL_PARENT(MATCH_PARENT), WRAP_CONTENT) it's possible situation, when their total size is greater than visible space of screen. Such cases breaks 'rubber layout' concept. But with linear layout we can avoid such situations, if we can find proportional coefficient (relative to the other elements) to replace hard coded size. Such technique in linear layout conception called weight. The weight of a child controls 'importance' of this element, i.e. how much  “space” its given within its parent linear layout. By the way, unlike other attributes of linear layout , which are applied to the linear layout view itself, this attribute applies to its child elements. 
The weight values should be numbers: max number for most prior item and min number for the lowest-priority element. You don't have to care about total size of values (I've read a few times, that sum of values must equals 1, but this is not true). You can specify weightSum for parent layout by yourself, but If  you will left it unspecified  - it will be computed at layout/measure time by adding the layout_weight of each child. And simple example:

 <?xml version="1.0" encoding="utf-8"?>  
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
        android:orientation="horizontal"  
        android:layout_width="fill_parent"  
        android:layout_height="fill_parent"  
        android:baselineAligned="false">  
   <LinearLayout android:background="#FF0000"  
          android:layout_height="fill_parent" android:layout_width="wrap_content"  
          android:layout_weight="1.2"/>  
   <LinearLayout android:background="#00FF00"  
          android:layout_height="fill_parent" android:layout_width="wrap_content"  
          android:layout_weight="0.3"/>  
   <LinearLayout android:background="#00FFFF"  
          android:layout_height="fill_parent" android:layout_width="wrap_content"  
          android:layout_weight="0.5"/>  
   <LinearLayout android:background="#FFFF00"  
          android:layout_height="fill_parent" android:layout_width="wrap_content"  
          android:layout_weight="1.5"/>  
 </LinearLayout>  

Due to our layout, yellow part should be the largest (about 43% of total width), red part is a little bit smaller, while cyan and green take together only approximately 23%. And on device it looks like in should be:


Now, lets take a look to ayout algorithm. It's is built around layout orientation: vertical or horizontal:

   @Override  
   protected void onLayout(boolean changed, int l, int t, int r, int b) {  
     if (mOrientation == VERTICAL) {  
       layoutVertical();  
     } else {  
       layoutHorizontal();  
     }  
   }  

Note first that layoutHorizontal and layoutVertical works in the same manner with respect to layout orientation. So, let's considering only one of them, layoutVertical. I won't include code of method here, it can be found here, we only briefly review the main steps. At first step border right coordinate is calculated. Then we get count of child in layout and calculate major and minor gravity:

     final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;  
     final int minorGravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;  

Major gravity will be used on next step to calculate upper point from which items will be placed. Minor gravity will be applied to each child without explicitly specified gravity. In loop through layout children left point (where element should be placed) us calculated with respect to minor gravity (if there is no explicitly specified gravity for current element). And in the end, knowing left and top point where element should be placed and it's dimensions we can draw it. We should note, that some methods within loop have no any effects for linear layout and will be overridden for TableLayout (which based on LinearLayout), which will be considered next.
TableLayout is a grid of of rows and columns, where a cell can display a view control. From a user interface design perspective, a TableLayout is comprised of TableRow controls - one for each row in your table. The contents of a TableRow are simply the view controls that will go in each “cell” of the table grid.
Although table layouts can be used to design entire user interfaces, they usually aren’t the best solution for doing so, because they are derived from LinearLayout and not the most efficient of layout controls. Generally speaking, TableLayout is a little bit more than an organized set of nested LinearLayouts, and nesting layouts too deeply is generally discouraged for performance concerns. However, for data that is already in a format suitable for a table, such as spreadsheet data, table layout may be a reasonable choice.


RelativeLayout

Unlike linear or table layouts relative layout doesn't drive us to the limits of your current row - you can place elements where ever you want relatively to the other elements or even to parent layout. I guess this layout is very familiar to developers and I don't see any reason to focus on it. Just note, that considering capabilities of relative layout, its layout/measurement algorithm is much difficult. 
Let's consider common example of a layout: list item with an icon on the left, a title at the top and an optional description underneath the title:



This layout may be implemented using different layout, for example LinearLayout, RelativeLayout or TableLayout. Having the same result, we can compare layout's complexity by hierarchyviewer. So, here are layouts with different layout managers:

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
        android:layout_width="fill_parent"  
        android:layout_height="72dp"  
        android:padding="6dip">  
   <ImageView  
       android:id="@+id/icon"  
       android:layout_width="wrap_content"  
       android:layout_height="fill_parent"  
       android:layout_marginRight="6dip"  
       android:src="@drawable/ic_launcher" />  
   <LinearLayout  
       android:orientation="vertical"  
       android:layout_width="fill_parent"  
       android:layout_height="fill_parent">  
     <TextView  
         android:layout_width="fill_parent"  
         android:layout_height="0dip"  
         android:layout_weight="1"  
         android:gravity="center_vertical"  
         android:text="Layout Example item" />  
     <TextView  
         android:layout_width="fill_parent"  
         android:layout_height="0dip"  
         android:layout_weight="1"  
         android:singleLine="true"  
         android:ellipsize="marquee"  
         android:text="Simple item that shows how the same..." />  
   </LinearLayout>  
 </LinearLayout>  

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
         android:layout_width="fill_parent"  
         android:layout_height="62dp"  
         android:padding="6dip">  
   <ImageView  
       android:id="@+id/icon"  
       android:layout_width="wrap_content"  
       android:layout_height="fill_parent"  
       android:layout_alignParentTop="true"  
       android:layout_alignParentBottom="true"  
       android:layout_marginRight="6dip"  
       android:src="@drawable/ic_launcher" />  
   <TextView  
       android:id="@+id/secondLine"  
       android:layout_width="fill_parent"  
       android:layout_height="26dip"  
       android:layout_toRightOf="@id/icon"  
       android:layout_alignParentBottom="true"  
       android:layout_alignParentRight="true"  
       android:singleLine="true"  
       android:ellipsize="marquee"  
       android:text="Simple item that shows how the same..." />  
   <TextView  
       android:layout_width="fill_parent"  
       android:layout_height="wrap_content"  
       android:layout_toRightOf="@id/icon"  
       android:layout_alignParentRight="true"  
       android:layout_alignParentTop="true"  
       android:layout_above="@id/secondLine"  
       android:layout_alignWithParentIfMissing="true"  
       android:gravity="center_vertical"  
       android:text="Layout Example item" />  
 </RelativeLayout>  

 <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"  
        android:layout_width="fill_parent"  
        android:layout_height="72dp"  
        android:padding="6dip">  
   <TableRow  
       android:layout_height="wrap_content"  
       android:layout_width="match_parent">  
   <ImageView  
       android:id="@+id/icon"  
       android:layout_width="wrap_content"  
       android:layout_height="fill_parent"  
       android:layout_marginRight="6dip"  
       android:src="@drawable/ic_launcher"/>  
     <LinearLayout  
         android:orientation="vertical"  
         android:layout_width="fill_parent"  
         android:layout_height="fill_parent">  
       <TextView  
           android:layout_width="fill_parent"  
           android:layout_height="0dip"  
           android:layout_weight="1"  
           android:gravity="center_vertical"  
           android:text="Layout Example item"/>  
       <TextView  
           android:layout_width="fill_parent"  
           android:layout_height="0dip"  
           android:layout_weight="1"  
           android:text="Simple item that shows how the same..."/>  
     </LinearLayout>  
   </TableRow>  
 </TableLayout>  

And the difference between implementations becomes obvious when comparing the view hierarchies in HierarchyViewer:
Linear layout

Relative layout

Table layout

So, as we can see, we can create the same layout with different layout managers, but view hierarchies will be much different. For single item it may no sense to optimize view, but it much more important when you use such a layout for every item in a ListView, for instance. So I urge not to focus on single layout manager, but to choose it depending on certain problem.

Friday, August 17, 2012

About cache

Cache is a temporary buffer (with quick access) that stores data so that future requests for this data can be processed faster. If requested data is contained in cache then request can be served by reading the cache, otherwise data has to be computed or fetched from its original storage. Definitely, in first case our application will perform operation quicker.

But we have to pay for this advantage - to store a lot of data cache need to use a huge amount of memory. It's not a big problem when we are talking about cache on local disk (or sdcard) to store, for example, downloaded images. But if we need to store some data in RAM to have the quickest access to this data we will have to limit our cache by some constant value which often much less than all data size. This automatically implies 'preemptive nature' of cache: if there is no free space in cache and we need to put one more 'item' - something (already stored in cache) must be removed.

First and most obvious way to implement own cache would be SoftReference. Let's take a look on simple (not multithreaded) cache based on SoftReference. Let our cache will be called SoftCache and let is be parameterized:

 public class SoftCache<K, V>  

Data will be stored in HashMap:

 private Map<K, SoftReference<V>> mCacheMap = new HashMap<K, SoftReference<V>>();  

And methods to put new item to cache (we must supply our cache records with keys to be able to get them), get item (with appropriate key) from cache and to remove it:

   public V put(K key, V value) {  
     SoftReference<V> softRef = mCacheMap.put(key, new SoftReference<V>(value));  
     if (softRef == null) {  
       return null;  
     }  
     V oldValue = softRef.get();  
     softRef.clear();  
     return oldValue;  
   }
  
   public V get(K key) {  
     SoftReference<V> softRef = mCacheMap.get(key);  
     return softRef == null ? null : softRef.get();  
   }  

   public V remove(K key) {  
     SoftReference<V> softRef = mCacheMap.remove(key);  
     if (softRef == null) {  
       return null;  
     }  
     V oldValue = softRef.get();  
     softRef.clear();  
     return oldValue;  
   }  

As we can see, this approach is easy enough to implement. But it has a few disadvantages:
  1. We can't specify cache size.
  2. SoftReference doesn't give us control over when and how remove records from cache when we need to add new item to already 'full' cache
SoftReference approach may be interested as a general purpose cache. But if we want to optimize our cache to be the most efficient for certain purpose we need somehow define rules for items replacing in cache. Generally speaking, it's very difficult issue of computer science and it's often called Cache Algorithms.
So let's take a look to some of Cache Algorithms without going into details of algorithms' efficiency. Our goal here is to understand algorithms' functions and try to find how we can apply caches based on these algorithms to everyday problems.

     First in First out (FIFO)


Algorithm with least effort for managing the cache entries. It's based on using queue as a storage for cache entries. When cache is full and an entry needs to be replaced (since new entry need to be inserted) - entry at the front of the queue (the oldest entry) will be removed and replaced with the current fetched entry.
It's not easy to find certain case where this algorithm will give max output, probably it should be used as a general purpose cache when we can't find better approaches.

     Least Frequently Used (LFU)


This Algorithm is based on counting how often an entry being requested - it's increments a counter associated with each cache entry. Entry with least frequently used counter is removed first when cache is full and new entry need to be added. This algorithm is not very fast (since it requires brute-force search for element to remove when cache is full). But LFU cache is a good choice when the request frequency does not vary over time (i.e. what was the most frequent yesterday is also the same today). As an very abstract example of Android application which using LFU cache may be some media player which requested audio streams from internet - in most cases users are listening the same music, so it may be cached to provide immediate access. But as I said, it's very abstract example, because in most cases, our cache will be to small to store even a few audio streams. But I believe this example shows certain case where certain algorithm gives real advantage.

     Least Recently Used (LRU)


Main idea of LRU is to remove the least recently used items first when free space in cache is required. Every new item is placed on the top of the cache, while older top items falled down. But whenever an item is accessed, it will be placed at the top again. When the cache exceeds its size limit, items from the bottom will be discarded. This algorithm does not require exhaustive search, so it's faster comparatively to LFU.
LRU will be good choice for some kind of gallery application or applications to render some big pictures which usually broken on small pieces - LRU helps to avoid yank effect when user doing move events around the same area.
B.t.w., since api 12 LRU cache is present in android sdk and compatibility package.

     Most Recently Used (MRU)


The opposite to LRU - adding new items to the top of cache MRU removes items from top when the cache exceeds its size limit. Good choice for common database memory caches, when already fetched data, probably, will not be requested in the foreseeable future.

There are a lot of other algorithms, but we will focus on this and go to implementation.

Let's start from generic base cache element to be used for all cache implementations:
 public class CacheElement<K, V> {  
   
   /**  
    * Cache element value.  
    */  
   private V mValue;  
   
   /**  
    * Cache element key.  
    */  
   private K mKey;  
   
   /**  
    * Counter for LFU algorithm.  
    */  
   private int mHitCount;  
   
   ...
   // mutator methods  
 }  

I guess here all is obvious.
Next, we will define base cache class with some common functionality:
 public abstract class AbstractCache<K, V> {  
   private static final int MAX_ITEMS_IN_CACHE = 3;  

   protected Map<K, CacheElement<K, V>> mTable = new HashMap<K, CacheElement<K, V>>();  

   protected boolean isFull() {  
     return itemsCount() >= MAX_ITEMS_IN_CACHE;  
   }  

   protected CacheElement<K, V> createCacheElement(K key, V value) {  
     CacheElement<K, V> cacheElement = new CacheElement<K, V>();  
     cacheElement.setKey(key);  
     cacheElement.setValue(value);  
     return cacheElement;  
   } 
 
   protected boolean updateCacheElement(CacheElement<K, V> element, K key, V value) {  
     if (element != null) {  
       element.setValue(value);  
       return true;  
     }  
     return false;  
   }  

   public abstract void put(K key, V value);  

   public abstract V get(K key);  

   public abstract void print();  

   protected abstract int itemsCount();  
 }  

Let's look closely to this generic class. MAX_ITEMS_IN_CACHE defined maximum of elements, to be placed in cache. Of course, it would be more convenient to have size limit, but calculation of object size in java is not trivial procedure and since it's only example we can proceed with count limitation. mTable is used for quick search of already stored (cached) items by key. isFull method is quite obvious - it's used to define is cache full and one of the cache items need to be deleted. createCacheElement and updateCacheElement are used to create and update already added to cache element respectively. And 4 abstract methods to be implemented in certain cache implementation. Should be noted, that print is used only for test purposes and it will be implemented using System.out#print to be able to run on desktop.

So, first will be FIFO cache
 public class FIFOCacheImpl<K, V> extends AbstractCache<K, V> {  
   
   protected Queue<CacheElement<K, V>> mCache = new ConcurrentLinkedQueue<CacheElement<K, V>>();  
   
   @Override
   public final synchronized void put(K key, V value) {  
     CacheElement<K, V> element = mTable.get(key);  
     if (updateCacheElement(element, key, value)) {  
       return;  
     }  
     CacheElement<K, V> cacheElement = createCacheElement(key, value);  
     if (isFull()) {  
       CacheElement<K, V> elem = mCache.poll();  
       mTable.remove(elem.getKey());  
     }  
     mCache.offer(cacheElement);  
     mTable.put(key, cacheElement);  
   }  
   
   @Override
   public final synchronized V get(K key) {  
     CacheElement<K, V> element = mTable.get(key);  
     return element != null ? element.getValue() : null;  
   }  
   
   @Override  
   public void print() {  
     System.out.print("{ ");  
     for (CacheElement<K, V> cacheElement : mCache) {  
       System.out.print("[ " + cacheElement.getKey() + " - " + cacheElement.getValue() + " ] ");  
     }  
     System.out.println("}");  
   }  
   
   @Override  
   protected int itemsCount() {  
     return mCache.size();  
   }  
 }  

Queue is used as primary storage for items to provide FIFO behavior. Methods get, print and itemsCount are quite obvious, so let's move to put right away. At first step we are using quick dictionary mTable to find if item already exists in cache and if such item found - update it with new value. If item with key doesn't exists in cache - create it and if cache is not full put it to cache and table (for quick search). But if cache is full - remove item from head (if we are adding new elements to tail) of cache and from search dictionary (mTable).
And simple example:
     AbstractCache<Integer, String> fifoCache = new FIFOCacheImpl<Integer, String>();  
     fifoCache.put(1, "s1");  
     fifoCache.print();  
     fifoCache.put(2, "s2");  
     fifoCache.print();  
     fifoCache.put(3, "s3");  
     fifoCache.print();  
     fifoCache.put(4, "s4");  
     fifoCache.print();  
     fifoCache.put(5, "s5");  
     fifoCache.print();  

and system output:
 { [ 1 - s1 ] }  
 { [ 1 - s1 ] [ 2 - s2 ] }  
 { [ 1 - s1 ] [ 2 - s2 ] [ 3 - s3 ] }  
 { [ 2 - s2 ] [ 3 - s3 ] [ 4 - s4 ] }  
 { [ 3 - s3 ] [ 4 - s4 ] [ 5 - s5 ] }  

So, all as expected: when cache is full - oldest items removed from cache.

Next will be LFU cache
 public class LFUCacheImpl<K, V> extends AbstractCache<K, V> {  
   
   protected List<CacheElement<K, V>> mCache = new LinkedList<CacheElement<K, V>>();  
   
   @Override  
   public void put(K key, V value) {  
     CacheElement<K, V> element = mTable.get(key);  
     if (updateCacheElement(element, key, value)) {  
       return;  
     }  
     CacheElement<K, V> cacheElement = createCacheElement(key, value);  
     if (isFull()) {  
       CacheElement<K, V> elem = removeLfuElement();  
       mTable.remove(elem.getKey());  
     }  
     mCache.add(cacheElement);  
     mTable.put(key, cacheElement);  
   }  
   
   @Override  
   public final synchronized V get(K key) {  
     CacheElement<K, V> element = mTable.get(key);  
     if (element != null) {  
       element.incrementHitCount();  
       return element.getValue();  
     }  
     return null;  
   }  
   
   @Override  
   public void print() {  
     System.out.print("{ ");  
     for (CacheElement<K, V> cacheElement : mCache) {  
       System.out.print("[ " + cacheElement.getKey() + " - " + cacheElement.getValue() + " : " +  
           cacheElement.getHitCount() + " ] ");  
     }  
     System.out.println("}");  
   }  
   
   @Override  
   protected int itemsCount() {  
     return mCache.size();  
   }  
   
   public CacheElement<K, V> removeLfuElement() {  
     CacheElement<K, V> leastElement = leastHit();  
     mCache.remove(leastElement);  
     return leastElement;  
   }  
   
   public CacheElement<K, V> leastHit() {  
     CacheElement<K, V> lowestElement = null;  
     for (CacheElement<K, V> element : mCache) {  
       if (lowestElement == null) {  
         lowestElement = element;  
       } else {  
         if (element.getHitCount() < lowestElement.getHitCount()) {  
           lowestElement = element;  
         }  
       }  
     }  
     return lowestElement;  
   }  
 }  

I won't dwell on the code: the idea is the same as for FIFO cache, only a few moment need to be clarified: when item is requested by get and requested item exists in cache - item's hit count is incremented. leastHit is using mHitCount to find item to remove from cache.
     AbstractCache<Integer, String> lfuCache = new LFUCacheImpl<Integer, String>();  
     lfuCache.put(1, "s1");  
     lfuCache.print();  
     lfuCache.get(1);  
     lfuCache.get(1);  
     lfuCache.print();  
     lfuCache.put(2, "s2");  
     lfuCache.print();  
     lfuCache.get(2);  
     lfuCache.get(2);  
     lfuCache.get(2);  
     lfuCache.print();  
     lfuCache.put(3, "s3");  
     lfuCache.print();  
     lfuCache.get(3);  
     lfuCache.get(3);  
     lfuCache.get(3);  
     lfuCache.get(3);  
     lfuCache.print();  
     lfuCache.put(4, "s4");  
     lfuCache.print();  
     lfuCache.get(4);  
     lfuCache.print();  
     lfuCache.put(5, "s5");  
     lfuCache.print();  

and system output:
 { [ 1 - s1 : 0 ] }  
 { [ 1 - s1 : 2 ] }  
 { [ 1 - s1 : 2 ] [ 2 - s2 : 0 ] }  
 { [ 1 - s1 : 2 ] [ 2 - s2 : 3 ] }  
 { [ 1 - s1 : 2 ] [ 2 - s2 : 3 ] [ 3 - s3 : 0 ] }  
 { [ 1 - s1 : 2 ] [ 2 - s2 : 3 ] [ 3 - s3 : 4 ] }  
 { [ 2 - s2 : 3 ] [ 3 - s3 : 4 ] [ 4 - s4 : 0 ] }  
 { [ 2 - s2 : 3 ] [ 3 - s3 : 4 ] [ 4 - s4 : 1 ] }  
 { [ 2 - s2 : 3 ] [ 3 - s3 : 4 ] [ 5 - s5 : 0 ] }  

So, as we can see, when item is requested from cache - its hit count is incremented. Least demanded items removes from cache when it's full.

And the last will be LRU cache (MLU is almost the same)
 public class LRUCacheImpl<K, V> extends AbstractCache<K, V> {  
   
   protected List<CacheElement<K, V>> mCache = new ArrayList<CacheElement<K, V>>();  
   
   @Override  
   public void put(K key, V value) {  
     CacheElement<K, V> element = mTable.get(key);  
     if (updateCacheElement(element, key, value)) {  
       Collections.swap(mCache, mCache.indexOf(element), 0);  
       return;  
     }  
     CacheElement<K, V> cacheElement = createCacheElement(key, value);  
     if (isFull()) {  
       CacheElement<K, V> elem = mCache.remove(mCache.size() - 1);  
       mTable.remove(elem.getKey());  
     }  
     mCache.add(0, cacheElement);  
     mTable.put(key, cacheElement);  
   }  
   
   @Override  
   public final synchronized V get(K key) {  
     CacheElement<K, V> element = mTable.get(key);  
     if (element != null) {  
       Collections.swap(mCache, mCache.indexOf(element), 0);  
       return element.getValue();  
     }  
     return null;  
   }  
   
   @Override  
   public void print() {  
     System.out.print("{ ");  
     for (CacheElement<K, V> cacheElement : mCache) {  
       System.out.print("[ " + cacheElement.getKey() + " - " + cacheElement.getValue() + " ] ");  
     }  
     System.out.println("}");  
   }  
   
   @Override  
   protected int itemsCount() {  
     return mCache.size();  
   }  
 }  

As we can see, requested (or updated item) is moved to the first position of list, while last element is removed, when cache is full. And here is example:
     AbstractCache<Integer, String> lruCache = new LRUCacheImpl<Integer, String>();  
     lruCache.put(1, "s1");  
     lruCache.print();  
     lruCache.put(2, "s3");  
     lruCache.print();  
     lruCache.put(1, "s1");  
     lruCache.print();  
     lruCache.get(2);  
     lruCache.print();  
     lruCache.put(3, "s1");  
     lruCache.print();  
     lruCache.put(4, "s1");  
     lruCache.print();  
     lruCache.get(4);  
     lruCache.print();  
     lruCache.put(5, "s1");  
     lruCache.print();  
     lruCache.put(6, "s1");  
     lruCache.print();  

and system output:
 { [ 1 - s1 ] }  
 { [ 2 - s3 ] [ 1 - s1 ] }  
 { [ 1 - s1 ] [ 2 - s3 ] }  
 { [ 2 - s3 ] [ 1 - s1 ] }  
 { [ 3 - s1 ] [ 2 - s3 ] [ 1 - s1 ] }  
 { [ 4 - s1 ] [ 3 - s1 ] [ 2 - s3 ] }  
 { [ 4 - s1 ] [ 3 - s1 ] [ 2 - s3 ] }  
 { [ 5 - s1 ] [ 4 - s1 ] [ 3 - s1 ] }  
 { [ 6 - s1 ] [ 5 - s1 ] [ 4 - s1 ] }  

So, all as expected, last requested item is on top, while not requested items are falling to the down. So, it was short introduction to different cache implementations to be used in your Android applications.

Thank you for attention.

Thursday, August 9, 2012

Hello, Kotlin

After a long years month of waiting Jetbrains finally released Kotlin M2 Candidate with official Android support!

A few links: About language, How to run Kotlin on Android and about Build tools.

Being able to provide custom control structures, Operator overloading and many other useful stuff (see Kotlin vs Java) Kotlin may become a very powerful extension for your development tools.

Looking forward to first official release.

Happy coding!

Saturday, July 7, 2012

whoami

Quite often you application must generate unique identifier for current instance of application to create server account linked with current device. Ideally, this identifier should persists on application reinstallation, so even after application being deleted and installed again the same account will be used for application on current device.

The simplest (and, probably, the most correct) approach is to use TelephonyManager#getDeviceId.
 mDeviceId = ((TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId()  
Unfortunately, deviceId may be null for devices w.o. GSM or CDMA module. Another way is to use Serial Number. This identifier is available via Build#SERIAL from android api 9. So, to cover older os versions let's use reflection:
 Class<?> c = Class.forName("android.os.SystemProperties");  
 Class<?>[] paramTypes= new Class[1];  
 paramTypes[0]= String.class;  
 Method get = c.getMethod("get", paramTypes);  
 Object[] params= new Object[1];  
 params[0]= new String("ro.serialno");  
 mDeviceId = (String) get.invoke(c, params);  
Serial identifier is quite 'unpredictable' and may be absent on Samsung devices, so we have to have more options to cover much more devices. Next step will be Secure#ANDROID_ID - randomly generated 64-bit number on the device's first boot:
 mDeviceId = Secure.getString(context.getContentResolver(), Secure.ANDROID_ID);  
But even this value sometimes is null (unfortunately, I don't remember devices on which this problem can be reproduced). Furthermore, this values will be changed upon factory reset.
It is also possible to use wi-fi mac address as identifier for application instance:
 mDeviceId = ((WifiManager)context.getSystemService(Context.WIFI_SERVICE)).getConnectionInfo().getMacAddress();  
But not all devices have wi-fi. Also, if the wi-fi is not turned on, the hardware may not report the Mac address (null will be returned). As a last resort identifier can be generated using UUID#randomUUID. This is mutable value, but it can be stored somewhere on sdcard to persist it's value after reinstallation. Probably, it's all available options to get unique id. Hopefully, order of presentation provides correct 'brute-force' algorithm of searching identifier.

Sunday, May 27, 2012

Customize your progress bar

ProgressBar is standard visual indicator for progress of some operation. It's often used by developers as a part of ProgressDialog to prevent user's interaction with application (because ProgressDialog is modal) while complex operations are performed in background.

Style of ProgressBar depends on  device vendor. It may looks like

for Samsung devices or like
for HTC devices etc. The same situation for 'indeterminate' progress with infinite round spinner. 

Fortunately, ProgressBar is very flexible and allow us to customize it (for example, when we want to have the same progress line for our application at any device). Let's start from most obvious - style. Default progress bar styles provided by sdk are:
  • Widget.ProgressBar.Horizontal
  • Widget.ProgressBar.Small
  • Widget.ProgressBar.Large
  • Widget.ProgressBar.Inverse
  • Widget.ProgressBar.Small.Inverse
  • Widget.ProgressBar.Large.Inverse
I believe the titles speaks for itself. I prefer Widget.ProgressBar.Horizontal. Further, let's define height of dialog using layout_height attribute:

   <ProgressBar  
       android:id="@+id/progress"  
       style="@android:style/Widget.ProgressBar.Horizontal"  
       android:layout_width="fill_parent"  
       android:layout_height="20dp"/>  

Now progress bar will looks like on pictures below.

To customize progress line we need create LayerDrawable background, something like this:

 <?xml version="1.0" encoding="utf-8"?>  
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">  
   <item android:id="@+id/my_bg">  
     <shape>  
       <corners android:radius="20dip"/>  
       <gradient android:startColor="#C0C0C0" android:centerColor="#F8F8FF"  
            android:centerY="0.75" android:endColor="#ffffff" android:angle="90"/>  
       <stroke android:width="1dp" android:color="#00aa00"/>  
     </shape>  
   </item>  
   <item android:id="@+id/my_progress">  
     <clip>  
       <shape>  
         <corners android:radius="20dip"/>  
         <gradient android:startColor="#CaCaC0" android:centerColor="#2828FF"  
              android:centerY="0.75" android:endColor="#325423" android:angle="270"/>  
       </shape>  
     </clip>  
   </item>  
 </layer-list>  

Tiny clarifications: since progress line has background and progress state at least 2 layers are required. And important moment: first layer is background while second is progress. Id of layers actually can be arbitrary (as in my example), but if you don't want to clip your layers by yourself you can use system hardcoded names: background for first layer and progress for second. In this case method tileify of ProgressBar class will perform clipping internally:

   private Drawable tileify(Drawable drawable, boolean clip) {  
     if (drawable instanceof LayerDrawable) {  
       LayerDrawable background = (LayerDrawable) drawable;  
       final int N = background.getNumberOfLayers();  
       Drawable[] outDrawables = new Drawable[N];  
       for (int i = 0; i < N; i++) {  
         int id = background.getId(i);  
         outDrawables[i] = tileify(background.getDrawable(i),  
             (id == R.id.progress || id == R.id.secondaryProgress));  
       }  
     ...  
     } else if (drawable instanceof BitmapDrawable) {  
     ...  
       return (clip) ? new ClipDrawable(shapeDrawable, Gravity.LEFT,  
           ClipDrawable.HORIZONTAL) : shapeDrawable;  
     }  
     return drawable;  
   }  

And this is how progress bar will looks like with crazy color in our LayerDrawable:


Not bad, isn't so?

Saturday, May 12, 2012

Deep look at Android Networking. Part 3. Mobile internet.

Mobile internet (GPRS, EDGE, etc) is typically more expensive and slower than internet provided by wlan access points (via wi-fi), but has much greater coverage. Most android devices have mobile internet. It's configured from Settings (Settings->Wireless and network->Mobile Networks):


Since as typical android device has possibility to establish connection to wlan access point (i.e. wi-fi internet connection) and use mobile operator internet (i.e. mobile internet) option to establish 2 internet connection simultaneously theoretical exists. But to dot the i's and cross the t's let's consider typical rules for internet connection, which inherent not just for Android OS, but for most mobile operation systems:
  1. Only one internet connection can be established.
  2. Wi-fi internet has higher priority than mobile internet. 
  3. If wi-fi internet connection is established you will not be able to establish mobile internet connection.
  4. If mobile internet connection is established and you will try establish wi-fi connection, mobile internet connection will be disabled.
This rules are quite logical and make sense. Only one internet connection can be established to save device battery. Wi-fi has higher priority because it's faster and cheaper than mobile internet. And since wi-fi connection has higher priority, points 3 and 4 are quite obvious too. But in case when you need to circumvent these rules you will be faced with serious problems (especially given the fact that the there is no public api in android sdk to manage mobile network connection) and all you remain to do is rely on funny tricks, some of which will be discussed below. But since all this tricks are based on reflection, dirty hacks and hidden api, there is no there is no guarantee, that this will works on your certain device (in my experience, it depends on vendor and device model). Furthermore, I don't recommend you to use this things in your production application, they are (this tricks) interesting only for experiments.

So, let's start from permissions essential for these experiments:
   <uses-permission android:name="android.permission.INTERNET"/>  
   <uses-permission android:name="android.permission.MODIFY_PHONE_STATE"/>  
   <uses-permission android:name="android.permission.WRITE_APN_SETTINGS"/>  
   <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>  
   <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>  
   <uses-permission android:name="android.permission.WRITE_SETTINGS"/>  

Next moment - we need to enable mobile data connection. It should be noted, that this operation a little bit differently performed for old and for new sdk version. For sdk 2.1 and earlier you should do something like this:
   private void setDataConnection(boolean dataConnection) {  
     Method dataConnSwitchMethod;  
     Class telephonyManagerClass;  
     Object ITelephonyStub;  
     Class ITelephonyClass;  
     TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);  
     try {  
       telephonyManagerClass = Class.forName(telephonyManager.getClass().getName());  
       Method getITelephonyMethod = telephonyManagerClass.getDeclaredMethod("getITelephony");  
       getITelephonyMethod.setAccessible(true);  
       ITelephonyStub = getITelephonyMethod.invoke(telephonyManager);  
       ITelephonyClass = Class.forName(ITelephonyStub.getClass().getName());  
       String invokeMethodName = dataConnection ? "enableDataConnectivity" : "disableDataConnectivity";  
       Log.d(TAG, invokeMethodName);  
       dataConnSwitchMethod = ITelephonyClass.getDeclaredMethod(invokeMethodName);  
       dataConnSwitchMethod.setAccessible(true);  
       dataConnSwitchMethod.invoke(ITelephonyStub);  
     } catch (Exception e) {  
       Log.e(TAG, e.getMessage());  
     }  
   }  

As you can see, we are getting ITelephony aidl interface to enable or disable mobile data connections:
   /**  
    * Allow mobile data connections.  
    */  
   boolean enableDataConnectivity();  
   /**  
    * Disallow mobile data connections.  
    */  
   boolean disableDataConnectivity();  

Starting from sdk 2.2 you can use the IConnectivityManager#setMobileDataEnabled method. It's hidden in API too, so we have to use reflection again:
   private void setMobileDataEnabled(boolean dataConnection) {  
     try {  
       final ConnectivityManager conman = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);  
       final Class conmanClass = Class.forName(conman.getClass().getName());  
       final Field iConnectivityManagerField = conmanClass.getDeclaredField("mService");  
       iConnectivityManagerField.setAccessible(true);  
       final Object iConnectivityManager = iConnectivityManagerField.get(conman);  
       final Class iConnectivityManagerClass = Class.forName(iConnectivityManager.getClass().getName());  
       final Method setMobileDataEnabledMethod = iConnectivityManagerClass.getDeclaredMethod("setMobileDataEnabled", Boolean.TYPE);  
       setMobileDataEnabledMethod.setAccessible(true);  
       setMobileDataEnabledMethod.invoke(iConnectivityManager, dataConnection);  
     } catch (Exception e) {  
       ...  
     }  
   }  

On some devices this operation requires android.permission.WRITE_SECURE_SETTINGS, which maybe granted only for system applications, so for such cases all next tricks will have no any sense. Only thing you can do - root your device and install app to /system folder (using adb shell push app.apk /system command).

So, after mobile data connection is enabled, we will try add APN we want to use:
   private static final Uri APN_TABLE_URI = Uri.parse("content://telephony/carriers");  
   public static final String OPERATOR_NUMERIC_KEY = "gsm.sim.operator.numeric";  
   
   public int addAPN() {  
     int id = -1;  
     ContentResolver resolver = getContentResolver();  
     ContentValues values = new ContentValues();  
     values.put("name", appName);  
     values.put("apn", accessPointName);  
     values.put("user", userName);  
     values.put("password", password);  
     // read mobile operator numeric info using shell command getprop  
     String numeric = getSystemProperty(OPERATOR_NUMERIC_KEY);  
     String mcc = "";  
     String mnc = "";  
     try {  
       mcc = numeric.substring(0, 3);  
       mnc = numeric.substring(3, 5);  
     } catch (Exception e) {  
       ...  
     }  
     values.put("mcc", mcc);  
     values.put("mnc", mnc);  
     values.put("numeric", numeric);  
     Cursor cursor = null;  
     try {  
       // insert apn  
       Uri newRow = resolver.insert(APN_TABLE_URI, values);  
       if (null != newRow) {  
         cursor = resolver.query(newRow, null, null, null, null);  
         Log.d(TAG, "Newly added APN:");  
         // Obtain the apn id  
         int idIndex = cursor.getColumnIndex("_id");  
         cursor.moveToFirst();  
         id = cursor.getShort(idIndex);  
         Log.d(TAG, "New ID: " + id + ": Inserting new APN succeeded!");  
       }  
     }  
     catch (Exception e) {  
       Log.d(TAG, e.getMessage());  
     }  
     if (null != cursor) {  
       cursor.close();  
     }  
     return id;  
   }  
   
   ...
   public static String getSystemProperty(String key) {
        try {
            String line;
            String formattedKey = "[" + key + ']';
            java.lang.Process p = Runtime.getRuntime().exec("getprop");
            BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
            while (null != (line = input.readLine())) {
                String[] property = line.split(":");
                if (formattedKey.equals(property[0].trim())) {
                    return property[1].trim().substring(1, property[1].length() - 2);
                }
            }
            input.close();
        }
        catch (Exception err) {
            err.printStackTrace();
        }

        return null;
    }

I think all is obvious here.  ContentResolver is used to access table of system APNs. The only thing that deserves attention here is 
            
     // read mobile operator numeric info using shell command getprop
     String numeric = getSystemProperty(OPERATOR_NUMERIC_KEY);  

We are extracting system property gsm.sim.operator.numeric and parsing result to get Mobile Network Code (mnc) and Mobile Country Code (mcc) - these values are essential for APN.

Now we need to set our inserted APN to be default. From user interface it's looks like to select appropriate radio button on list of available APNs.


Let's take a look how can we do this programmatically:

   private static final Uri PREFERRED_APN_URI = Uri.parse("content://telephony/carriers/preferapn");  

   public boolean setActiveAPN(int id) {  
     boolean result = false;  
     ContentResolver resolver = getContentResolver();  
     ContentValues values = new ContentValues();  
     values.put("apn_id", id);  
     try {  
       resolver.update(PREFERRED_APN_URI, values, null, null);  
       Cursor cursor = resolver.query(  
           PREFERRED_APN_URI,  
           new String[]{"name", "apn"},  
           "_id=" + id,  
           null,  
           null);  
       if (null != cursor) {  
         result = true;  
         cursor.close();  
       }  
     }  
     catch (Exception e) {  
       Log.d(TAG, e.getMessage());  
     }  
     return result;  
   }  

To setActiveAPN method we need to pass id. We can use identifier of APN, created by addAPN function or any other existed APN.

So, now, after mobile connection is enabled and you add APN and made it default you device will try to establish connection (of course, there should not be wi-fi connection). If you provide correct APN your device will have mobile internet after your credential will be verified.

But there is one more trick I want to show. It allow to raise mobile connection even with wifi connected. ConnectivityManager#startUsingNetworkFeature method is used to request network for you application. You need to specify which network the request pertains to (first param) and the name of the feature to be used (second param). Typical request will looks like:
    connectivityManager.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, "enableHIPRI");

This means, that you want to enable High Priority (HIPRI) Mobile data connection over mobile network. More about first argument you can read in documentation to ConnectivityManager. List of available features you can found in internal interface Phone:
   // "Features" accessible through the connectivity manager  
   static final String FEATURE_ENABLE_MMS = "enableMMS";  
   static final String FEATURE_ENABLE_SUPL = "enableSUPL";  
   static final String FEATURE_ENABLE_DUN = "enableDUN";  
   static final String FEATURE_ENABLE_HIPRI = "enableHIPRI";  
   static final String FEATURE_ENABLE_DUN_ALWAYS = "enableDUNAlways";  
   static final String FEATURE_ENABLE_FOTA = "enableFOTA";  
   static final String FEATURE_ENABLE_IMS = "enableIMS";  
   static final String FEATURE_ENABLE_CBS = "enableCBS";  

But you need to remember, that all requested network features are active only when your application is 'alive' (i.e. not stopped or killed by system).