RSS

Category Archives: Android

Android : C2DM and the TokToki -push-messaging service

C2DM (Android Cloud 2 Device Message) was announced at Google IO 2010.  The feature was introduced to relieve the applications from polling cloud resources e.g email.

Fortunately, C2DM has an API, so I thought I’d create a platform off the C2DM infrastructure. This involved developing a back-end application server (I’m running on Google App Engine) and an Android client library that Android developers can utilities to enhance their application (Android 2.2+ required) with push messaging.

TheTok-Toki service (named after the Tok-Tokkie beetle, indigenous to South Africa, known for tapping on the ground to communicate to other beetles). is hosted here.

 

 
Leave a comment

Posted by on November 23, 2011 in Android

 

Tags: , ,

Android : New Compatibly Library (r4) available

Following last weeks announcement of Android 4.0 (Ice Cream Sandwich) and the release release of the 4.0 SDK, Google/Android also release a new version of the Compatibility Library (r4).  Go check it out, it promises some bug fixes and additional support for ICS.

http://developer.android.com/sdk/compatibility-library.html

 
1 Comment

Posted by on October 24, 2011 in Android

 

Tags: , ,

Android : Tabs + ViewPager (Swipe-able Tabs, FTW)

In my previous two posts, I explained how you would implement Tabs using Fragments and then how to implement page swiping using ViewPager.  In this post, I’ll bring those two nuggets together and show you how to implement Swipe-able Tabs (i.e switch between tabs using the swipe gesture).

* Caveat Alert * At the time of this posting, there is no way of implementing MapView as a fragment, which may put a spanner in the works if you’re thinking about using this UI pattern with a MapView.

Requirements

To implement a Tabs & ViewPager, using fragments on devices running Android 2.1 or higher, you’ll need to include the Android Compatibility library.  In my example, I’m using Compatibility library v4.

Step-by-step

  1. Define the Tab ViewPager layout
  2. Define the PagerAdapter
  3. Define the Tab FragmentActivity

The Code

The Tab ViewPager layout

The Tab ViewPager layout (tabs_viewpager_layout.xml) declares a TabHost and child TabWidget views as per normal.  For this implementation, instead of having the dummy FrameLayout to hold the content, we define the ViewPager (android.support.v4.view.ViewPager)

<?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
	<TabHost
	    android:id="@android:id/tabhost"
	    android:layout_width="fill_parent"
	    android:layout_height="fill_parent"
	    >
	    <LinearLayout
	        android:orientation="vertical"
	        android:layout_width="fill_parent"
	        android:layout_height="fill_parent"
	        >
	        <TabWidget
	            android:id="@android:id/tabs"
	            android:orientation="horizontal"
	            android:layout_width="fill_parent"
	            android:layout_height="wrap_content"
	            android:layout_weight="0"
	            />

	        <FrameLayout
	            android:id="@android:id/tabcontent"
	            android:layout_width="0dp"
	            android:layout_height="0dp"
	            android:layout_weight="0"/>

	        <android.support.v4.view.ViewPager
			  	android:id="@+id/viewpager"
			  	android:layout_width="fill_parent"
			 	android:layout_height="0dp"
			 	android:layout_weight="1"
			  	/>
	    </LinearLayout>
	</TabHost>
</LinearLayout>

Define the PagerAdapter

As explained in the previous post, Page Swiping using ViewPager, the PagerAdapter is responsible for creating/returning the appropriate Fragment to the ViewPager.  The declaration of PageAdapter is unchanged from the previous post.

/**
 *
 */
package com.andy.fragments.viewpager;

import java.util.List;

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

/**
 * The <code>PagerAdapter</code> serves the fragments when paging.
 * @author mwho
 */
public class PagerAdapter extends FragmentPagerAdapter {

	private List<Fragment> fragments;
	/**
	 * @param fm
	 * @param fragments
	 */
	public PagerAdapter(FragmentManager fm, List<Fragment> fragments) {
		super(fm);
		this.fragments = fragments;
	}
	/* (non-Javadoc)
	 * @see android.support.v4.app.FragmentPagerAdapter#getItem(int)
	 */
	@Override
	public Fragment getItem(int position) {
		return this.fragments.get(position);
	}

	/* (non-Javadoc)
	 * @see android.support.v4.view.PagerAdapter#getCount()
	 */
	@Override
	public int getCount() {
		return this.fragments.size();
	}
}

Define the Tab FragmentActivity

The Tab FragmentActivity is a modified version Tab FragmentActivity I posted about in, Tabs, The Fragment Way. Thankfully, using ViewPager requires less code =)

*Disclaimer: The redundant lines of code are there to illustrate the minimal amount of changes required to implement view paging from the stock Tab implementation*

Change 1: As per the normal initialisation of Tabs, we create Tahhost.TabSpec instances for each tab.  In this implementation, we simple just add it to the TabHost (line 139) without having to detach fragments.

Change 2: Initialise the ViewPager. From line 099, we instantiate the Fragments and pass them to the ViewPager via the PagerAdapter. The order that the Fragments are supplied in the List will determine their tab order.

Change 3: Tab FragmentActivity to implement ViewPager.OnPageChangeListener interface. In order to handle page “swipe” events, our Tab FragmentActivity needs to implement the ViewPager.OnPageChangeListener interface. For our purpose we only really need to implement the onPageSelect() method (Line 168). Simply, when the page is selected (paged), it’s associated Tab is selected.

Change 4: Modify the onTabChanged() method. Similarly to Change 3, when a tab is select (and therefore becomes selected), we set the appropriate Fragment via the ViewPager mViewPager (Line 148).

package com.andy.fragments.tabs;

import java.util.HashMap;
import java.util.List;
import java.util.Vector;

import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.widget.TabHost;
import android.widget.TabHost.TabContentFactory;

import com.andy.R;
import com.andy.fragments.viewpager.PagerAdapter;

/**
 * The <code>TabsViewPagerFragmentActivity</code> class implements the Fragment activity that maintains a TabHost using a ViewPager.
 * @author mwho
 */
public class TabsViewPagerFragmentActivity extends FragmentActivity implements TabHost.OnTabChangeListener, ViewPager.OnPageChangeListener {

	private TabHost mTabHost;
	private ViewPager mViewPager;
	private HashMap<String, TabInfo> mapTabInfo = new HashMap<String, TabsViewPagerFragmentActivity.TabInfo>();
	private PagerAdapter mPagerAdapter;
	/**
	 *
	 * @author mwho
	 * Maintains extrinsic info of a tab's construct
	 */
	private class TabInfo {
		 private String tag;
         private Class<?> clss;
         private Bundle args;
         private Fragment fragment;
         TabInfo(String tag, Class<?> clazz, Bundle args) {
        	 this.tag = tag;
        	 this.clss = clazz;
        	 this.args = args;
         }

	}
	/**
	 * A simple factory that returns dummy views to the Tabhost
	 * @author mwho
	 */
	class TabFactory implements TabContentFactory {

		private final Context mContext;

	    /**
	     * @param context
	     */
	    public TabFactory(Context context) {
	        mContext = context;
	    }

	    /** (non-Javadoc)
	     * @see android.widget.TabHost.TabContentFactory#createTabContent(java.lang.String)
	     */
	    public View createTabContent(String tag) {
	        View v = new View(mContext);
	        v.setMinimumWidth(0);
	        v.setMinimumHeight(0);
	        return v;
	    }

	}
	/** (non-Javadoc)
	 * @see android.support.v4.app.FragmentActivity#onCreate(android.os.Bundle)
	 */
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		// Inflate the layout
		setContentView(R.layout.tabs_viewpager_layout);
		// Initialise the TabHost
		this.initialiseTabHost(savedInstanceState);
		if (savedInstanceState != null) {
            mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab")); //set the tab as per the saved state
        }
		// Intialise ViewPager
		this.intialiseViewPager();
	}

	/** (non-Javadoc)
     * @see android.support.v4.app.FragmentActivity#onSaveInstanceState(android.os.Bundle)
     */
    protected void onSaveInstanceState(Bundle outState) {
        outState.putString("tab", mTabHost.getCurrentTabTag()); //save the tab selected
        super.onSaveInstanceState(outState);
    }

    /**
     * Initialise ViewPager
     */
    private void intialiseViewPager() {

		List<Fragment> fragments = new Vector<Fragment>();
		fragments.add(Fragment.instantiate(this, Tab1Fragment.class.getName()));
		fragments.add(Fragment.instantiate(this, Tab2Fragment.class.getName()));
		fragments.add(Fragment.instantiate(this, Tab3Fragment.class.getName()));
		this.mPagerAdapter  = new PagerAdapter(super.getSupportFragmentManager(), fragments);
		//
		this.mViewPager = (ViewPager)super.findViewById(R.id.viewpager);
		this.mViewPager.setAdapter(this.mPagerAdapter);
		this.mViewPager.setOnPageChangeListener(this);
    }

	/**
	 * Initialise the Tab Host
	 */
	private void initialiseTabHost(Bundle args) {
		mTabHost = (TabHost)findViewById(android.R.id.tabhost);
        mTabHost.setup();
        TabInfo tabInfo = null;
        TabsViewPagerFragmentActivity.AddTab(this, this.mTabHost, this.mTabHost.newTabSpec("Tab1").setIndicator("Tab 1"), ( tabInfo = new TabInfo("Tab1", Tab1Fragment.class, args)));
        this.mapTabInfo.put(tabInfo.tag, tabInfo);
        TabsViewPagerFragmentActivity.AddTab(this, this.mTabHost, this.mTabHost.newTabSpec("Tab2").setIndicator("Tab 2"), ( tabInfo = new TabInfo("Tab2", Tab2Fragment.class, args)));
        this.mapTabInfo.put(tabInfo.tag, tabInfo);
        TabsViewPagerFragmentActivity.AddTab(this, this.mTabHost, this.mTabHost.newTabSpec("Tab3").setIndicator("Tab 3"), ( tabInfo = new TabInfo("Tab3", Tab3Fragment.class, args)));
        this.mapTabInfo.put(tabInfo.tag, tabInfo);
        // Default to first tab
        //this.onTabChanged("Tab1");
        //
        mTabHost.setOnTabChangedListener(this);
	}

	/**
	 * Add Tab content to the Tabhost
	 * @param activity
	 * @param tabHost
	 * @param tabSpec
	 * @param clss
	 * @param args
	 */
	private static void AddTab(TabsViewPagerFragmentActivity activity, TabHost tabHost, TabHost.TabSpec tabSpec, TabInfo tabInfo) {
		// Attach a Tab view factory to the spec
		tabSpec.setContent(activity.new TabFactory(activity));
        tabHost.addTab(tabSpec);
	}

	/** (non-Javadoc)
	 * @see android.widget.TabHost.OnTabChangeListener#onTabChanged(java.lang.String)
	 */
	public void onTabChanged(String tag) {
		//TabInfo newTab = this.mapTabInfo.get(tag);
		int pos = this.mTabHost.getCurrentTab();
		this.mViewPager.setCurrentItem(pos);
    }

	/* (non-Javadoc)
	 * @see android.support.v4.view.ViewPager.OnPageChangeListener#onPageScrolled(int, float, int)
	 */
	@Override
	public void onPageScrolled(int position, float positionOffset,
			int positionOffsetPixels) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see android.support.v4.view.ViewPager.OnPageChangeListener#onPageSelected(int)
	 */
	@Override
	public void onPageSelected(int position) {
		// TODO Auto-generated method stub
		this.mTabHost.setCurrentTab(position);
	}

	/* (non-Javadoc)
	 * @see android.support.v4.view.ViewPager.OnPageChangeListener#onPageScrollStateChanged(int)
	 */
	@Override
	public void onPageScrollStateChanged(int state) {
		// TODO Auto-generated method stub

	}
}

The Result

 
119 Comments

Posted by on October 13, 2011 in Android

 

Tags: , , , ,

Android : Page Swiping using ViewPager

As a follow up on my last Fragments post, I thought it would be useful to include another Honeycomb feature which is the View Pager that implements for page swiping UI pattern.

In this example, I’ve re-used the Fragment implements from the Tabs post.

Requirements

To implement a Tabbed, using fragments on devices running Android 2.1 or higher, you’ll need to include the Android Compatibility library.  In my example, I’m using Compatibility library v4

Step-by-step

  1. Define the ViewPager layout
  2. Define the FragmentActivity container for the PageViewer
  3. Define the PagerAdapter

The Code

The ViewPager layout

The ViewPager layout (viewpager_layout.xml) simply declares the ViewPager class from the v4 compatibility library.

<?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:orientation="vertical"
  >
  <android.support.v4.view.ViewPager
  	android:id="@+android:id/viewpager"
  	android:layout_width="fill_parent"
 	android:layout_height="fill_parent"
  	/>
</LinearLayout>

Defining the FragmentActivty

Our main FragmentActivity is going to host the ViewPager layout viewpager_layout.xml and initialise the ViewPager with an adapter that managers the fragments that are displayed when the user swipes between pages.  In my implementation, I simply instantiate the Fragments upfront and supply them in a list to the

constructor of the PagerAdapter PagerAdaptor.java.

As I mentioned in the intro, I reused the fragment implementations from my previous Fragment post where fragment 1 is Red, fragment 2 is Green and fragment 3 is Blue. After all, the design goal of Fragments is code/UI reuse.

/**
 *
 */
package com.andy.fragments.viewpager;

import java.util.List;
import java.util.Vector;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;

import com.andy.R;
import com.andy.fragments.tabs.Tab1Fragment;
import com.andy.fragments.tabs.Tab2Fragment;
import com.andy.fragments.tabs.Tab3Fragment;

/**
 * The <code>ViewPagerFragmentActivity</code> class is the fragment activity hosting the ViewPager
 * @author mwho
 */
public class ViewPagerFragmentActivity extends FragmentActivity{
	/** maintains the pager adapter*/
	private PagerAdapter mPagerAdapter;
	/* (non-Javadoc)
	 * @see android.support.v4.app.FragmentActivity#onCreate(android.os.Bundle)
	 */
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		super.setContentView(R.layout.viewpager_layout);
		//initialsie the pager
		this.initialisePaging();
	}

	/**
	 * Initialise the fragments to be paged
	 */
	private void initialisePaging() {

		List<Fragment> fragments = new Vector<Fragment>();
		fragments.add(Fragment.instantiate(this, Tab1Fragment.class.getName()));
		fragments.add(Fragment.instantiate(this, Tab2Fragment.class.getName()));
		fragments.add(Fragment.instantiate(this, Tab3Fragment.class.getName()));
		this.mPagerAdapter  = new PagerAdapter(super.getSupportFragmentManager(), fragments);
		//
		ViewPager pager = (ViewPager)super.findViewById(R.id.viewpager);
		pager.setAdapter(this.mPagerAdapter);
	}
}

Defining the PagerAdapter

The PagerAdapter class needs to extend FragmentPagerAdapter.  The most basic requirement for us, is to implement getItem(int position) and getCount().

/**
 *
 */
package com.andy.fragments.viewpager;

import java.util.List;

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

/**
 * The <code>PagerAdapter</code> serves the fragments when paging.
 * @author mwho
 */
public class PagerAdapter extends FragmentPagerAdapter {

	private List<Fragment> fragments;
	/**
	 * @param fm
	 * @param fragments
	 */
	public PagerAdapter(FragmentManager fm, List<Fragment> fragments) {
		super(fm);
		this.fragments = fragments;
	}
	/* (non-Javadoc)
	 * @see android.support.v4.app.FragmentPagerAdapter#getItem(int)
	 */
	@Override
	public Fragment getItem(int position) {
		return this.fragments.get(position);
	}

	/* (non-Javadoc)
	 * @see android.support.v4.view.PagerAdapter#getCount()
	 */
	@Override
	public int getCount() {
		return this.fragments.size();
	}
}

Here is what it looks like as we page from left-to-right:

 
75 Comments

Posted by on October 5, 2011 in Android

 

Tags: , , , ,

 
Follow

Get every new post delivered to your Inbox.

Join 36 other followers