Monday 23 June 2014

Ordered Broadcasts

There are two types of broadcasts in Android: normal and ordered. The following table shows the main differences:


Normal
Ordered
Way of delivery
Normal broadcasts are delivered to the available receivers asynchronously, in an unspecified order
Ordered broadcasts are delivered to the available receivers one at a time, in a specified order (the order depends on the android:priority attribute of the different receivers in the AndroidManifest file)
Feedback
With normal broadcasts no feedback can be sent to the broadcaster
With ordered broadcasts the receiver can send information to the broadcaster (using the methods abortBroadcast(), seResultCode(), setResultData()


Tip: in a receiver (handling ordered broadcasts) you can call the method abortBroadcast() to make sure that the broadcast is not sent to other receivers. If you combine this method with a high value for the android:priority attribute, you can make sure that your receiver is the only one to handle that broadcast (SMS apps can use this technique).

BroadcastReceiver in Android

BroadcastReceiver

Let’s see how a BroadcastReceiver can handle ordered broadcasts (se the comments in the code for more information):
public class MyReceiver extends BroadcastReceiver {
    [...]
    public void onReceive(Context context, Intent intent) {
        //is this an ordered broadcast or not?
        if(isOrderedBroadcast() {
            //here you can handle the broadcast    
            [...]

            //here you can send information back to the broadcaster
            setResultCode(Activity.RESULT_OK);
            setResultData(“here you can pass a String”);

            //you can also create complex data to send to the broadcaster
            Bundle myBundle = getResultExtras(true);
            myBundle.put [...] //code omitted for brevity
        }
    }
}


Broadcaster

Sending an ordered broadcast is quite simple. Let’s look at the code:
Intent int = new Intent(YOUR_FILTER);
sendOrderedBroadcast(int, responseReceiver, null, RESULT_OK, null, null);
As you can see you just have to create an Intent with the filter registered for the BroadcastReceiver MyReceiver and call the method sendOrderedBroadcast. This method takes a BroadcastReceiver (responseReceiver) as a parameter: this is the receiver that will receive the information sent back by the BroadcastReceiver MyReceiver.
So you finally have to register the BroadcastReceiver responseReceiver (to handle the results) in the following way:
BroadcastReceiver responseReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        //here you can retrieve the results sent by MyReceiver
        String str = getResultData();

        //here you can retrieve the complex data sent by MyReceiver
        Bundle myBundle = getResultExtras(false);
        if(myBundle != null) {
            //here you can retrieve the data using myBundle.get... methods
        }
    }
}

Friday 13 June 2014

Creating a pie chart with aChart Engine

In many Android apps you may need to show data in graphical format (pie charts, bar charts, time charts, etc.). To do this you can write the code from scratch, or use one of the many third-party libraries available. One of the most used is certainly aChart Engine, and there are several good reasons for that:
  1. it is leight;
  2. it is free;
  3. it is relatively complete.

In this brief tutorial I will explain the most important features you must know to create a pie chart using aChart Engine.



Download and install the library

First of all you have to download the library (version 1.1.0) and set up your Eclipse project to use it. The steps are the following:
  1. donwload the library (jar file, version 1.1.0) from this link. You can find the complete documentation of the package here;
  2. open Eclipse; right click on the main project folder; select "Build Path" and "Configure Build Path..."; select "Libraries" tab; click on "Add external Jars..." and select the library Jar file you have downloaded.
Now your Eclipse project is ready to use the library. Of course, if you want to use the different classes, you first have to import them in your Activity (import org.achartengine.model.CategorySeries ... etc.). 

Source data

Let’s suppose we want to create a pie chart showing the distribution of the different Android versions, using the following data:
Kit Kat – 7.8%
Jelly Bean – 33%
Ice Cream Sandwich – 25%
Honeycomb – 17%
Gingerbread – 11%
Older – 6.2%

Each slice of the pie chart is represented by a different color.
The source data in Java is represented by three arrays, each with six elements:

String[] labels = new String[] {“Kit Kat”, “Jelly Bean”, “Ice Cream Sandwich”, “Honeycomb”, “Gingerbread”, “Older”};
double[] values = {7.8, 33, 25, 17, 11, 6.2};
int[] colors = {Color.RED, Color.BLUE, Color.GREEN, Color.MAGENTA, Color.YELLOW, Color.GRAY};

CategorySeries

The class CategorySeries of aChart Engine (org.achartengine.model.CategorySeries) is used to represent a series for the category charts like the pie ones.
We create an instance of this class and populate it with the previously showed source data (labels and values):

CategorySeries categorySeries = new CategorySeries(“Android versions”);
for(int i=0; i<labels.length; i++) {
    categorySeries.add(labels[i], values[i]);
}

DefaultRenderer

The class DefaultRenderer (org.achartengine.renderer.DefaultRenderer) is an abstract renderer used to format the charts.
We can create an instance of this class and specify how we want our pie chart to be rendered:

DefaultRenderer defaultRenderer = new DefaultRenderer();
defaultRenderer.setChartTitle(“Android versions”);
defaultRenderer.setChartTitleTextSize(30);
defaultRenderer.setZoomButtonsVisible(false);
...
NB: It is important to set the zoom buttons visibility to false, otherwise you may get a NullPointerException in the onDraw() method of the class GraphicalView (as far as I know, this should be a bug in the library).
The are of course many other formattings you can control using a DefaultRenderer: you can read the official documentation for more information.

To control the rendering of each slice of the pie chart (color, showing or not showing values, etc.) you can use the SimpleSeriesRenderer class (org.achartengine.renderer.SimpleSeriesRenderer): you just have to create an instance of this class for each slice, set the relevant data and add it to the previously defined DefaultRenderer:

for(int i=0; i<labels.length; i++) {
    SimpleSeriesRenderer simpleSeriesRenderer = new SimpleSeriesRenderer();
    simpleSeriesRenderer.setColor(colors[i]);
    simpleSeriesRenderer.setDisplayChartValues(true);
    ...
    defaultRenderer.addSeriesRenderer(simpleSeriesRenderer);
}

Starting a new Activity

To show our pie chart we first have to retrieve an Intent, populated with the relevant data, using the ChartFactory class:

Intent intPiechart = ChartFactory.getPieChartIntent(context, categorySeries, defaultRenderer, “Android versions”);
startActivity(intPieChart);

The new Activity must be declared in the AndroidManifest.xml file as well:

<activity android:name=”org.achartengine.GraphicalActivity”/>

Monday 5 May 2014

Spinner with "re-select" functionality

This is an advanced tutorial: I'll cover custom views, the Android source code and Java reflection.

A simple Spinner

As you probably already know, when the user selects an item from a Spinner the event onItemSelected is triggered.
To define the selection event handler for a Spinner, you have to implement the AdapterView.OnItemSelectedListener interface and the corresponding onItemSelected() callback method:
public class SpinnerActivity extends Activity implements OnItemSelectedListener {
 //...
 
    public void onItemSelected(AdapterView<?> parent, View view,
            int pos, long id) {
        // An item was selected. You can retrieve the selected item using
        // parent.getItemAtPosition(pos)
    }

    public void onNothingSelected(AdapterView<?> parent) {
        // Another interface callback
    }
}

However, if the Spinner is set to a specific item and the user re-selects the same item, no callback method is invoked. The reason is that the default implementation of the Spinner class uses an internal variable to keep track of the currently selected item: if the user re-selects the same item, no callback method is triggered.
To be more precise, to understand exactly what happens we have to look at the source code of the Spinner class, using AndroidXRef:

By examining the source code you can discover that when the user selects an item the method setSelection is invoked (check the methods onClick and show) . The method setSelection is defined in the superclass AbsSpinner (Spinner infact extends AbsSpinner).


As you can see the method setSelection calls setSelectionInt, which checks if the currently selected item is equal to the item already selected: in this case no event is triggered.
From the source code of setSelectionInt we discover that the class uses the variable mOldSelectedPosition to keep track of the already selected item of the Spinner. However, the AbsSpinner class contains no definition of this variable, so we have to check the superclasses.
After a brief search you can discover that mOldSelectedPosition is defined in the class AdapterView (superclass of AbsSpinner):


Now we have all the elements to create our custom Spinner with "re-select" functionality:
import java.lang.reflect.Field;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.Spinner;


public class SpinnerReselect extends Spinner {
 
 public SpinnerReselect(Context context) {
     super(context);
     // TODO Auto-generated constructor stub
 }
 
 public SpinnerReselect(Context context, AttributeSet attrs) {
     super(context, attrs);
     // TODO Auto-generated constructor stub
 }
 
 public SpinnerReselect(Context context, AttributeSet attrs, int defStyle) {
     super(context, attrs, defStyle);
     // TODO Auto-generated constructor stub
 }

  @Override
 public void setSelection(int position, boolean animate) {
     ignoreOldSelectionByReflection();
     super.setSelection(position, animate);
 }

  private void ignoreOldSelectionByReflection() {
     try {
         Class<?> c = this.getClass().getSuperclass().getSuperclass().getSuperclass();
         Field reqField = c.getDeclaredField("mOldSelectedPosition");
         reqField.setAccessible(true);
         reqField.setInt(this, -1);
     } catch (Exception e) {
         Log.d("Exception Private", "ex", e);
         // TODO: handle exception
     }
 }

  @Override
 public void setSelection(int position) {
     ignoreOldSelectionByReflection();
     super.setSelection(position);
 }
}



By implementing our custom Spinner we have to override the default implementation of the setSelection methods. To do so, we simply call the method ignoreOldSelectionByReflection before calling the default methods (defined in the class AbsSpinner: that's why we use super.setSelection...).

In the method ignoreOldSelectionByReflection we make use of Java reflectionReflection is commonly used by programs which require the ability to examine or modify the runtime behavior of applications running in the Java virtual machine. This is a relatively advanced feature and should be used only by developers who have a strong grasp of the fundamentals of the language. With that caveat in mind, reflection is a powerful technique and can enable applications to perform operations which would otherwise be impossible.

Let's examine the code:

Class<?> c = this.getClass().getSuperclass().getSuperclass().getSuperclass();

As we already saw the variable mOldSelectedPosition is defined the class AdapterView (superclass of AbsSpinner). So we have to get a reference to this class by calling getClass and getSuperclass respectively.


Field reqField = c.getDeclaredField("mOldSelectedPosition");
reqField.setAccessible(true);

The secondo step is to get access to the field mOldSelectedPosition. By calling reqField.setAccessible(true) we make sure that the reflected object should suppress Java language access checking when it is used.

reqField.setInt(this, -1);

The trick is quite clear: we set the value of mOldSelectedPosition to -1 to make sure that the currently selected item of the Spinner is always different from the previously selected item, even if the user re-selectes the same item.
This way the method setSelection is always triggered!


Sunday 27 April 2014

ListPreference: how to load data dinamically

In this tutorial I'll explain how to populate a ListPreference programmatically. It is easier than you might expect; however I haven't found any official tutorial about it. If you need more information about Settings in Android you can read the official documentation.


Generally speaking, if you want to add a ListPreference to your app's settings, you have to add a ListPreference object in the preference XML file, like in the following example:
<ListPreference
        android:dependency="pref_sync"
        android:key="pref_syncConnectionType"
        android:title="@string/pref_syncConnectionType"
        android:dialogTitle="@string/pref_syncConnectionType"
        android:entries="@array/pref_syncConnectionTypes_entries"
        android:entryValues="@array/pref_syncConnectionTypes_values"
        android:defaultValue="@string/pref_syncConnectionTypes_default" />

As you can see you provide the entries of the ListPreference, and the corresponding values, with the items android:entries and android:entryValues, that refer to an array loaded in the res/values folder.
But if you want to load the data programmatically (for example, if you want to fetch the data from a local database or from an online service), you must create a custom ListPreference class.

To begin with, let's see the new preference XML file with a reference to our custom ListPreference:
<com.androidthetechnicalblog.preference.MyCustomPreference
            android:key="pref_mycustompreference"
            android:title="@string/pref_mycustompreference"
            android:summary="@string/pref_mycustompreference_summary"/>

We are creating a custom ListPreference class, so we must provide the full path of the class. As you can also see, we omitted android:entries and android:entryValues, because we want to load the data programmatically.

Now let's see how MyCustomPreference class looks like (not relevant code omitted for brevity):
public class MyCustomPreference extends ListPreference {  
    // ...  

    public MyCustomPreference (Context context, AttributeSet attrs) {      
        super(context, attrs);      
    
        setEntries(entries());         
        setEntryValues(entryValues());         
        setValueIndex(initializeIndex());       
    }  

    public MyCustomPreference (Context context) {      
        this(context, null);  
    }  

    private CharSequence[] entries() {      
        //action to provide entry data in char sequence array for list          
        String myEntries[] = {"one", "two", "three", "four", "five"};         

        return myEntries;  
    }  

    private CharSequence[] entryValues() {      
        //action to provide value data for list           
     
        String myEntryValues[] = {"ten", "twenty", "thirty", "forty", "fifty"};
        return myEntryValues;
   }

   private int initializeIndex() {
        //here you can provide the value to set (typically retrieved from the SharedPreferences)
        //...

        int i = 2;
        return i;
    }
}

The code is quite simple. You just have to provide the entries and entryValues through the methods setEntries and setEntryValues, that accept a CharSequence (or String) array as a parameter. You can also set the default initial value, typically retrieved from the SharedPreferences, through the method setValueIndex

For everything that is not explicitly covered in this tutorial you can refer to the official documentation aboud Android settings.

Wednesday 23 April 2014

Animating a ProgressBar to a specific value

In this tutorial I'll explain how to set a specific progress value to a ProgressBar using a smooth animation.



ObjectAnimator animation = ObjectAnimator.ofInt(pbBudget, "progress", 0, 50);
To begin with we create an ObjectAnimator object: this is a subclass of ValueAnimator that provides support for animating properties on target objects. The constructors of this class take parameters to define the target object that will be animated as well as the name of the property that will be animated. In this example we used the following parameters:
  • pbBudget: reference to the ProgressBar in the layout;
  • "progress": the name of the property to be animated;
  • 0: starting point of the animation;
  • 50: ending point of the animation.

animation.setDuration(1500);
The code is self-explanatory: the animation lasts 1,5 seconds.


animation.setInterpolator(new DecelerateInterpolator());
It is possible to use different interpolators for our animation, like for example:

animation.start();

You can also create an animation for the ProgressBar from scratch, using the method setProgress(int progress) with a delay (android.os.SystemClock.sleep(long ms)).
If you decide to do so, I suggest to use an AsyncTask and update the ProgressBar using the onProgressUpdate method.
Avoid animating the ProgressBar in the UI thread with a loop:
  1. because this will freeze the UI until the animation is completed;
  2. because even though you are in the UI thread, you don't release the UI thread until the animation is completed, thus preventing the system to update the UI (and the ProgressBar) itself.

Wednesday 16 April 2014

Hidden Android APIs: hiding SMS messages to the default SMS receiver

In a previous tutorial we saw how to take advantage of the hidden Android APIs to listen to incoming SMS messages.
Now suppose that we want to listen to specific SMS messages (messages coming from a particular number or containing specific strings) and to hide them to the default SMS receiver (like Google Hangout or other client).

This is a private message!

As in the previous tutorial we have to declare a BroadcastReceiver in the AndroidManifest.xml file. However, in order to take priority over the default SMS receiver, we also have to set a high priority for our SMS BroadcastReceiver:
<receiver android:name="com.androidthetechinalblog.SMSReceiver">
   <intent-filter android:priority="9999">
      <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
   </intent-filter>
</receiver>

Now we just have to make some minor changes to the SMSReceiver class:
public class SMSReceiver extends BroadcastReceiver {
 
 public void onReceive(Context context, Intent intent) {
  String action = intent.getAction();
 
  if(action.equals(“android.provider.Telephony.SMS_RECEIVED”)) {
   Object incomingSMSs[] = (Object[]) intent.getSerializableExtra(“pdus”);
    
   for(Object tmp : incomingSMSs) {
    byte message[] = (byte[]) tmp;
    SmsMessage smsMessage = SmsMessage.createFromPdu(message);

    String phoneNumber = smsMessage.getOriginatingAddress();
    String messageBody = smsMessage.getMessageBody();

    if(phoneNumber.equals("3457148596") || messageBody.contains("test")) {
       //we have found our SMS! here you can perform some actions
       abortBroadcast();
       setResultData(null);
    }
   }
  }
 }
}

As you can see, by calling abortBroadcast() and setResultData(null) (methods working only for "ordered broadcasts", like in our example) we make sure that our SMS won't be propagated to any other receiver.

Wednesday 2 April 2014

Quick trick of the week: EditText inside a ListView



Let's suppose you want to create a layout with a ListView containing an EditText in each item, like in the following picture:


If yout set up your layout like the one showed above you'll soon have to deal with an annoying problem: for some unknown reason the EditText immediately loses focus, and it's almost impossible to write anything.
For some devices a good workaround would be to double tap on the EditText, but this is not an accetable solution for the end users of our apps.

Fortunately the solution is quite easy: you just have to add the following lines of code:
  1. in the AndroidManifest.xml file add the following line for the Activity containing the ListView: android:windowSoftInputMode="adjustPan";
  2. in the layout file of the Activity add the following line to your ListView: android:descendantFocusability="beforeDescendants".


Now the EditText(s) should behave as expected...

 <activity android:name="com.androidthetechnicalblog.MyActivity"
   android:configChanges="keyboardHidden|orientation|screenSize"     
   android:windowSoftInputMode="stateHidden|adjustPan"
   android:label="@string/app_name"></activity>         

<ListView
   android:id="@android:id/list"             
   android:descendantFocusability="beforeDescendants"       
   android:layout_width="match_parent"
   android:layout_height="wrap_content"            
   android:layout_marginTop="10dp" />

Monday 31 March 2014

Hidden Android APIs: Settings

In the previous tutorial we talked about the hidden Android APIs, how to discover them and how to use them in our apps. To be more precise, we saw that the easiest way to use the hidden APIs is to copy hidden constants from the Android source code into our Activities (this way we can, for example, set up a BroadcastReceiver to intercept incoming SMS messages).



The same method can be used to start Activities to change specific system settings directly from our app. As far as system settings are concerned, there are some settings that are available in the official and public APIs. An example is the constant Settings.ACTION_AIRPLANE_MODE_SETTINGS, through which we can show settings to allow entering/exiting airplane mode. But there are a lot of other settings which are available only in the hidden APIs. To find them, look for the Settings class with AndroidXRef, as follows:


To find the hidden settings you just have to look for the "@hide" tag. You will find all the constants you can use to create Intents to launch specific parts of the settings UI.
For example, if you want to launch an Activity to check system updates, you can use the hidden constant Settings.ACTION_SYSTEM_UPDATE_SETTINGS:



As you can see from the Android source code, this constant is marked with the "@hide" tag, so it is not visible in the official API.
You can use this constant in the following way:

Intent pref = new Intent("android.settings.SYSTEM_UPDATE_SETTINGS"); startActivity(pref);

When you want to use hidden constants to change system settings you must be aware of two things:

  1. in some cases a matching Activity for a given constant may not exist, so ensure you safeguard against this;
  2. for some settings you have to add special permissions to the AndroidManifest.xml file (you can refer to the error messages in the Logcat to discover the permissions needed).

Wednesday 26 March 2014

Hidden Android APIs: listening to incoming SMS messages

In the Android platform there are two classes, SmsManager and SmsMessage, for sending SMS messages; hower there is no official class for receiving them. To be able to receive SMS messages we have to use a hidden API, present in the Android platform but not generally available for developers.
Hidden Android APIs contain several constants, methods, interfaces, etc. that can come in handy in a variety of situations.



To discover hidden Android APIs you can use the following resource:
  • AndroidXRef (http://androidxref.com): this site has indexed all the Android source code and offers a useful search box; however you have to know exactly what you are looking for.

Searching class Telephony from AndroidXRef


In order to make use of the Android hidden APIs, there are two possible scenarios:
  • constants: if you just need to use a hidden constant (for example for broacast actions), you can simply copy them from the Android source code into your app. In this tutorial we will use this technique;
  • methods, classes, interfaces, etc.: hidden methods, classes and interfaces must be compiled, before beeing able to use them. To do this you can either modify the SDK jar file used to compile your app, or make use of the java reflection method, each of which has its pros and cons.

To be able to receive incoming SMS messages we will use the following hidden constants contained in the class telephony-common (you can find them using the utilities listed above):
  • android.provider.Telephony.SMS_RECEIVED”: Intent action used in our BroadcastReceiver to listen to incoming SMS messages;
  • pdus”: constant used to retrieve SMS data from the Intent.

Extract from the class Telephony of the Android source code


Extract from the class Telephony of the Android source code


So here is the code:
  1. declare the use of the RECEIVE_SMS permission in the AndroidManifest.xml file;
  2. declare a BroadcastReceiver in the AndroidManifest.xml file with the intent-filter “android.provider.Telephony.SMS_RECEIVED”;
  3. implement the BroadcastReceiver as follows:


public class SMSReceiver extends BroadcastReceiver {

 public void onReceive(Context context, Intent intent) {
  String action = intent.getAction();

  if(action.equals(“android.provider.Telephony.SMS_RECEIVED”)) {
   Object incomingSMSs[] = (Object[]) intent.getSerializableExtra(“pdus”);
   
   for(Object tmp : incomingSMSs) {
    byte message[] = (byte[]) tmp;
    SmsMessage smsMessage = SmsMessage.createFromPdu(message);
   }
  }
 }
}

Once you have a SmsMessage object, you can use one ot its several methods to retrieve useful info about the SMS received:
smsMessage.getOriginatingAddress();
smsMessage.getMessageBody();
etc.

Wednesday 12 March 2014

Binding Services – part 3 (communication Service -> Activity)

In our previous tutorial about IntentService we saw that a BroadcastReceiver can be used as a means of communication between the Service and the calling client. Hower this method cannot be used for frequent and fast calls, such as for progress updates. For this purpose we have to use a different approach...
For more information about binding Services and the way they are connected to a calling Activity, please refer to my previous tutorials.


SERVICE

First of all we have to define a public interface inside our Service as a means of communication between the Service and the calling Activity:

public interface InterfaceCallback {
   void onProgressUpdate(int progress);
   void onTaskCompleted(MyResult myResult);
}

where MyResult is a user defined class carrying the results of the operation performed by the Service in the background.
The next step is to connect our Service to the calling Activity. To do this, we define an instance variable of the type InterfaceCallback and create a public method that will be called by the calling Activity to connect itself to the Service (the following code goes inside the Service class):

private InterfaceCallback interfaceCallback;
...
public void setInterfaceCallback(InterfaceCallback interfaceCallback) {
   this.interfaceCallback = interfaceCallback;
}

Now our Service is ready to communicate with the calling Activity using the interfaceCallback reference. For example, if we want to notify the updates of a background task (from the onProgressUpdate method of an AsyncTask, for instance) we can call:

interfaceCallback.onProgressUpdate(progress);

In the same way, if we need to communicate that the background operation has been completed and send and object containing the results, we can simply call:

interfaceCallback.onTaskCompleted(myResult);




CALLING ACTIVITY

To make sure that our Activity can receive updates from the Service we have to implement the previously defined interface:

public class CallingActivity extends Activity implements ServiceConnection, MyService.InterfaceCallback {
//see previous tutorial
}

Once we have established a valid connection with the Service, we can register our Activity as a callback (our Activity overrides the InterfaceCallback methods that are triggered by the Service):

@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
  MyService myService = ((MyService.MyBinder) iBinder).getReference();
   myService.setInterfaceCallback(this);
myService.startBackgroundTask();
}

@Override
protected void onPause() {
   super.onPause();
   ...
   if(myService != null) {
      myService.setInterfaceCallback(null);
      unbindService(this);
   }
}

Finally we have to override the methods onProgressUpdate and onTaskCompleted of the implemented InterfaceCallback interface. These methods, as we already saw, are called from the Service to notify the connected Activity about the progress updates and the completion of the background task:

@Override
public void onProgressUpdate(int progress) {
   //code left out for brevity
}

@Override
public void onTaskCompleted(MyResult myResult) {
   //code left out for brevity
}


to be continued...

Wednesday 5 March 2014

Binding Services - part 2 (staying in the foreground)

In our previous tutorial we saw how to create a binding Service and how to bind to it using the Binder pattern. This is a very useful pattern because, once we retrieve a valid reference to our Service, we can use this reference to call Service's methods like any other Java object.



Binding Services usually stay alive until the last client disconnects, calling the unbindService method. When no more clients are connected, the Service is no longer running in the foreground and may be targeted by the system for shutdown (usually when Android is running out of resources).
In order to prevent the system from doing this, we can use the startForeground method. This method makes sure that the Service will stay in the foreground state (usually when executing long running tasks in the background) even if no client is connected.
The only thing to remember is to always call stopForeground, with the parameter true, when the Service has completed its task, otherwise we could potentially waste system resources.



Let's suppose to define a method in our Service class called executeTask, which is meant to perform long running operations. This method is called from our Activity, once a valid reference to our Service is obtained (see previous tutorial for more details), with the following code:

myService.executeTask();

Now we want that our Service will stay in the foreground until the task is completed. We also create a notification reporting that a background operation is running:

public void executeTask() {
   //create the Notification
   Notification.Builder builder = new Notification.Builder(this);
   builder.setContentTitle("Notification title");
   builder.setContentText("Notification text");
   builder.setSmallIcon(R.drawable.icon_for_notification);
   Notification mNotification = builder.build();

   //the Service won't be stopped by the system
   startForeground(1001, mNotification);

  //background operations: left out for brevity
  ...

  //remove the Service from foreground state
  stopForeground(true);
}

Monday 24 February 2014

Binding Services – part 1

In this tutorial I’ll explain the basics of binding Services. For more information about what Services are and what they are used for please refer to my previous tutorial, IntentServices in Android, that you can find here.


Services in Android can be activated in two ways:
  • you can start a Service through the Context.startService() method;
  • or you can bind to a Service through the Context.bindService() method.

The main difference is that if you bind to a Service, the Service will stay alive until the last client disconnects. In addition to that, if you bind to a Service, instead of starting it, you have a reference to the Service class that can be used to easily call the Service’s methods.
In this first tutorial about binding Services we’ll see how you have to set up your Service class to allow other components to be able to bind to it. To do this you have to implement the onBind method of the Service class, which must return an IBinder object.
In the following example we create an inner class, called MyBinder (extending the Binder class – please note that the Binder class implements the IBinder interface), and we return an object of this class in the onBind method (we can do so because, as already said, the Binder class implements the IBinder interface).

In our MyBinder class we create a method returning a reference to our Service class, which is used in the clients binding to the Service:

public class MyService extends Service {
   //the content of the Service is omitted for brevity
   public void startBackgroundTask() {
      ...
   }
   ...

   //MyBinder class extending Binder
   public class MyBinder extends Binder {
      public MyService getReference() {
         return MyService.this;
      }
   }

   //create an instance of our MyBinder class
   private MyBinder myBinder = new MyBinder();

   //onBind method, returning an instance of our MyBinder
   @Override
   public IBinder onBind(Intent intent) {
return myBinder;
}
}

Now that we have implemented the onBind method in our Service, we can easily bind to the Service through the Context.bindService method.
To begin with, our Activity (or other component binding to the Service) must implement the ServiceConnection interface. The ServiceConnection interface provides a callback method, onServiceConnected, called when a valid connection to the Service is established.

public class MyActivity extends Activity implements ServiceConnection {
...
}

To bind to MyService we can use the following code, typically in the onResume method (this refers to the component, our Activity in this example, that implements the ServiceConnection interface):

Intent intent = new Intent(this, MyService.class);
bindService(intent, this, BIND_AUTO_CREATE);

To unbind from MyService the code is the following (typically in the onPause method):

unbindService(this);

Finally we have to override the onServiceConnected and onServiceDisconneted methods of the ServiceConnection interface. These methods are called, respectively, when MyService is connected/disconnected to/from our Activity.

@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
   MyService myService = ((MyService.MyBinder) iBinder).getReference();
   myService.startBackgroundTask();
}

@Override
public void onServiceDisconnected(ComponentName componentName) {
   ...
}

As you can see in the onServiceConnected method we have an IBinder parameter, of the type MyService.MyBinder, because in the onBind method of our Service we return an object of this type (MyService.MyBinder extends Binder and implements the IBinder interface).
Using the iBinder reference, casting it to MyService.Binder and calling the method getReference we obtain a reference to our MyService class. You can then use this reference to call specific methods of MyService, omitted here for brevity, to perform background operations (you have of course to use different threads to perform background tasks, because all methods of the Service class run in the UI thread).

To be continued...

Saturday 15 February 2014

Using ViewPager to swipe between Fragments in an ActionBar

In this tutorial I'll  briefly explain how to use the ViewPager widget to swipe between different Fragments in an ActionBar.
In our example we not only want to swipe between Fragments using a ViewPager widget: we also need to set up an ActionBar, where each Tab contains a different Fragment, and be able to swipe between them with a smooth animated transition.

In the following example the ViewPager manages the loading of the Fragments, but the widget has to be synchronized with the ActionBar, in other words:

  1. when you swipe to a different Fragment, the ActionBar must select the correct Tab;
  2. when you select a Tab in the ActionBar the ViewPager must select the correct Fragment.


1) XML FILE OF THE MAIN ACTIVITY


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    
    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />


</LinearLayout>

As you can see you have to place the ViewPager widget (here named "pager"), which is provided by the android.support.v4 library, in your layout. We set layout_width and layout_height attributes both to "match_parent" in order to make sure that the ViewPager covers the entire display.

2) MAIN ACTIVITY AND FRAGMENTS: IMPORTS

To be able to use the ViewPager widget you have to use the classes provided by the support library, not the standard library:

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentPagerAdapter;

import android.support.v4.view.ViewPager;

In addition to that your main Activity must extend FragmentActivity, not the standard Activity class:

public class MainActivity extends FragmentActivity {
...
}

Make sure to import the Fragment class provided by the support library also in the classes of each Fragment displayed by the ActionBar through our ViewPager:

import android.support.v4.app.Fragment;

...

public class FragmentOne extends Fragment {
...
//the code of the Fragments is omitted for brevity
...
}


3) ONCREATE METHOD OF THE MAIN ACTIVITY

In the onCreate method of the main Activity we have to create the Fragments used to display our data, the ActionBar and setup the ViewPager widget to be able to swipe between different Fragments.
Here is the code:

@Override
protected void onCreate(Bundle savedInstanceState){
   super.onCreate(savedInstanceState);

setContentView(R.layout.main_activity);

    //first we create the Fragments
    firstFragment = new FirstFragment();
secondFragment = new SecondoFragment();
thirdFragment = new ThirdFragment();
fourthFragment = new FourthFragment();

//now we put the Fragments in an array to use them with the ViewPager
arrFragment = new Fragment[4];
arrFragment[0] = firstFragment;
arrFragment[1] = secondFragment;
arrFragment[2] = thirdFragment;
arrFragment[3] = fourthFragment;

    //now we create an adapter between our Fragments and the ViewPager
    //for this purpose we use and instance of our class MyAdapter, which is 
    //explained later
myFragmentPagerAdapter = new MyAdapter(getSupportFragmentManager());
myViewPager = (ViewPager) findViewById(R.id.pager);
    //we load 3 pages in memory on both sides of the current page
    //pages beyond this limit are recreated from the adapter when needed
myViewPager.setOffscreenPageLimit(3); 

myViewPager.setAdapter(myFragmentPagerAdapter);

//here we set up our ActionBar
setupTabs();

myViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
      @Override
public void onPageSelected(int position) {
getActionBar().setSelectedNavigationItem(position);
}
});
}

With the method setOnPageChangeListener we set a listener that will be invoked whenever the page changes or is incrementally scrolled. 
In this case we retrieve a reference of our ActionBar and select the Tab at the position specified by the ViewPager. In this example we have 4 tabs (see next paragraph), so let's select the Tab at the specified position.


4) SETTING UP THE ACTION BAR.

In our example we not only want to swipe between Fragments using a ViewPager widget: we also need to set up an ActionBar, where each Tab contains a different Fragment.
The method setupTabs(), called from onCreate, creates the ActionBar, the 4 Tabs and sets up a connection between the ActionBar and the ViewPager widget.
Basically we register a listener, called every time a Tab is selected (pressed), which forces the ViewPager to change page (load a different Fragment) with a smooth transition:

private void setupTabs() {
final ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
ActionBar.TabListener tabListener = new ActionBar.TabListener() {

@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub

}

@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
myViewPager.setCurrentItem(tab.getPosition());
}

@Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub

}
  };

     actionBar.addTab(actionBar.newTab().setText(R.string.tab_one).setTabListener(tabListener));
actionBar.addTab(actionBar.newTab().setText(R.string.tab_two).setTabListener(tabListener));
actionBar.addTab(actionBar.newTab().setText(R.string.tab_three).setTabListener(tabListener));
actionBar.addTab(actionBar.newTab().setText(R.string.tab_four).setTabListener(tabListener));

}

5) ADAPTER

To make all things work we need an Adapter class (inner class of the main Activity class) to link our Fragments with the ViewPager widget:

public class MyAdapter extends FragmentPagerAdapter {
private final int PAGE_COUNT = 4;

public MyAdapter(FragmentManager fm) {
super(fm);
}

@Override
public Fragment getItem(int i) {
return arrFragment[i];
}

@Override
public int getCount() {
return PAGE_COUNT;
}

@Override
public CharSequence getPageTitle(int position) {
switch(position) {
case TAB_ONE:
return getResources().getString(R.string.tab_one);
case TAB_TWO:
return getResources().getString(R.string.tab_two);
case TAB_THREE:
return getResources().getString(R.string.tab_three);
case TAB_FOUR:
return getResources().getString(R.string.tab_four);
 
   default:
return null;
}
}
}

where of course:

//constants
private static final int TAB_ONE = 0;
private static final int TAB_TWO = 1;
private static final int TAB_THREE = 2;
private static final int TAB_FOUR = 3;


As you can see from the previous example we have:

  1. a ViewPager widget which loads our Fragments through the class MyAdapter defined above;
  2. an ActionBar which forces the ViewPager to load the correct Fragment each time a Tab is selected (pressed);
  3. a listener linked to our ViewPager which selects the correct Tab whenever the user swipes to a different Fragment.