Saturday, June 30, 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.

Thursday, June 28, 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, June 27, 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, June 26, 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, June 25, 2012

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



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, June 24, 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, June 23, 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

Please notice:
This exercise aim to demonstrate how to communicate between Fragments in ViewPager. But, you have to take care about live-cycle of the Fragments. For example, may be the target Fragment have not yet created when data is passed. Or, the Fragment have been destroyed after data passed. Read more: Life cycle of Fragments in ViewPager.

Friday, June 22, 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


(This example implement ViewPager using FragmentPagerAdapter. For ViewPager using custom PagerAdapter, read HERE.)

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
ViewPager example, with switching page programmatically

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, June 21, 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, June 20, 2012

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


Sunday, June 17, 2012

Split Action Bar for Android 4

The old article demonstrate how to "Create ActionBar using XML" for Android 3.

When your application is running on Android 4.0 (API level 14) and higher, there's an extra mode available for the action bar called "split action bar." When you enable split action bar, a separate bar appears at the bottom of the screen to display all action items when the activity is running on a narrow screen (such as a portrait-oriented handset). Splitting the action bar to separate the action items ensures that a reasonable amount of space is available to display all your action items on a narrow screen, while leaving room for navigation and title elements at the top.

To enable split action bar, simply add uiOptions="splitActionBarWhenNarrow" to your <activity> or <application> manifest element.


Split Action Bar:
Split Action Bar


Normal Action Bar:
Normal Action Bar


- Add android:uiOptions="splitActionBarWhenNarrow" in AndroidManifest.xml.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.exercise.AndroidSplitActionBar"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="14" />

    <application
        
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:uiOptions="splitActionBarWhenNarrow"
            android:name=".AndroidSplitActionBarActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>


- /res/menu/menu.xml define the items in Action Bar.
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/itemid_0"
        android:title="Action Item 0"
        android:icon="@drawable/ic_launcher"
        android:orderInCategory="0"
        android:showAsAction="ifRoom|withText" />
    <item android:id="@+id/itemid_1"
        android:title="Action Item 1"
        android:orderInCategory="0"
        android:showAsAction="ifRoom|withText" />
    <item android:id="@+id/itemid_2"
        android:title="Action Item 2"
        android:orderInCategory="0"
        android:showAsAction="ifRoom|withText" />

</menu>


- Override onCreateOptionsMenu() method to inflate menu.
package com.exercise.AndroidSplitActionBar;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;

public class AndroidSplitActionBarActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  MenuInflater menuInflater = getMenuInflater();
        menuInflater.inflate(R.menu.menu, menu);

        return super.onCreateOptionsMenu(menu);
 }
}



Saturday, June 16, 2012

Programmatically create layout and view, with ID assigned by setId().

This example demonstrate how to create layout and view at run time using Java code, instead of XML code. We can assign IDs for the layouts/views by calling setId() mdthod.

Programmatically create layout and view, with ID assigned by setId().

In order to call setId() with named id, create /res/values/ids.xml to define out ID resources.
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item type="id" name="layout_id"/>
    <item type="id" name="image_id" />
</resources>


Main code.
package com.exercise.AndroidSetId;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;

public class AndroidSetIdActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        LinearLayout layout = new LinearLayout(AndroidSetIdActivity.this);
        layout.setId(R.id.layout_id);
        LayoutParams layoutParams 
         = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        layout.setLayoutParams(layoutParams);
        layout.setOrientation(LinearLayout.VERTICAL);
        
        ImageView imageView = new ImageView(AndroidSetIdActivity.this);
        imageView.setId(R.id.image_id);
        imageView.setImageResource(R.drawable.ic_launcher);
        LayoutParams imageViewLayoutParams 
         = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        imageView.setLayoutParams(imageViewLayoutParams);
        
        layout.addView(imageView);
        
        setContentView(layout);
        
        layout.setOnClickListener(viewOnClickListener);
        imageView.setOnClickListener(viewOnClickListener);
    }
    
    OnClickListener viewOnClickListener
    = new OnClickListener(){

  @Override
  public void onClick(View v) {
   
   int myId = v.getId();
   
   Toast.makeText(AndroidSetIdActivity.this, 
     "ID: " + String.valueOf(myId) + " clicked", 
     Toast.LENGTH_LONG).show();
  }};
}



Schedule of Android Sessions in Google IO 2012

Be among the first to see the latest demos and developments from Android. Watch the keynote and over 40 sessions live streamed from Google I/O! It all begins June 27, at 9am.

Check the Android sessions schedule.


Improve Android Emulator performance with Intel Atom x86 System Image

Back to the releasing of Android SDK r17, Intel Atom x86 System Image was included. AVD with Intel Atom x86 System Image can  access the host CPU natively and offer significantly faster execution.

Android emulator with Intel Atom x86 System Image


To install Intel Atom x86 System Image, click Window from Eclipse menu, select Android SDK Manager. Check to install package of Intel Atom x86 System Image, it's available on Android 4.0.3(API 15) and 2.3.3(API 10) currently.



Create emulator using Intel Atom x86 System Image

- Window -> AVD Manager. New a AVD.



- Select CPU/ABI of Intel Atom (x86). Enter others as needed. Click Create AVD.