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.

Sunday 9 February 2014

"Listening" to preference changes

As you already know in an Android app settings, options and user preferences are generally stored using SharedPreferences objects.
The name of the preference file created by PreferenceManager.getDefaultSharedPreferences() is formed by the package name of your app (com.....) plus the suffix _preferences.


What you might not know (at least I didn't know it until I discovered this week while developing my next app) is that Android uses a single instance of the preference file within the same app. This means that if you open the same preference file twice (for example in 2 different Activities) at the same time, every change that you commit using one object (better apply, because the apply() method works asynchronously) will immediately be reflected in the other object.
So, if you change a preference within an Activity you need a method to notify the other components of your app (Activities, Services, etc.), using the same preference file, tha the change has occured.

To do this you have to implement the SharedPreferences.OnSharedPreferenceChangeListener interface within your Activity, Service, etc.
Basically you have to follow the following steps:

1) implement the SharedPreferences.OnSharedPreferenceChangeListener interface, for example:

public class MyExample extends Activity implements SharedPreferences.OnSharedPreferenceChangeListener {
...
}

2) register and unregister the listener in the appropriate methods, like onResume and onPause:

SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
pref.registerOnSharedPreferenceChangeListener(this);
String currency = pref.getString("currency", "USD");

and (unregister):

SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
pref.unregisterOnSharedPreferenceChangeListener(this);

3) override the method onSharedPreferenceChanged in order to listen to preference changes:

@Override
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
   if(key.equals("currency") {
      currency = pref.getString("currency", "USD");
   }
}

Now you know that another component of your app has just changed the value of the currency preference. You may want to perform some actions in response.

Wednesday 5 February 2014

Exporting SQLite database into pdf with PDFJET

In this tutorial I will explain how to convert an SQLite database into pdf using a third party library, PDFJET. You can download the library, as well as the documentation, from this site. Make sure to download the open source library, which is free but relatively complete (there is also a more complete version, which you can use only for evaluation purposes, but you have to pay for it for developing your apps).



Why using PDFJET library

There are 3 main reasons for using PDFJET library in my opinion:
  1. there is an open source version of the library (FREE);
  2. it’s relatively complete (it has all the main features you need to create a pdf file);
  3. it’s light (about 350 kb).
Of course if you need more advanced features you should better use the pay version of the library, or other librarries that you prefer.

Setting up your project (Eclipse) to use the library

To use PDFJET library in your project (Eclipse) follow these steps:
  1. download the library from this page (open source version);
  2. extract the files to a different folder;
  3. in Eclipse create the package com.pdfjet in the src folder;
  4. copy alla java files that you find in the folder open source\PDFjet-Open-Source\com\pdfjet in the package com.pdfjet that you have created;
  5. import the package in your class with import com.pdfjet.
Now you can use the PDFJET library in your class.

Using the library

If you visit the PDFJET official site you’ll find dozens of examples about how to use the library and a complete documentation of all the classes available (the documentation can also be found in the library you download from the website: look at the folder open source\PDFjet-Open-Source\docs\java\com\pdfjet).
In this tutorial I will only give you a few examples of the instructions you can use to quickly convert an SQLite database into a pdf file.

Creating the pdf file

Let’s suppose we want to create a pdf file, Budget.pdf, in the external storage directory of our device. Here is the code:

String state = Environment.getExternalStorageState();
//check if the external directory is availabe for writing
if (!Environment.MEDIA_MOUNTED.equals(state)) {
return;
}
else {
File exportDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
}

//if the external storage directory does not exists, we create it
if (!exportDir.exists()) {
exportDir.mkdirs();
}
File file;
file = new File(exportDir, "Budget.pdf");

//PDF is a class of the PDFJET library
PDF pdf = new PDF(new FileOutputStream(file));

//instructions to create the pdf file content

pdf.flush();

Title

Now suppose that we want to create a title and center it on the page (horizontally):

//first we create a page with portrait orientation
Page page = new Page(pdf, Letter.PORTRAIT);

//font of the title
Font f1 = new Font(pdf, CoreFont.HELVETICA_BOLD);
f1.setSize(7.0f);

//title: font f1 and color blue
TextLine title = new TextLine(f1, “TABLE’S TITLE”);
title.setFont(f1);
title.setColor(Color.blue);

//center the title horizontally on the page
title.setPosition(page.getWidth()/2 – title.getWidth()/2, 40f);

//draw the title on the page
title.drawOn(page);

Links

Here is the code to create a link to our website:

//font of the link
Font f2 = new Font(pdf, CoreFont.HELVETICA);
f2.setSize(7.0f);

//text of the link
TextLine website = new TextLine(f2, "Visit Website");
website.setColor(Color.blue);
website.setUnderline(true);
website.setURIAction("https://sites.google.com/site/flingsoftware/");

//position of the link
website.setPosition(40f, 40f);

//draw the link on the page
website.drawOn(page);

Creating a table

To convert an SQLite database into pdf we need of course a table. Here is the code to create it:

Table table = new Table();
List<List<Cell>> tableData = new ArrayList<List<Cell>>();

As you can see to create a table we use an ArrayList where each element is represented by another ArrayList containing Cell objects. Cell is a class of the PDFJET library used to create a single cell in the table.

Adding columns’ titles

List<Cell> columnTitles = new ArrayList<Cell>();
columnTitles.add(new Cell(f1, “COLUMN 1”);
columnTitles.add(new Cell(f1, “COLUMN 2”);
columnTitles.add(new Cell(f1, “COLUMN 3”);
columnTitles.add(new Cell(f1, “COLUMN 4”);
columnTitles.add(new Cell(f1, “COLUMN 5”);
columnTitles.add(new Cell(f1, “COLUMN 6”);

//light gray background and center alignment
for(int i=0; i<6; i++) {
   ((Cell) columnTitles.get(i)).setBgColor(Color.lightyellow);
   ((Cell) columnTitles.get(i)).setTextAlignment(Align.CENTER);
}
tableData.add(columnTitles);

In this example we created an ArrayList of Cells, each of which representing the title of a column, we set the color background and alignment of each Cell, and finally added the ArrayList to the “ArrayList of ArrayLists” tableData, our complete table.

Adding database records to the table

DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault());
NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.getDefault());

int i = 1;
while(myCursor.moveToNext()) {
   //retrieve data from cursor  
   Long date = myCursor.getLong(myCursor.getColumnIndex("date"));
   String item = myCursor.getString(myCursor.getColumnIndex("item"));
   Double amount = myCursor.getDouble(myCursor.getColumnIndex("amount"));
   String currency = myCursor.getString(myCursor.getColumnIndex("currency"));
   Double convAmount = myCursor.getDouble(myCursor.getColumnIndex("converted_amount"));
   String description = myCursor.getString(myCursor.getColumnIndex("description"));

   //next record in the table
   List<Cell> record = new ArrayList<Cell>();

   //create Cells and add them to the record
   Cell dateCell = new Cell(f2, df.format(new Date(date)));
   dateCell.setTextAlignment(Align.CENTER);
   record.add(dataCell);

   record.add(new Cell(f2, item));

   Cell amountCell = new Cell(f2, nf.format(amount));
   amountCell.setTextAlignment(Align.RIGHT);
   record.add(amountCell);

   Cell currencyCell = new Cell(f2, currency);
   currencyCell.setTextAlignment(Align.CENTER);
   record.add(currencyCell);

   Cell convAmountCell = new Cell(f2, nf.format(convAmount));
   convAmountCell.setTextAlignment(Align.RIGHT);
   record.add(convAmountCell);
   record.add(new Cell(f2, description));
   
   //add the record to the table
   tableData.add(record);

   //one line gray and one line white...
   if(i%2 == 0) {
dateCell.setBgColor(Color.lightgray);
amountCell.setBgColor(Color.lightgray);
        ...
   }
   i++;
}

In the previous example we iterate over the Cursor retrieved from the database and write each record in the table, field (each represented by a Cell object of the PDFJET library) after field.

Printing the table on the page

//populate the table with our tableData ArrayList
table.setData(tableData, Table.DATA_HAS_1_HEADER_ROWS);
//autoadjust column widths to fit the content
table.autoAdjustColumnWidths();
//let’s suppose we want to manually set the width of column 0
table.setColumnWidth(0, 40.0f);
//each cell can contain more rows
table.wrapAroundCellText();

table.setPosition(page.getWidth()/2 – table.getWidth()/2, 40f);
table.drawOn(page);

Printing the table on more than one page

If your table is particularly long and you need more than one page to print it, you can use the following loop:

int numOfPages = table.getNumberOfPages(page);
int currentPage = 0;
while (true) {
point = table.drawOn(page);

   //print page number
   TextLine numPag = new TextLine(f2, ++currentPage + “ of “ + numOfPages);
   numPag.setPosition(largPag - 30.0f - numPag.getWidth(), page.getHeight() - 20.0f);
   numPag.drawOn(page);

   //scrivo il nome tabella a fondo pagina
   TextLine tabella = new TextLine(f2,    mioContext.getString(R.string.menu_esporta_tabellaPdf_fondoPaginaSpese));
   tabella.setPosition(30.0f, page.getHeight() - 20.0f);
   tabella.drawOn(page);
   if (!table.hasMoreData()) {
      // Allow the table to be drawn again later:
      table.resetRenderedPagesCount();
      break;
   }
   page = new Page(pdf, Letter.PORTRAIT);
}

Sunday 2 February 2014

Autostart an app at bootup

Generally speaking it's not possible in Android to make your app to start automatically at bootup. But you can use a trick to achieve the same result.


Basically you have to register a BroadcastReceiver in your AndroidManifest.xml file to listen to the Intent.ACTION_BOOT_COMPLETED event. In your BroadcastReceiver class you can now start your app or Service.
This method is often used to start a Service to perform certain operations in the background (for example, to register an alarm clock).

Let's look at the code of the AndroidManifest.xml file:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
...
<receiver android:enabled="true" android:name=".BootUpReceiver"
        android:permission="android.permission.RECEIVE_BOOT_COMPLETED">

        <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
</receiver>

Now, let's suppose that you want to start a Service at bootup. The code of our BroadcastReceiver is the following:

public class BootUpReceiver extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
                Intent i = new Intent(INTENT_ACTION);  
                i.putExtra...
                [...]
                context.startService(i);  
        }

}

Of course you have to use this code only when really needed: an app starting app every time the device is booting could possibly waste system's resources.