Archive

Archive for the ‘Researches’ Category

Android Volley Tutorial

February 1, 2014 2 comments

Volley is an android library released by Google that can make your life easier when dealing with network operations. In this blog post I will mention the main features of the library and show a few example usages, in particular, how to make a request, how to download images, and how to use the cache.

Features of Volley library

a) Automatically schedules the network requests

b) Supports request prioritization. This means that you can load content depending of priorities, for example the main content could have a high priority, but the images a low priority.

c) Provides transparent disk and memory cache that allows for quick reloading of data. Transparent cache means that the caller doesn’t have to know about the existence of the cache. That is, the cache is implemented automatically. You do, however, have the possibility to disable the caching.

d) Provides a good API for canceling requests. You can cancel a single request, or cancel requests depending on some filters.

Besides the great features that Volley comes with, you don’t have to use it for everything. Volley is great for RPC-style network operations that populate UI, a typical example would be loading thumbnail images into a ListView, but not very good for streaming operations like downloading a video or mp3.

Getting started with Volley

1. Clone the Volley project:
git clone https://android.googlesource.com/platform/frameworks/volley
2. Import the library into your project

The most frequent classes of Volley that you will work with are RequestQueue and Request, and ImageLoader when dealing with images loading.

RequestQueue is used for dispatching requests to the network. It is recommended to create it early and use it as a Singleton.
Request is the base class for creating network requests (GET, POST).
ImageLoader is a helper class that handles loading and caching images from remote URLs.

Step 1: VolleySingleton.java

As recommended, lets create first a Singleton class that will return on demand an instance of RequestQueue and one of ImageLoader.

public class VolleySingleton {

    private static VolleySingleton instance;
    private RequestQueue requestQueue;
    private ImageLoader imageLoader;

    private VolleySingleton(Context context) {
        requestQueue = Volley.newRequestQueue(context);

        imageLoader = new ImageLoader(requestQueue, new ImageLoader.ImageCache() {
            private final LruCache<String, Bitmap> cache = new LruCache<String, Bitmap>(20);


            @Override
            public Bitmap getBitmap(String url) {
                return cache.get(url);
            }

            @Override
            public void putBitmap(String url, Bitmap bitmap) {
                cache.put(url, bitmap);
            }
        });
    }


    public static VolleySingleton getInstance(Context context) {
        if (instance == null) {
            instance = new VolleySingleton(context);
        }
        return instance;
    }

    public RequestQueue getRequestQueue() {
        return requestQueue;
    }

    public ImageLoader getImageLoader() {
        return imageLoader;
    }
}
Step 2: Add internet permission
<uses-permission android:name="android.permission.INTERNET" /> 
Step 3: Create an instance of RequestQueue
RequestQueue queue = VolleySingleton.getInstance(this).getRequestQueue();
Step 4: Create the request

Volley comes with a class called JsonRequest that you can use to make requests to a server that returns a json response.
However, in this example we will query an RSS feed which returns a response in XML format. Volley does not include a similar class for handling xml responses, like JsonRequest, but it has StringRequest class that can be used to retrieve the response body as a String.

There are two ways to construct a StringRequest:

StringRequest(int method, String url, Listener<String> listener,
            ErrorListener errorListener)

or

StringRequest(String url, Listener<String> listener, ErrorListener errorListener)

The second constructor does not take the request method as a parameter, when not specified, a GET request is created.

Listener is a callback interface for delivering the result, and
ErrorListener is a callback interface for delivering error responses.

Example:

String url = "http://www.pcworld.com/index.rss";
StringRequest request = new StringRequest(url, new Listener<String>() {

            @Override
            public void onResponse(String response) {
                // we got the response, now our job is to handle it 
                parseXmlResponse(response); 
            }
        }, new ErrorListener() {

            @Override
            public void onErrorResponse(VolleyError error) {
               //something happened, treat the error.
            }
        });
Step 6: Execute the request
queue.add(request);

And that is all! The execution of the request implies its addition to the RequestQueue.

Step 7: Loading thumbnail images

Loading images can be done easy if you replace the android’s ImageView with Volley’s NetworkImageView:

<com.android.volley.toolbox.NetworkImageView
        android:id="@+id/icon"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:src="@drawable/default_placeholder" />

then use setImageUrl() and you are done!

String url = "..."; // URL of the image
ImageView imageView = (ImageView)view.findViewById(R.id.image);
ImageLoader imageLoader = VolleySingleton.getImageLoader(); 
imageView.setImageUrl(url, imageLoader); 

If, for some reason, you don’t want or can’t use NetworkImageView, then there’s an alternate method.
You can use the get() method of ImageLoader class which accepts the image url and an instance of ImageListener:

ImageLoader imageLoader = VolleySingleton.getImageLoader(); 
imageLoader.get(url, new ImageListener() {
             
            public void onErrorResponse(VolleyError error) {
                imageView.setImageResource(R.drawable.icon_error); // set an error image if the download fails
            }
             
            public void onResponse(ImageContainer response, boolean arg1) {
                if (response.getBitmap() != null) {
                    imageView.setImageBitmap(response.getBitmap());
                } 
            }
        });
Reading from cache

One of the Volley’s features is that it provides transparent disk and memory cache. The cache is implemented automatically for classes that extends Request, such as JsonRequest and StringRequest.

To read the cache:

Entry entry = queue.getCache().get(url);
if(entry!=null){
     String data = new String(entry.data, "UTF-8");
     // process data
}

To turn off the cache:

request.setShouldCache(false);

to remove the cache for a specific request:

queue.getCache().remove(url);

to clear all cache:

queue.getCache().clear();

to invalidate the cache: this will allow to display the cached data until the response is received. When the response is received, it will automatically override the cached data.

queue.getCache().invalidate(url, true);

For more details about Volley you can watch the full video at: https://developers.google.com/events/io/sessions/325304728

Using Maven to save the build time in a properties file

Create a folder called build in the root directory of the project, and a file build.properties with the following content:

build.time=@buildtime@

Using the maven replacer plugin we can replace the token @buildtime@ within the build.properties file with the build timestamp value, and then let the Android application read that value and use it.

 
<plugins>
     <plugin>
         <groupId>com.google.code.maven-replacer-plugin</groupId>
         <artifactId>replacer</artifactId>
         <version>1.5.2</version>
         <executions>
            <execution>
               <phase>validate</phase>
               <goals>
                  <goal>replace</goal>
               </goals>
            </execution>
         </executions>
         <configuration>
            <file>build/build.properties</file>
               <outputFile>res/raw/build.properties</outputFile>
               <replacements>
                  <replacement>
                     <token>@buildtime@</token>
                     <value>${maven.build.timestamp}</value>
                  </replacement>
               </replacements>
        </configuration>
   </plugin>
</plugin>

Run this task with mvn validate command. This will do nothing but replace the tokens from build.properties file with the timestamp value, and output the result to a new file in res/raw.

From here on the file can be accessed as a raw resource and read as a regular properties file.

Reading the properties file:

InputStream rawResource = resources.openRawResource(R.raw.build);
Properties properties = new Properties();
properties.load(rawResource);
String buildTime = properties.getProperty("build.time");

Using Maven in Android to build for different environments (dev, staging, prod, etc)

If you are working on a relatively complex project, chances are that you may need to build the application against different environments, such as a development, a staging, and a production environment. Assuming you are using Maven as a build tool, here’s one solution how Maven could help with this.

For the sake of this example let assume that you are working on an Android app that consumes web services. You have a dedicated development environment where you spent most of the time, but once every two weeks you need to make a version of the app that is built for production.

Let assume that the endpoint for the testing environment is dev.mysite.com, and for the production environment is: prod.mysite.com.
But as an aspiring developer and after reading a bunch of books about best practices, you can no longer accept to just go and manually edit the source files by changing all over the place one environment with another, and you ask yourself if Maven could help with this.

It can, and here’s how.
The main idea is to store all the properties, in this particular example all the urls, in separate resource files. Then, using maven resource plugin copy the corresponding property file into values/environment.xml.

1. In your project root directory create following directory structure:
environment/dev/environment.xml
environment/prod/environment.xml

maven environment

2. Then fill the content of the resource files with appropriate values.
/dev/environment.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="url">http://dev.mysite.com</string>
</resources>

/prod/environment.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="url">http://prod.mysite.com</string>
</resources>

3. Add the maven resource plugin to pom.xml by specifying the phase when the copy action should be executed, the resources, and the output directory:

//...
<plugins>
    <plugin>
        <artifactId>maven-resources-plugin</artifactId>
        <version>2.4.3</version>
        <executions>
             <execution>
                <id>copy-string-resources</id>
                <phase>validate</phase> <!-- when to execute copy operation -->
                <goals>
                    <goal>copy-resources</goal>
                </goals>
                <configuration>
                    <resources>
                        <resource>
                            <directory>environment/${environment}/</directory>
                            <includes>
                               <include>environment.xml</include>
                               <filtering>true</filtering>
                            </includes>
                        </resource>
                    </resources>
                    <overwrite>true</overwrite>
                    <outputDirectory>${basedir}/res/values/</outputDirectory>
                </configuration>
      </plugin>
</plugins>

4.1 From this point on, you can automate the preparation of environment by creating 2 run configurations:
mvn validate -Denvironment=dev
mvn validate -Denvironment=prod

that will do nothing but copy the appropriate resources from evironment/${environment}/environment.xml, into values/environment.xml

Now, every time you’ll need to prepare a build against a specific environment, the only thing you’ll need to do will be to run one of those commands.

4.2 Another option, to make the things even more compact, is instead of passing the environment like this: -Denvironment=dev, would be to create 2 profiles in pom.xml:

<profiles>
   <profile>
       <id>development</id>
       <properties>
           <environment>dev</environment>
       </properties>
   </profile>

   <profile>
       <id>prod</id>
       <properties>
           <environment>prod</environment>
       </properties>
   </profile>
</profiles>

and then create 2 run configurations with appropriate profile:
mvn validate -P development
mvn validate -P prod

For easy access at environment resources you could create a class like this that will return all the environment properties your applications uses:

public class ApplicationEnvironment{
	
	//...
	
	public String getServerUrl(){
		return resources.getString(R.string.url);
	}	
}

Dealing with AsyncTask and Screen Orientation

A common task in Android is to perform some background activity in another thread, meanwhile displaying a ProgressDialog to the user. Example of these tasks include downloading some data from internet, logging into an application, etc. Implementing an AsyncTask is fairly a simple job, the big challenge is how to handle it properly when an orientation change occurs.

In this article I will walk though a series of potential solutions to address the screen orientation issues when using an AsyncTask.

So, lets create a proof of concept application that makes use of an AsyncTask which does not handle configuration changes yet, and then present a few solutions.

Here’s the AsyncTask implementation that we will be using during the tutorial:

public class AsyncTaskExample extends AsyncTask<String, Integer, String> {

	private final TaskListener listener;

	public AsyncTaskExample(TaskListener listener) {
		this.listener = listener;
	}

	@Override
	protected void onPreExecute() {
		listener.onTaskStarted();
	}

	@Override
	protected String doInBackground(String... params) {
		for (int i = 1; i <= 10; i++) {
			Log.d("GREC", "AsyncTask is working: " + i);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		return "All Done!";
	}

	@Override
	protected void onPostExecute(String result) {
		listener.onTaskFinished(result);
	}
}

- doInBackground() – this will be called by the AsyncTask on a background thread, and performs all the heavy work. For the sake of this example, I just wrote a simple loop  with a delay of 1 sec between iterations to simulate a task that takes some time.
- The constructor of the class takes a listener as a parameter. The listener will be used to delegate the work of onPreExecute()/onPostExecute() to the calling Activity.

This is the interface definition used by AsyncTaskExample:

public interface TaskListener {
	void onTaskStarted();

	void onTaskFinished(String result);
}

And here’s the usage of AsyncTaskExample (the problematic case):

public class MainActivity extends Activity implements TaskListener, OnClickListener {

	private ProgressDialog progressDialog;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		findViewById(R.id.start).setOnClickListener(this);
	}

	@Override
	public void onClick(View v) {
		if (v.getId() == R.id.start) {
			new AsyncTaskExample(this).execute();
		}
	}

	@Override
	public void onTaskStarted() {
		progressDialog = ProgressDialog.show(CopyOfMainActivity.this, "Loading", "Please wait a moment!");
	}

	@Override
	public void onTaskFinished(String result) {
		if (progressDialog != null) {
			progressDialog.dismiss();
		}
	}
}

The Activity implements the TaskListener interface and provides appropriate implementation for its methods,  displaying the ProgressDialog when the task is started, and dismissing it when the task is finished. The AsyncTask is fired when clicking on a button.

Now, if you run this example without changing the screen orientation, the AsyncTask will start and finish its work normally. Problems begin to appear when the device orientation is changed while the AsyncTask is in the middle of the work. The application will crash, and an exception similar to these ones will be thrown: java.lang.IllegalArgumentException: View not attached to window manager, or Activity has leaked window com.android.internal.policy….

The cause relies in the Activity life cycle. A change in device orientation is interpreted as a configuration change which causes the current activity to be destroyed and then recreated. Android calls onPause(), onStop(), and onDestroy() on currently instance of activity, then a new instance of the same activity is recreated calling onCreate(), onStart(), and onResume(). The reason why Android have to do this, is because depending of screen orientation, portrait or landscape, we may need to load and display different resources, and only through re-creation Android can guarantee that all our resources will be re-requested.

But don’t panic, you are not alone, there are several solutions that will help us to deal with this situation.

Solution 1 – Think twice if you really need an AsyncTask.

AsyncTasks are good for performing background work, but they are bound to the Activity which adds some complexity. For things like making HTTP requests to a server perhaps you should consider an IntentService. IntentService used in conjunction with a BroadcastReceiver or ResultReceiver to deliver results, could do a better job than an AsyncTask in certain situations.

Solution 2 – Put the AsyncTask in a Fragment.

Using fragments probably is the cleanest way to handle configuration changes. By default, Android destroys and recreates the fragments just like activities, however, fragments have the ability to retain their instances, simply by calling: setRetainInstance(true), in one of its callback methods, for example in the onCreate().

There’s however one aspect that should be taken in consideration in order to achieve the desired result. Our AsyncTask uses a ProgressDialog to signal when the AsyncTask is started, and dismisses it when the task is done. This complicates a bit the things because even if we are using setRetainInstance(true), we should close all windows and dialogs when the Activity is destroyed, otherwise we will get an: Activity has leaked window com.android.internal.policy…  exception. This happens when you try to show a dialog after you have exited the Activity.

In order to address this issue, we will add some logic to keep track of AsyncTask status (running/not running). We will dismiss the ProgressDialog when the fragment is detached from activity, and check in onActivityCreated() the status of AsyncTask. If the status is “running”, this means we are returning from a screen orientation and we will just re-create and display the ProgressDialog to show that the AsyncTask is still working.

public class ExampleFragment extends Fragment implements TaskListener, OnClickListener {

	private ProgressDialog progressDialog;
	private boolean isTaskRunning = false;
	private AsyncTaskExample asyncTask;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setRetainInstance(true);
	}

	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		super.onActivityCreated(savedInstanceState);
		// If we are returning here from a screen orientation
		// and the AsyncTask is still working, re-create and display the
		// progress dialog.
		if (isTaskRunning) {
			progressDialog = ProgressDialog.show(getActivity(), "Loading", "Please wait a moment!");
		}
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
		View view = inflater.inflate(R.layout.fragment_layout, container, false);
		Button button = (Button) view.findViewById(R.id.start);
		button.setOnClickListener(this);
		return view;
	}

	@Override
	public void onClick(View v) {
		if (!isTaskRunning) {
			asyncTask = new AsyncTaskExample(this);
			asyncTask.execute();
		}
	}

	@Override
	public void onTaskStarted() {
		isTaskRunning = true;
		progressDialog = ProgressDialog.show(getActivity(), "Loading", "Please wait a moment!");
	}

	@Override
	public void onTaskFinished(String result) {
		if (progressDialog != null) {
			progressDialog.dismiss();
		}
		isTaskRunning = false;
	}

	@Override
	public void onDetach() {
		// All dialogs should be closed before leaving the activity in order to avoid
		// the: Activity has leaked window com.android.internal.policy... exception
		if (progressDialog != null && progressDialog.isShowing()) {
			progressDialog.dismiss();
		}
		super.onDetach();
	}
}
Solution 3 – Lock the screen orientation

You could do this in 2 ways:

a) permanently locking the screen orientation of the activity, specifying the screenOrientation attribute in the AndroidManifest with “portrait” or “landscape” values:

<activity
   android:screenOrientation="portrait"
   ...  />

b) or, temporarily locking the screen in onPreExecute(), and unlocking it in onPostExecute(), thus preventing any orientation change while the AsyncTask is working:

@Override
public void onTaskStarted() {
	lockScreenOrientation();
	progressDialog = ProgressDialog.show(CopyOfCopyOfMainActivity.this, "Loading", "Please wait a moment!");
}

@Override
public void onTaskFinished(String result) {
	if (progressDialog != null) {
		progressDialog.dismiss();
	}
	unlockScreenOrientation();
}

private void lockScreenOrientation() {
	int currentOrientation = getResources().getConfiguration().orientation;
	if (currentOrientation == Configuration.ORIENTATION_PORTRAIT) {
		setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
	} else {
		setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
	}
}

private void unlockScreenOrientation() {
	setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
}
Solution 4 – Prevent the Activity from being recreated.

This is the easiest way to handle configuration changes, but the less advised. The only thing you need to do is to specify the configChanges attribute followed by a list of values that specifies when the activity should prevent itself from restarting.

<activity
   android:configChanges="orientation|keyboardHidden"
   android:name=".MainActivity"
   .... />

Using this approach however, is not recommended, and this is clearly stated in the Android documentation: Using this attribute should be avoided and used only as a last-resort.

You may ask what’s wrong with this approach. Well, if you build the above example against Android 2.2 it will work fine, but if you build it against Android 3.0 and higher, you may notice that the application still crashes on orientation change. This is because starting  with Android 3.0 you need also to handle the screenSize, and smallestScreenSize:

<activity
   android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize"
   android:name=".MainActivity"
   .... />

As it turns out, not only a screen orientation causes the Activity to recreate, there are also other events which may produce configuration changes and restart the Activity, and there’s a good chance that we won’t handle them all. This is why the use of this technique is discouraged.

Caching Objects in Android Internal Storage

April 7, 2013 8 comments

Android provides several options for persisting application data, such as SQLite Databases, SharedPreferences, internal and external storage.

In this post we’ll take a look how we can use the internal storage to persist application data. By default, files saved to internal storage are private to the application and they cannot be accessed by other applications. When the application is uninstalled, the files are removed.

To create and write a file to internal storage, openFileInput(); should be used. This opens a private file associated with the Context’s application package for writing. If the file does not already exits, then it is first created.

openFileInput() returns a FileInputStream, and we could use its write() method, which accepts a byte array as argument, to write the data. However, in the below example we will wrap the FileInputStream into an ObjectOutputStream which provides 2 convenient methods  for writing and reading objects: writeObject() and readObject().

So, lets  pretend that we need to save a List of some objects. The model class of our object looks like this:

public class Entry implements Serializable{
   private String name;

   public Entry(String name) {
      this.name = name;
   }

   public String getName() {
      return name;
   }
}

Make sure that the model class implements Serializable, otherwise you may get a java.io.NotSerializableException when attempting to write the object on internal storage.

Below is the utility class that provides 2 methods, one for storing objects to internal storage, and another for retrieving objects from internal storage.

public final class InternalStorage{

   private InternalStorage() {}

   public static void writeObject(Context context, String key, Object object) throws IOException {
      FileOutputStream fos = context.openFileOutput(key, Context.MODE_PRIVATE);
      ObjectOutputStream oos = new ObjectOutputStream(fos);
      oos.writeObject(object);
      oos.close();
      fos.close();
   }

   public static Object readObject(Context context, String key) throws IOException,
         ClassNotFoundException {
      FileInputStream fis = context.openFileInput(key);
      ObjectInputStream ois = new ObjectInputStream(fis);
      Object object = ois.readObject();
      return object;
   }
}

An this is how InternalStorage class can be used to persist and retrieve data from internal storage.

// The list that should be saved to internal storage.
List<Entry> entries = new ArrayList<Entry>();
entries.add(new Entry("House"));
entries.add(new Entry("Car"));
entries.add(new Entry("Job"));

try {
   // Save the list of entries to internal storage
   InternalStorage.writeObject(this, KEY, entries);

   // Retrieve the list from internal storage
   List<Entry> cachedEntries = (List<Entry>) InternalStorage.readObject(this, KEY);

   // Display the items from the list retrieved.
   for (Entry entry : cachedEntries) {
     Log.d(TAG, entry.getName());
   }
} catch (IOException e) {
   Log.e(TAG, e.getMessage());
} catch (ClassNotFoundException e) {
   Log.e(TAG, e.getMessage());
}

 

Using Custom Fonts in Android

December 20, 2012 4 comments

By default Android comes with three standard fonts: Droid Sans (default font), Droid Serif, and Droid Sans Mono. They all can be applied to any view that supports styling, such as TextView, Button, by specifying the “android:typeface” attribute in the XML declaration with any of these values: sans, serif, monospace.


<TextView
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:text="Sans"
   android:typeface="sans" />

<TextView
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:text="Serif"
   android:typeface="serif" />

<TextView
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:text="Monospace"
   android:typeface="monospace" />

android standard fonts

 

Using custom fonts in Android is pretty straightforward. First find a free font and put it in the assets/fonts directory. (It’s not mandatory to have a /fonts directory, but if I have a lot of stuff in the /assets directory I organize them in separate directories). Then get a reference to your TextView and create a Typeface object specifying the font path. Lastly, apply the typeface to the TextView.

In this particular example I used the font: christmaseve.ttf

TextView textView = (TextView) findViewById(R.id.textView);
Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/christmaseve.ttf");
textView.setTypeface(tf);

android custom fonts

 

RuntimeException: Native typeface cannot be made

If you get this exception while trying to integrate the custom font into your application, make sure the path to the font file is correct, and the font name is spelled correctly. I noticed I was getting this exception when my font path was misspelled, for example writing “.tff” instead of “.ttf”, or forgetting to add the “fonts/” prefix to the path.

Custom font used in this example provided by: http://bythebutterfly.com

Integrating Google Analytics SDK (V2) with Android

November 3, 2012 17 comments

The Google Analytics SDK for Android makes it easy for developers to collect valuable statics about how the users are using their app.

Here are some features that Android Google Analytics SDK offers:

  • The number of active users that are using the application
  • Usage of specific features
  • The number and type of application crashes
  • From where in the world the application is used
  • And many other useful metrics.

Just to illustrate the integration process lets create a simple proof of concept application with 2 activities: MainActivity and AboutActivity, and 2 buttons: Rate and Share.

Our mission is to integrate Google Analytics SDK with the application, to:

  • track activity views, (MainActivity and About)
  • track events (how many times the buttons “Rate”, and “Share” are clicked)

android google analytics sdk

If you are searching for Google Analytics I’m assuming you are already pretty familiar with Android and could create the proof of concept application yourself, so I will skip this step and concentrate solely on integration.

 

1. Downloading the SDK

Go to downloads page and download GoogleAnalyticsAndroid.zip Version 2.0. Extract the archive and add libGoogleAnalyticsV2.jar to your project’s /libs directory.

At the moment of writing this post, Google provides two versions: version 1.5.1 (legacy), and version 2.0 beta. Still if the Version 2 of SDK is beta, I highly suggest you choose this version, over the 1.5.1 (legacy).
The reason not to choose SDK 1.5.1 is that it uses a tracking model that is designed to track visitors to traditional websites and interaction with widgets in traditional web pages.

The new “App” profiles and reports will only accept data from version 2 or higher of the SDK.

 

2. Creating a Google Analytics account

Before starting to use the SDK you first must create an account at: http://www.google.com/analytics/

  1. Sign in to your account.
  2. Click Admin.
  3. Click Account list (just below the menu bar)
  4. Click +New Account
  5. When asked what you would like to track, select App property.android app profile
  6. Enter all the necessary information and click Get Tracking ID.

Now that you have a Tracking ID, you can begin the integration with the application. The first step is to update the AndroidManifest file.

 

3. Updating AndroidManifest file.

Add folowing permissions to the AndroidManifest file:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

 

4. Creating the analytics.xml file

In version 2 of Google Analytics SDK for Android, the tracking settings are managed from an xml resource file called: analytics.xml. You will need to create this file in res/values directory, and add your tracking ID as well as other settings here.


<?xml version="1.0" encoding="utf-8"?>
<resources>

   <!-- Replace placeholder ID with your tracking ID -->
   <string name="ga_trackingId">UA-00000000-0</string>

   <!-- Enable Activity tracking -->
   <bool name="ga_autoActivityTracking">true</bool>

   <!-- Enable debug -->
   <bool name="ga_debug">true</bool>

   <!-- The screen names that will appear in your reporting -->
   <string name="com.testgoogleanalytics.MainActivity">MainActivity</string>
   <string name="com.testgoogleanalytics.About">About</string>

   <!--
   The inverval of time after all the collected data
   should be sent to the server, in seconds.
   -->
   <integer name="ga_dispatchPeriod">30</integer>

</resources>

 

5. Tracking activities.

To track activities add the tracking methods to the onStart() and onStop()  of each of your activities.


// Example of tracking MainActivity
public class MainActivity extends Activity {
   @Override
   public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
   }

   @Override
   protected void onStart() {
      super.onStart();
      EasyTracker.getInstance().activityStart(this); // Add this method
   }

   @Override
   protected void onStop() {
      super.onStop();
      EasyTracker.getInstance().activityStop(this); // Add this method
   }
}

One thing to note here is that EasyTraker requires a context before you can use it. If you attempt to call any of its methods but did not pass first a context, you may end up with an IllegalStateException.

In the above example, in  the onStart()  and onStop() methods the context is passed as an argument to activityStart() and activityStop(), but  if you need to make EasyTracker calls in other classes or methods, you’ll need to call EasyTracker’s setContext(Context context) method first:

Context context= this;  // Get current context.
EasyTracker.getInstance().setContext(context);  // Set context
// EasyTracker is now ready for use.

 

6. Tracking events

Tracking events is just as easy as tracking activities, you just need a Tracker object and call the trackEvent(String category, String action, String label, int value) method.

public class MainActivity extends Activity {

   private Tracker tracker;

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

      // Set context
      EasyTracker.getInstance().setContext(getApplicationContext());
      // Instantiate the Tracker
      tracker = EasyTracker.getTracker();

      // Add tracking functionality to "Rate" button
      Button rate = (Button) findViewById(R.id.rate);
      rate.setOnClickListener(new OnClickListener() {
         @Override
         public void onClick(View arg0) {
            // The rest of your code
            tracker.trackEvent("Buttons Category", "Rate", "", 0L);
         }
      });

      // Add tracking functionality to "Share" button....
   }
}

In this particular example I don’t need a label nor a value, that is why I set for the last 2 parameters of trackEvent() method, an empty string a 0 (zero), but depending of your needs you may populate them with some data.

 

7. Debugging

Debugging helps you deal with troubleshooting, and make you sure that the data actually is sent to the server. To set the Google Analytics in debug mode, add the following setting in the analytics.xml


<bool name="ga_debug">true</bool>

Once your are in debug mode, you can watch the log information in LogCat:

 

Waiting for the big moment!

If everything is configured correctly, the reports should appear on live. Usually it takes about 24 hours to see the data in your account.

android actions google analytics

 

 

What happens if my application is used when no network is available?

Just in case you asked this yourself…, all the events are persisted in a local storage, and they will be sent the next time your app is running and dispatch is called.

 

Last but not least

One important thing not to be forgotten: you must indicate to your users, either in the application itself or in your terms of service, that you reserve the right to anonymously track and report a user’s activity inside of your app.

Android Google Analytics SDK offers more than tracking activities and events, see: https://developers.google.com/analytics/devguides/collection/android/v2/ to get the most out of it.

Please visit the Android Tutorials page for more tutorials.

Android Asset Studio – The easiest way to create icons for your android apps!

July 31, 2012 3 comments

Android asset studio

Android Asset Studio is an online utility that lets you generate all kind of icons you may need for your android applications, starting with launcher icons, action bar and tab icons, notification icons, and menu icons. It even includes a simple 9-patch generator allowing you to create 9-patch images.

One of the trickier parts when creating the icons is that you should create them for all kinds of resolutions: ldpi, mdpi, hdpi, and xhdpi. With Android Asset Studio this is as simple as uploading an image. The tool generates automatically for you all the versions of the icon under all resolutions, and make them available as a downloadable zip archive.

The icons may be generated from an image uploaded, or from a clipart library, or from text. It’s a very convenient tool and I highly recommend using it if you want to have professional, good looking icons on all resolutions.

Android – Scheduling an application to start later.

July 2, 2012 8 comments

Recently I have been working on a simple application that should have the ability to start itself after a period of time, after the application is closed. Hopefully, it turned out that this is quite simple to implement, and to achieve this, the AlarmManager in conjuction with a BroadcastReceiver can be used.

The basic idea is as follows: the AlarmManger registers an intent, when the alarm goes off, the intent that had been registered automatically will start the target application if it is not already running. The BroadcastReceiver will be listening for that intent, and when the intent is received, it will start the desired activity from the application.

The broadcast receiver implementation looks like this:


public class OnAlarmReceive extends BroadcastReceiver {

  @Override
  public void onReceive(Context context, Intent intent) {

     Log.d(Globals.TAG, "BroadcastReceiver, in onReceive:");

     // Start the MainActivity
     Intent i = new Intent(context, MainActivity.class);
     i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
     context.startActivity(i);
  }
}

Register the OnAlarmReceive in the AndroidManifest file:


<application
   android:icon="@drawable/ic_launcher"
   android:label="@string/app_name" >

   // ......

   <receiver
      android:name=".OnAlarmReceive" />

</application>

And finally, here’s how to setup the alarm:

/**
* Sets up the alarm
*
* @param seconds
*            - after how many seconds from now the alarm should go off
*/
private void setupAlarm(int seconds) {
  AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
  Intent intent = new Intent(getBaseContext(), OnAlarmReceive.class);
  PendingIntent pendingIntent = PendingIntent.getBroadcast(
     MainActivity.this, 0, intent,
     PendingIntent.FLAG_UPDATE_CURRENT);

  Log.d(Globals.TAG, "Setup the alarm");

  // Getting current time and add the seconds in it
  Calendar cal = Calendar.getInstance();
  cal.add(Calendar.SECOND, seconds);

  alarmManager.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pendingIntent);

  // Finish the currently running activity
  MainActivity.this.finish();
}

The last line from the code – finishing the current activity – is optional of course, but in case you need to finish the activity, here’s how to do.

For a live demo of the code, download the Amazing Cracked Screen application and see how it works. There you have the possibility to set up the delay in seconds when the application should start later and show the “broken” screen.

How to create popups in Android

In this post I’ll show you how to create a popup window in Android. A popup window can be used to display an arbitrary view, and it can be very convenient in cases when you want to display an additional information, but don’t want or it’s not appropriate to launch a new activity or  display a dialog.

The final output should look like this:

Android Popup

We will use the PopupWindow class to create the popup.

One thing I would like to mention is that we want the popup to be attached to the button that opened it. For example if the “Show Popup” button from the screenshot above would be positioned in the middle of the screen, we want the popup window stick to the button’s position. To achieve this, first we should get the button’s “x” and “y” position on the screen, and pass them to the popup window. Then will we use an offset to align the popup properly – a bit to the right, and a bit down, so it won’t overlap the whole button.

Another think I would like to mention is that we will use a 9 patch background image for the popup, so it will look more fancy. But of course you can skip it and put any background you want, or no background at all.

9 patch image:

9 patch image

Put the image into res/drawable directory.

 

1. Create a new project in Eclipse:
Project: TestPopup
Activity: TestPopupActivity

2. Open layout/main.xml file and add a button


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#CCC"
android:orientation="vertical" >

<Button
   android:id="@+id/show_popup"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:text="Show Popup" />

</LinearLayout>

3. Create a new layout file: layout/popup_layout.xml that defines the layout of popup.


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="wrap_content"
   android:id="@+id/popup"
   android:layout_height="wrap_content"
   android:background="@drawable/popup_bg"
   android:orientation="vertical" >

<TextView
   android:id="@+id/textView1"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:text="Popup"
   android:textAppearance="?android:attr/textAppearanceLarge" />

<TextView
   android:id="@+id/textView2"
   android:layout_marginTop="5dp"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:text="This is a simple popup" />

<Button
   android:id="@+id/close"
   android:layout_marginTop="10dp"
   android:layout_gravity="center_horizontal"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:text="Close" />

</LinearLayout>

 

4. And now the most interesting part. Open the TestPopupActivity and fill it with below code. Carefully read the comments to understand what’s going on.


public class TestPopupActivity extends Activity {

//The "x" and "y" position of the "Show Button" on screen.
Point p;

@Override
public void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.main);

   Button btn_show = (Button) findViewById(R.id.show_popup);
   btn_show.setOnClickListener(new OnClickListener() {
     @Override
     public void onClick(View arg0) {

       //Open popup window
       if (p != null)
       showPopup(TestPopupActivity.this, p);
     }
   });
}

// Get the x and y position after the button is draw on screen
// (It's important to note that we can't get the position in the onCreate(),
// because at that stage most probably the view isn't drawn yet, so it will return (0, 0))
@Override
public void onWindowFocusChanged(boolean hasFocus) {

   int[] location = new int[2];
   Button button = (Button) findViewById(R.id.show_popup);

   // Get the x, y location and store it in the location[] array
   // location[0] = x, location[1] = y.
   button.getLocationOnScreen(location);

   //Initialize the Point with x, and y positions
   p = new Point();
   p.x = location[0];
   p.y = location[1];
}

// The method that displays the popup.
private void showPopup(final Activity context, Point p) {
   int popupWidth = 200;
   int popupHeight = 150;

   // Inflate the popup_layout.xml
   LinearLayout viewGroup = (LinearLayout) context.findViewById(R.id.popup);
   LayoutInflater layoutInflater = (LayoutInflater) context
     .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
   View layout = layoutInflater.inflate(R.layout.popup_layout, viewGroup);

   // Creating the PopupWindow
   final PopupWindow popup = new PopupWindow(context);
   popup.setContentView(layout);
   popup.setWidth(popupWidth);
   popup.setHeight(popupHeight);
   popup.setFocusable(true);

   // Some offset to align the popup a bit to the right, and a bit down, relative to button's position.
   int OFFSET_X = 30;
   int OFFSET_Y = 30;

   // Clear the default translucent background
   popup.setBackgroundDrawable(new BitmapDrawable());

   // Displaying the popup at the specified location, + offsets.
   popup.showAtLocation(layout, Gravity.NO_GRAVITY, p.x + OFFSET_X, p.y + OFFSET_Y);

   // Getting a reference to Close button, and close the popup when clicked.
   Button close = (Button) layout.findViewById(R.id.close);
   close.setOnClickListener(new OnClickListener() {

     @Override
     public void onClick(View v) {
       popup.dismiss();
     }
   });
}
}
Follow

Get every new post delivered to your Inbox.

Join 484 other followers

%d bloggers like this: