Saturday, 30 June 2012

Google I/O 2012 - Google Play: Marketing 101 for Developers


As soon as you hit the "Publish" button on your app, you become (partly) a marketer; you might as well try to be a good one. We'll share everything we know about promoting apps on Google play: building a strategic marketing framework, making good use of media channels, taking advantage of the assets we've built for developers, and convincing the Play team to feature your app.

Friday, 29 June 2012

Tablet Wars just Heating up with Google Nexus 7

With the Microsoft Surface announcement and now the Google Nexus 7, it would seem we have all the major players entered in the big tablet competition. But wait, there's more! As CNET reports via Boy Genius Report, Amazon is readying two new Kindle tablets for an end of July release. So you may want to wait on that Nexus 7 purchase for a month just to see what the options are.



Nexus 7 Review

CNET has a complete hands on review of the Nexus 7. Basically, a beautiful looking tablet with great performance for only $199. The Nexus has no expansion capabilities (no SD card slot or memory options beyond 16GB). But unless you have a large movie or music collection, this is gonna be just fine for most people. The fact that it is Wifi only should not be a surprise given the price.



There are a couple of key points for me.

  • Media - Can Google compete with Apple and Amazon on movies and books and such. To me, there is no clear advantage to going with Google in this area. While there are for Apple and Amazon Prime. My idea. Buy Netflix and offer it for free or at a big discount on your devices. That would get some attention.

  • Voice - Can they do better at voice than Siri. I'm waiting for more info on this. Some of the reviews seem to imply you can do voice dictation without an Net connection. That would be cool if it turns out to be true.

Anyway, things are getting very interesting in the summer of 2012!

What's New in Android Developers' Tools - Google I/O 2012



Google I/O 2012 - Keynote Day 1 now available



Thursday, 28 June 2012

Various Navigation Type provided in new Android SDK Tools, Revision 20.

In addition to the Master Detail Flow template described in last post, Android SDK Tools Revision 20 also provide various Navigation Type for Blank activity.

To use the template of Navigation Type, minimum SDK version of at least 14 is required.

Provided templates include:

Tabs




- Tabs + Swipe


- Swipe Views + Title Strip


- Dropdown

It's a example of Swipe Views + Title Strip:




And the auto-generated code:

package com.example.androidr20a;

import android.app.ActionBar;
import android.app.FragmentTransaction;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.NavUtils;
import android.support.v4.view.ViewPager;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class MainActivity extends FragmentActivity {

/**
* The {@link android.support.v4.view.PagerAdapter} that will provide fragments for each of the
* sections. We use a {@link android.support.v4.app.FragmentPagerAdapter} derivative, which will
* keep every loaded fragment in memory. If this becomes too memory intensive, it may be best
* to switch to a {@link android.support.v4.app.FragmentStatePagerAdapter}.
*/
SectionsPagerAdapter mSectionsPagerAdapter;

/**
* The {@link ViewPager} that will host the section contents.
*/
ViewPager mViewPager;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Create the adapter that will return a fragment for each of the three primary sections
// of the app.
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());


// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}




/**
* A {@link FragmentPagerAdapter} that returns a fragment corresponding to one of the primary
* sections of the app.
*/
public class SectionsPagerAdapter extends FragmentPagerAdapter {

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

@Override
public Fragment getItem(int i) {
Fragment fragment = new DummySectionFragment();
Bundle args = new Bundle();
args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, i + 1);
fragment.setArguments(args);
return fragment;
}

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

@Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0: return getString(R.string.title_section1).toUpperCase();
case 1: return getString(R.string.title_section2).toUpperCase();
case 2: return getString(R.string.title_section3).toUpperCase();
}
return null;
}
}

/**
* A dummy fragment representing a section of the app, but that simply displays dummy text.
*/
public static class DummySectionFragment extends Fragment {
public DummySectionFragment() {
}

public static final String ARG_SECTION_NUMBER = "section_number";

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
TextView textView = new TextView(getActivity());
textView.setGravity(Gravity.CENTER);
Bundle args = getArguments();
textView.setText(Integer.toString(args.getInt(ARG_SECTION_NUMBER)));
return textView;
}
}
}


<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<!--
This title strip will display the currently visible page title, as well as the page
titles for adjacent pages.
-->
<android.support.v4.view.PagerTitleStrip android:id="@+id/pager_title_strip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:background="#33b5e5"
android:textColor="#fff"
android:paddingTop="4dp"
android:paddingBottom="4dp" />

</android.support.v4.view.ViewPager>


Android SDK Tools, Revision 20 now support Application templates

Lets walk through the new project wizard of Android SDK Tools Revision 20 to create a Master Detail Flow Hello World.

- As normal, click File - > New to create a new project
- Select Android Application Project under Android, and click Next>.



- Setup a new project, include select Build SDK and Minimum Required SDK, click Next>.



- Configure Launcher Icon.



- New Android ADT now supports new application templates for creating new application:
  • Blank activity: Creates a new blank activity, with optional inner navigation.
  • Master Detail Flow: Creates a new master/detail flow, which is two columns on tablets, and one column on smaller screens. This creates a master fragment, detail fragment, and two activities.
Choice MasterDetailFlow as our example, click Next>.



- Accept the default setting of the New Master/Detail Flow at this moment, click Finish.



Lets run the new Hello World generated.

- Now you can select how monitor logcat.



- Run on Android Phone Galaxy Nexus, still running 4.0.2!






- Run on Android Tablet HTC Flyer, running 3.2.1.



Related:
- Various Navigation Type provided in new Android SDK Tools, Revision 20.
- Life cycle of MasterDetailFlow HelloWorld

Screenshot of Android 4.1 Jelly Bean emulator






Wednesday, 27 June 2012

Jelly Bean will be rolling out to Galaxy Nexus, Nexus S and Xoom devices in mid July

According to engadget, Jelly Bean will be rolling out to Galaxy Nexus, Nexus S and Xoom devices in mid July, along with the open source code. Developers though, can start playing with the SDK today.

Source: http://www.engadget.com/2012/06/27/jelly-bean-android-4-1-revealed-by-google/

Android 4.1 (Jelly Bean) preview platform announced



At Google I/O, the latest version of the Android platform, Android 4.1 (Jelly Bean), was announced. With Jelly Bean, we�ve made the great things about Android even better with improved system performance and enhanced user features.

Android 4.1 is the fastest and smoothest version of Android yet. Google have made improvements throughout the platform and added great new features for users and developers. This document, Android 4.1 for Developers, provides a glimpse of what's new for developers.

See the Android 4.1 APIs document for a detailed look at the new developer APIs.

Source: Android Developers Blog - Introducing Android 4.1 (Jelly Bean) preview platform, and more


Life cycle of Fragment

In order to work with Fragment, Lifecycle of Fragment is a must known issue.

It's a experience to know Lifecycle of Fragment. It display the called lifecycle relate method on screen. Via this experience, you (and me) can know more about it.

Life cycle of Fragment


Create /res/layout/fragmentlayout.xml, the layout of the fragment.
<?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" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="It's Fragment" />
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/ic_launcher"/>
</LinearLayout>


MyFragment.java, extends Fragment.
package com.exercise.AndroidExFragment;

import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class MyFragment extends Fragment {

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View myFragmentView = inflater.inflate(R.layout.fragmentlayout, container, false);
updateMyStatus("onCreateView()");
return myFragmentView;
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
updateMyStatus("onActivityCreated()");
}

@Override
public void onAttach(Activity activity) {
// TODO Auto-generated method stub
super.onAttach(activity);
updateMyStatus("onAttach()");
}

@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
updateMyStatus("onCreate()");
}

@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
updateMyStatus("onDestroy()");
}

@Override
public void onDestroyView() {
// TODO Auto-generated method stub
super.onDestroyView();
updateMyStatus("onDestroyView()");
}

@Override
public void onDetach() {
// TODO Auto-generated method stub
super.onDetach();
updateMyStatus("onDetach()");
}

@Override
public void onPause() {
// TODO Auto-generated method stub
super.onPause();
updateMyStatus("onPause()");
}

@Override
public void onResume() {
// TODO Auto-generated method stub
super.onResume();
updateMyStatus("onResume()");
}

@Override
public void onStart() {
// TODO Auto-generated method stub
super.onStart();
updateMyStatus("onStart()");
}

@Override
public void onStop() {
// TODO Auto-generated method stub
super.onStop();
updateMyStatus("onStop()");
}

private void updateMyStatus(String myst){
((AndroidExFragmentActivity)getActivity()).updateStatus(" >> MyFragment: " + myst);
}

}


The main activity, AndroidExFragmentActivity.java.
package com.exercise.AndroidExFragment;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class AndroidExFragmentActivity extends Activity {

TextView status;
String myStatus = "";

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
status = (TextView)findViewById(R.id.status);
updateMyStatus("onCreate()");
}

@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
updateMyStatus("onDestroy()");
}

@Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
updateMyStatus("onPause()");
}

@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
updateMyStatus("onResume()");
}

@Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
updateMyStatus("onStart()");
}

@Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
updateMyStatus("onStop()");
}

private void updateMyStatus(String myst){
updateStatus("Activity: " + myst);
}

public void updateStatus(String st){

if(status == null){
myStatus += "delay - " + st + "\n";
}else{
myStatus += st + "\n";
status.setText(myStatus);
}
}
}


main.xml, the main layout to include our fragment.
<?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="horizontal" >

<ScrollView
android:layout_width="0px"
android:layout_weight="3"
android:layout_height="match_parent">
<TextView
android:id="@+id/status"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#555555"/>
</ScrollView>

<fragment
class="com.exercise.AndroidExFragment.MyFragment"
android:id="@+id/myfragment"
android:layout_width="0px"
android:layout_weight="2"
android:layout_height="match_parent" />

</LinearLayout>


Download the files.

Related:
- Life cycle of MasterDetailFlow HelloWorld

Tuesday, 26 June 2012

java.lang.NoClassDefFoundError: com.google.ads.AdView

If you have Android Apps with admob, and you update admob API with current ADT (may be ADT-17 or later), may be your code can be compiled without error, but fail in run-time, caused by java.lang.NoClassDefFoundError: com.google.ads.AdView!

It seem to be problem in ADT with external jars. To solve it:

- Create a libs folder in your project.

- Copy AdMob jar, GoogleAdMobAdsSdk-6.0.1.jar, in the libs folder.

- Update Java Build Path by selecting "Add JARs..." (NOT "Add External JARs...") to add the jar in libs.


Qualcomm announce Snapdragon SDK for Android, now available for Public Preview.



The Snapdragon SDK for Android has what you�d expect in any SDK: new APIs implemented using Android extensions, grouped in software packages by function, along with the docs and sample code you need to start writing to them.

The Snapdragon SDK for Android is a collection of software components that can be downloaded to enhance your app � especially when it's running on Snapdragon Processor powered devices. It is designed to make it easy for developers and device makers to take advantage of a host of next-gen technologies � from low power, always-on geo-fencing, to complex facial recognition and superfast computer vision, to dual mic stereo audio recording.

Visit Snapdragon SDK for Android Public Preview in QDeveNet

Monday, 25 June 2012

Google I/O 2012 live event will begin in 33 hours



HTML Learning Tools from Mozilla

Firefox LogoThe Mozilla Foundation has setup its Webmaker site to help folks learn how to code HTML.

The site includes:



  • Thimble is an online HTML editor you can use to create web pages. It is a simple split pane with your HTML code on the left and the resulting output on the right. You can publish the page to the Webmaker site so it can share it with others. The site includes a number of projects designed to get your started learning.

  • X-Ray Goggles is a tool for exploring the code on a web page.

  • Popcorn is a tool for creating Video

All the tools are online which is pretty cool. The site could use a starter video or project that gets really basic. From my experience, you can't just throw tags at folks and expect them to "get it". But I would definitely give the Mozilla Foundation and A for effort.



The Register has a detailed review here.

Android ICS Emulator for Mac OS with Intel� Hardware Accelerated Execution Manager


Eric Adams, a Software Engineer at Intel, will show you step-by-step how to download and install on Mac the latest Android ICS emulator for x86.

Android ICS Emulator for Ubuntu with KVM acceleration supported by Intel VT-x


Eric Adams, a Software Engineer at Intel, will show you step-by-step how to download and install on Ubuntu the latest Android ICS emulator for x86.

Android ICS Emulator for Microsoft Windows with Intel� Hardware Accelerated Execution Manager


Eric Adams, a Software Engineer at Intel, will show you step-by-step how to download and install on Windows the latest Android ICS emulator for x86.

Developing Android Apps with the Intel� Hardware Accelerated Execution Manager

The Benefits of Developing Android Apps with the Intel� Hardware Accelerated Execution Manager

This video shows how any Android developer using an Intel� Architecture (IA) based host PC with Windows, Mac or Linux can greatly speed up Android emulation by leveraging Intel� Virtualization Technology. Side by side comparisons show the performance gains of using the free Intel� HAXM driver with the Intel� x86 Atom� System Image to deliver much faster boot times, game play, and app execution. Whether you�re coding in Dalvik Java or C/C++ (for NDK apps), and regardless of whether you�re targeting ARM or IA-based smartphones or tablets, this solution will deliver a far superior Android emulation experience for faster testing and debug of your Android apps.

Sunday, 24 June 2012

AsyncTask run in background thread of a invisible Fragment of ViewPager

Further exercise from last post "Communication between Fragments in ViewPager".

When a button in MyFragmentA clicked, it will start a AsyncTask in MyFragmentC, running in background and update a ProgressBar. When the ProgressBar finished, it will update MyFragmentB. It can be noted that the AsyncTask run in background even MyFragmentC is not in visible screen.

AsyncTask run in background thread of a invisible Fragment of ViewPager


Modify MyFragmentA.java and /res/layout/fragment_a.xml to add a Butten to start AsyncTask in MyFragmentC.
package com.exercise.AndroidViewPager;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MyFragmentA extends Fragment {

EditText A_input;
Button A_enter;
Button A_startCProgress;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View myFragmentView = inflater.inflate(R.layout.fragment_a, container, false);

A_input = (EditText)myFragmentView.findViewById(R.id.a_input);
A_enter = (Button)myFragmentView.findViewById(R.id.a_enter);
A_enter.setOnClickListener(A_enterOnClickListener);

A_startCProgress = (Button)myFragmentView.findViewById(R.id.a_startcprogress);
A_startCProgress.setOnClickListener(A_startCProgressOnClickListener);

return myFragmentView;
}

OnClickListener A_startCProgressOnClickListener
= new OnClickListener(){

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
String TabOfFragmentC = ((AndroidViewPagerActivity)getActivity()).getTabFragmentC();

MyFragmentC fragmentC = (MyFragmentC)getActivity()
.getSupportFragmentManager()
.findFragmentByTag(TabOfFragmentC);

fragmentC.StartProgress();

}

};

OnClickListener A_enterOnClickListener
= new OnClickListener(){

@Override
public void onClick(View arg0) {

String textPassToB = A_input.getText().toString();

String TabOfFragmentB = ((AndroidViewPagerActivity)getActivity()).getTabFragmentB();

MyFragmentB fragmentB = (MyFragmentB)getActivity()
.getSupportFragmentManager()
.findFragmentByTag(TabOfFragmentB);

fragmentB.b_updateText(textPassToB);

Toast.makeText(getActivity(),
"text sent to Fragment B:\n " + TabOfFragmentB,
Toast.LENGTH_LONG).show();
}};

}


<?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" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="It's Fragment A" />
<EditText
android:id="@+id/a_input"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/a_enter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Enter to Fragment B"/>
<Button
android:id="@+id/a_startcprogress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Start Async Progress in Fragment C"/>
</LinearLayout>


Modify MyFragmentC.java and /res/layout/fragment_c.xml to add a ProgressBar and implement AsyncTask.
package com.exercise.AndroidViewPager;

import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;

public class MyFragmentC extends Fragment {

ProgressBar cProgress;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View myFragmentView = inflater.inflate(R.layout.fragment_c, container, false);

String myTag = getTag();
((AndroidViewPagerActivity)getActivity()).setTabFragmentC(myTag);

cProgress = (ProgressBar)myFragmentView.findViewById(R.id.progressbar);

return myFragmentView;
}

public void StartProgress(){
new ProgressAsyncTask().execute();
}

public class ProgressAsyncTask extends
AsyncTask<Void, Integer, Void> {

int myProgress;

@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
myProgress = 0;
}

@Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);

String TabOfFragmentB = ((AndroidViewPagerActivity)getActivity()).getTabFragmentB();
MyFragmentB fragmentB = (MyFragmentB)getActivity()
.getSupportFragmentManager()
.findFragmentByTag(TabOfFragmentB);
fragmentB.b_updateText("Progress finished!");

}

@Override
protected Void doInBackground(Void... arg0) {
// TODO Auto-generated method stub
while(myProgress<100){
myProgress++;
publishProgress(myProgress);
SystemClock.sleep(100);
}
return null;
}

@Override
protected void onProgressUpdate(Integer... values) {
// TODO Auto-generated method stub
cProgress.setProgress(values[0]);
}

}

}


<?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" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="It's Fragment C" />
<ProgressBar
android:id="@+id/progressbar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleHorizontal"
android:progress="0"
android:max="100"/>
</LinearLayout>


main activity, AndroidViewPagerActivity.java
package com.exercise.AndroidViewPager;

import java.util.ArrayList;

import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.FragmentTransaction;
import android.content.Context;
import android.os.Bundle;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;

public class AndroidViewPagerActivity extends FragmentActivity {

ViewPager mViewPager;
TabsAdapter mTabsAdapter;

String TabFragmentB;
String TabFragmentC;

public void setTabFragmentB(String t){
TabFragmentB = t;
}

public String getTabFragmentB(){
return TabFragmentB;
}

public void setTabFragmentC(String t){
TabFragmentC = t;
}

public String getTabFragmentC(){
return TabFragmentC;
}

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

mViewPager = new ViewPager(this);
mViewPager.setId(R.id.pager);
setContentView(mViewPager);

final ActionBar bar = getActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);

mTabsAdapter = new TabsAdapter(this, mViewPager);
mTabsAdapter.addTab(bar.newTab().setText("Fragment A"),
MyFragmentA.class, null);
mTabsAdapter.addTab(bar.newTab().setText("Fragment B"),
MyFragmentB.class, null);
mTabsAdapter.addTab(bar.newTab().setText("Fragment C"),
MyFragmentC.class, null);

if (savedInstanceState != null) {
bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
}

}

@Override
protected void onSaveInstanceState(Bundle outState) {
//super.onSaveInstanceState(outState);
outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
}

public static class TabsAdapter extends FragmentPagerAdapter
implements ActionBar.TabListener, ViewPager.OnPageChangeListener {

private final Context mContext;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();

static final class TabInfo {
private final Class<?> clss;
private final Bundle args;

TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
}
}

public TabsAdapter(FragmentActivity activity, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = activity.getActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}

public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
TabInfo info = new TabInfo(clss, args);
tab.setTag(info);
tab.setTabListener(this);
mTabs.add(info);
mActionBar.addTab(tab);
notifyDataSetChanged();
}

@Override
public void onPageScrollStateChanged(int state) {
// TODO Auto-generated method stub

}

@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// TODO Auto-generated method stub

}

@Override
public void onPageSelected(int position) {
// TODO Auto-generated method stub
mActionBar.setSelectedNavigationItem(position);
}

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

}

@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Object tag = tab.getTag();
for (int i=0; i<mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
mViewPager.setCurrentItem(i);
}
}
}

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

}

@Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}

@Override
public int getCount() {
return mTabs.size();
}

}

}


Download the files.

Saturday, 23 June 2012

Communication between Fragments in ViewPager

In Previous exercise "ViewPager" (and fix of "NullPointerException of ViewPager when change orientation"), I create a ViewPager with three independent Fragments. Now, I want to make some input (EditText) from Fragment A, then transfer it to Fragment B.

Communication between Fragments in ViewPager


With FragmentManager, we can access another fragment from our current fragment by calling findFragmentByTag(<tag of target fragment>). But, what's the tag of Fragment B? I can't found any method something like setTag()!

Luckly; I found getTag() method to get the tag name of current fragment. So I create a mechanism to access the tag across fragments via the main activity, AndroidViewPagerActivity. - Call getTag() in onCreateView() of MyFragmentB. Then pass it to the main activity AndroidViewPagerActivity. When MyFragmentA need to pass something to MyFragmentB, it retrieve it from AndroidViewPagerActivity.

Modify the main activity, AndroidViewPagerActivity.java, to have a String TabFragmentB; and implement setTabFragmentB() and getTabFragmentB() to access it.
package com.exercise.AndroidViewPager;

import java.util.ArrayList;

import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.FragmentTransaction;
import android.content.Context;
import android.os.Bundle;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;

public class AndroidViewPagerActivity extends FragmentActivity {

ViewPager mViewPager;
TabsAdapter mTabsAdapter;

String TabFragmentB;

public void setTabFragmentB(String t){
TabFragmentB = t;
}

public String getTabFragmentB(){
return TabFragmentB;
}

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

mViewPager = new ViewPager(this);
mViewPager.setId(R.id.pager);
setContentView(mViewPager);

final ActionBar bar = getActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);

mTabsAdapter = new TabsAdapter(this, mViewPager);
mTabsAdapter.addTab(bar.newTab().setText("Fragment A"),
MyFragmentA.class, null);
mTabsAdapter.addTab(bar.newTab().setText("Fragment B"),
MyFragmentB.class, null);
mTabsAdapter.addTab(bar.newTab().setText("Fragment C"),
MyFragmentC.class, null);

if (savedInstanceState != null) {
bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
}

}

@Override
protected void onSaveInstanceState(Bundle outState) {
//super.onSaveInstanceState(outState);
outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
}

public static class TabsAdapter extends FragmentPagerAdapter
implements ActionBar.TabListener, ViewPager.OnPageChangeListener {

private final Context mContext;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();

static final class TabInfo {
private final Class<?> clss;
private final Bundle args;

TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
}
}

public TabsAdapter(FragmentActivity activity, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = activity.getActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}

public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
TabInfo info = new TabInfo(clss, args);
tab.setTag(info);
tab.setTabListener(this);
mTabs.add(info);
mActionBar.addTab(tab);
notifyDataSetChanged();
}

@Override
public void onPageScrollStateChanged(int state) {
// TODO Auto-generated method stub

}

@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// TODO Auto-generated method stub

}

@Override
public void onPageSelected(int position) {
// TODO Auto-generated method stub
mActionBar.setSelectedNavigationItem(position);
}

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

}

@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Object tag = tab.getTag();
for (int i=0; i<mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
mViewPager.setCurrentItem(i);
}
}
}

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

}

@Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}

@Override
public int getCount() {
return mTabs.size();
}

}

}


Modify MyFragmentA.java and /res/layout/fragment_a.xml to add a ExitText and a Butten to send something.

package com.exercise.AndroidViewPager;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MyFragmentA extends Fragment {

EditText A_input;
Button A_enter;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View myFragmentView = inflater.inflate(R.layout.fragment_a, container, false);

A_input = (EditText)myFragmentView.findViewById(R.id.a_input);
A_enter = (Button)myFragmentView.findViewById(R.id.a_enter);
A_enter.setOnClickListener(A_enterOnClickListener);

return myFragmentView;
}

OnClickListener A_enterOnClickListener
= new OnClickListener(){

@Override
public void onClick(View arg0) {

String textPassToB = A_input.getText().toString();

String TabOfFragmentB = ((AndroidViewPagerActivity)getActivity()).getTabFragmentB();

MyFragmentB fragmentB = (MyFragmentB)getActivity()
.getSupportFragmentManager()
.findFragmentByTag(TabOfFragmentB);

fragmentB.b_updateText(textPassToB);

Toast.makeText(getActivity(),
"text sent to Fragment B:\n " + TabOfFragmentB,
Toast.LENGTH_LONG).show();
}};

}


<?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" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="It's Fragment A" />
<EditText
android:id="@+id/a_input"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/a_enter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Enter to Fragment B"/>
</LinearLayout>


Modify MyFragmentB.java and /res/layout/fragment_b.xml to receive something.

package com.exercise.AndroidViewPager;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

public class MyFragmentB extends Fragment {

TextView b_received;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View myFragmentView = inflater.inflate(R.layout.fragment_b, container, false);

b_received = (TextView)myFragmentView.findViewById(R.id.b_received);
String myTag = getTag();

((AndroidViewPagerActivity)getActivity()).setTabFragmentB(myTag);

Toast.makeText(getActivity(),
"MyFragmentB.onCreateView(): " + myTag,
Toast.LENGTH_LONG).show();

return myFragmentView;
}

public void b_updateText(String t){
b_received.setText(t);
}

}


<?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" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="It's Fragment B" />
<TextView
android:id="@+id/b_received"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="center"
android:src="@drawable/ic_launcher"/>
</LinearLayout>


Download the files.

Next:
- AsyncTask run in background thread of a invisible Fragment of ViewPager


Friday, 22 June 2012

NullPointerException of ViewPager when change orientation

In my last exercise of "ViewPager", when change orientation, NullPointerException will be thrown in onSaveInstanceState()!

May be it's a bug in ViewPager. Note the class ViewPager is currently under early design and development. May be it will be fixed in later updates.

At this moment, my solution is to comment the statement to call super.onSaveInstanceState(outState).

 @Override
protected void onSaveInstanceState(Bundle outState) {
//super.onSaveInstanceState(outState);
outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
}


Next:
- Communication between Fragments in ViewPager

ViewPager

android.support.v4.view.ViewPager is Layout manager that allows the user to flip left and right through pages of data.

Note this class is currently under early design and development. The API will likely change in later updates of the compatibility library, requiring changes to the source code of apps when they are compiled against the newer version.

ViewPager


To use compatibility library, Android Support Package is needed. Refer to last post to "Add Android Support Package".

Create three Fragments, each one corresponding to one tab. Please note that the Fragment(s) extends android.support.v4.app.Fragment. 

MyFragmentA.java
package com.exercise.AndroidViewPager;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class MyFragmentA extends Fragment {

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View myFragmentView = inflater.inflate(R.layout.fragment_a, container, false);
return myFragmentView;
}

}


/res/layout/fragment_a.xml
<?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" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="It's Fragment A" />
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/ic_launcher"/>
</LinearLayout>


MyFragmentB.java
package com.exercise.AndroidViewPager;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class MyFragmentB extends Fragment {

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View myFragmentView = inflater.inflate(R.layout.fragment_b, container, false);
return myFragmentView;
}

}


/res/layout/fragment_b.xml
<?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" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="It's Fragment B" />
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="center"
android:src="@drawable/ic_launcher"/>
</LinearLayout>


MyFragmentC.java
package com.exercise.AndroidViewPager;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class MyFragmentC extends Fragment {

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View myFragmentView = inflater.inflate(R.layout.fragment_c, container, false);
return myFragmentView;
}

}


/res/layout/fragment_c.xml
<?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" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="It's Fragment C" />

</LinearLayout>


Main code, AndroidViewPagerActivity.java
package com.exercise.AndroidViewPager;

import java.util.ArrayList;

import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.FragmentTransaction;
import android.content.Context;
import android.os.Bundle;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;

public class AndroidViewPagerActivity extends FragmentActivity {

ViewPager mViewPager;
TabsAdapter mTabsAdapter;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

mViewPager = new ViewPager(this);
mViewPager.setId(R.id.pager);
setContentView(mViewPager);

final ActionBar bar = getActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);

mTabsAdapter = new TabsAdapter(this, mViewPager);
mTabsAdapter.addTab(bar.newTab().setText("Fragment A"),
MyFragmentA.class, null);
mTabsAdapter.addTab(bar.newTab().setText("Fragment B"),
MyFragmentB.class, null);
mTabsAdapter.addTab(bar.newTab().setText("Fragment C"),
MyFragmentC.class, null);

if (savedInstanceState != null) {
bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
}

}

@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
}

public static class TabsAdapter extends FragmentPagerAdapter
implements ActionBar.TabListener, ViewPager.OnPageChangeListener {

private final Context mContext;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();

static final class TabInfo {
private final Class<?> clss;
private final Bundle args;

TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
}
}

public TabsAdapter(FragmentActivity activity, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = activity.getActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}

public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
TabInfo info = new TabInfo(clss, args);
tab.setTag(info);
tab.setTabListener(this);
mTabs.add(info);
mActionBar.addTab(tab);
notifyDataSetChanged();
}

@Override
public void onPageScrollStateChanged(int state) {
// TODO Auto-generated method stub

}

@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// TODO Auto-generated method stub

}

@Override
public void onPageSelected(int position) {
// TODO Auto-generated method stub
mActionBar.setSelectedNavigationItem(position);
}

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

}

@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Object tag = tab.getTag();
for (int i=0; i<mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
mViewPager.setCurrentItem(i);
}
}
}

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

}

@Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}

@Override
public int getCount() {
return mTabs.size();
}

}

}


Download the files.

!!! It's a bug here: when change orientation, NullPointerException will be thrown. Please refer to next post "NullPointerException of ViewPager when change orientation" for my solution.

Next:
- Communication between Fragments in ViewPager

Related:
- ActionBar in Tab navigation mode

Add Android Support Package

I have a old post "Install and setup Compatibility Package" describe how to include Android Support Package in Java Build Path. I try again it recently, it seem that the method no longer work! When work with android.support.v4.app.FragmentActivity, java.lang.ClassNotFoundException will be thrown.

It can be solved by Add Support Library in Eclipse menu.
- New a Android project target Android 3.0 (API Level 11).

- Modify AndroidManifest.xml to specify minSdkVersion and targetSdkVersion:
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="11"/>

- Add Android Support Library.
Right click on the project in Eclipse, select Android Tools, Add Support Library...

Add Support Library...


Accept to install Android Support.

install Android Support Package


- Test it
Modify your activity extends FragmentActivity instead Activity, and import android.support.v4.app.FragmentActivity.

Now you can run it without error.

Thursday, 21 June 2012

New look of Android Developer Site

Android Developer Site redesigned with more streamlined, simplified, and focus experienced.

Android Developer Site


How to NFC

Google I/O 2011: How to NFC
Gingerbread brings a comprehensive NFC reader/writer API, and some modest but surprisingly powerful P2P support. Come hear why you should care about NFC technology, what kinds of applications are possible right now, and best practices for deployment.



Near Field Communication (NFC) is a set of short-range wireless technologies, typically requiring a distance of 4cm or less to initiate a connection. NFC allows you to share small payloads of data between an NFC tag and an Android-powered device, or between two Android-powered devices.


Wednesday, 20 June 2012

960px Grid Design

What is a 960px grid design? I had the same question myself. I stumbled across this concept when a co-worker wrote a post about Twitter Bootstrap. This is a HTML5 and CSS3 framework for developing web applications using 960px width and a 12 column grid. So why 960px and why a 12 column grid? Well the answer to that is a bit complicated. I found the 960 Grid site which provided a little more information.



What is a 960px Grid system?

A process for designing web sites based on classic print typography principles. The width is based on a common minimum laptop display size of 1024x768. The 960px size fits well on that screen size. In addition, 960 gives you a number of options for creating grids to lay out your page on. At least that is my understanding, I have a lot more reading to do.



Why use it?

Bottom line, you get beautiful design. If you go to the 960.gs site, they include a number of examples. It just seems to give sites a nice balance and weight to the layouts.



Site Redesigns

This perked my interest as I am in the process of redesigning my sites for HTML5 and mobile devices. It is still early days, but I have some preliminary stuff up. I have only applied the 960 grid to the Blue Sky example, I have not got to it yet on Abbey Workshop.

Anyway, as I make progress I will try to make some additional posts on the subject.

Why Siri Matters

Read Write Web has this great post on "Why Siri Matters". I'm a big believer that voice will be the killer interface for all things mobile. We are just in the very beginning of voice interfaces and I don't think we can even conceive the amount of change this will bring to our lives.



The most obvious implications are less reliance of desktop computing. What does that mean for companies like Google, Facebook, and Microsoft? With agents like Siri will most web searches go through Google? Will you do all your work processing with voice?

Create ActionBar in Tab navigation mode

ActionBar in Tab navigation mode

ActionBar in Tab navigation mode


New a Android project target Android 3.2, API Level 13.

Create three Fragments, each one corresponding to one tab.

MyFragmentA.java
package com.exercise.AndroidNavigationTabs;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class MyFragmentA extends Fragment {

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View myFragmentView = inflater.inflate(R.layout.fragment_a, container, false);
return myFragmentView;
}

}


/res/layout/fragment_a.xml
<?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" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="It's Fragment A" />
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/ic_launcher"/>
</LinearLayout>


MyFragmentB.java
package com.exercise.AndroidNavigationTabs;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class MyFragmentB extends Fragment {

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View myFragmentView = inflater.inflate(R.layout.fragment_b, container, false);
return myFragmentView;
}

}


/res/layout/fragment_b.xml
<?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" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="It's Fragment B" />
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="center"
android:src="@drawable/ic_launcher"/>
</LinearLayout>


MyFragmentC.java
package com.exercise.AndroidNavigationTabs;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class MyFragmentC extends Fragment {

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View myFragmentView = inflater.inflate(R.layout.fragment_c, container, false);
return myFragmentView;
}

}


/res/layout/fragment_c.xml
<?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" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="It's Fragment C" />

</LinearLayout>


Main code, AndroidNavigationTabsActivity.java
package com.exercise.AndroidNavigationTabs;

import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;

public class AndroidNavigationTabsActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

final ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

Tab tabA = actionBar.newTab();
tabA.setText("Tab A");
tabA.setTabListener(new TabListener<MyFragmentA>(this, "Tag A", MyFragmentA.class));
actionBar.addTab(tabA);

Tab tabB = actionBar.newTab();
tabB.setText("Tab B");
tabB.setTabListener(new TabListener<MyFragmentB>(this, "Tag B", MyFragmentB.class));
actionBar.addTab(tabB);

Tab tabC = actionBar.newTab();
tabC.setText("Tab C");
tabC.setTabListener(new TabListener<MyFragmentC>(this, "Tag C", MyFragmentC.class));
actionBar.addTab(tabC);

if (savedInstanceState != null) {
int savedIndex = savedInstanceState.getInt("SAVED_INDEX");
getActionBar().setSelectedNavigationItem(savedIndex);
}

}

@Override
protected void onSaveInstanceState(Bundle outState) {
// TODO Auto-generated method stub
super.onSaveInstanceState(outState);
outState.putInt("SAVED_INDEX", getActionBar().getSelectedNavigationIndex());
}

public static class TabListener<T extends Fragment>
implements ActionBar.TabListener{

private final Activity myActivity;
private final String myTag;
private final Class<T> myClass;

public TabListener(Activity activity, String tag, Class<T> cls) {
myActivity = activity;
myTag = tag;
myClass = cls;
}

@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {

Fragment myFragment = myActivity.getFragmentManager().findFragmentByTag(myTag);

// Check if the fragment is already initialized
if (myFragment == null) {
// If not, instantiate and add it to the activity
myFragment = Fragment.instantiate(myActivity, myClass.getName());
ft.add(android.R.id.content, myFragment, myTag);
} else {
// If it exists, simply attach it in order to show it
ft.attach(myFragment);
}

}

@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {

Fragment myFragment = myActivity.getFragmentManager().findFragmentByTag(myTag);

if (myFragment != null) {
// Detach the fragment, because another one is being attached
ft.detach(myFragment);
}

}

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

}

}
}


Download the files.

Related:
- ViewPager