Friday 29 August 2014

Android: Fragment demo to Add & Replace fragment, Different UI for different orientation.

Please visit my website for latest post about the difference between Add & Replace method and use of Back Stack.

http://dipenpatel.co.in/understanding-android-fragmentsadd-replace-method-and-back-stack/




Adding here Fragment demo which "Add" & "Replace" fragment in fragment holder.

Adding demo app for::

  • Fragment
  • Add & Replace fragment
  • Different UI for different orientation
  • Maintaining BackStack of Fragment






                           1. Portrait UI                                        2. Lanscape UI

We will add different layout xml in different layout folder "layout" & "layout-land" to render differently on different orientation.

There are two Fragment & two Button, first button will "Replace" first fragment container and second button will "Add" fragment in second fragment container.

When we "Replace" fragment it will detach existing fragment and "Add" new fragment.
When we "Add" fragment it will add new fragment and existing fragment remain same.

We can maintain back stack of fragment which can be accessible later.
  /**
   * We can add name to this back stack and we can access this fragment by name later.
     Otherwise we can pass null to parameter*/
    fragmentTwoTransaction.addToBackStack(null);  

Note:
I have added every fragment method name in StringBuilder when this method execute and Toast this StringBuilder onDetach of fragment. You can uncomment the Toast line in onDetach method and check fragment lifecycle.

About Code:::

LauncherActivity.java

/**
 * @author dipenp
 *
 */
public class LauncherActivity extends Activity {

private Button replaceFragmentButton, addFragmentButton;
private static int FRAGMENT_ONE_POSITION = 0, FRAGMENT_TWO_POSITION = 0;

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

/**************************************************
* Adding layout with two Button & two Fragment.
* One button to "Replace" fragment in first fragment & one button to "Add" fragment in second fragment.
* We have added same layout with different structure in different folder one in layout & one in layout-land(to display when device in landscape mode)
**************************************************/
setContentView(R.layout.activity_launcher);

replaceFragmentButton = (Button)findViewById(R.id.buttonOne);
addFragmentButton = (Button)findViewById(R.id.buttonTwo);

/**
* When we click on this button it will "Replace" existing fragment and add new one.
*/
replaceFragmentButton.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
FragmentTransaction fragmentOneTransaction = getFragmentManager().beginTransaction();

switch (FRAGMENT_ONE_POSITION) {
case 0:
FRAGMENT_ONE_POSITION++;
fragmentOneTransaction.replace(R.id.fragment_one_holder, new FragmentOne(LauncherActivity.this));
break;
case 1:
FRAGMENT_ONE_POSITION++;
fragmentOneTransaction.replace(R.id.fragment_one_holder, new FragmentTwo(LauncherActivity.this));
break;
case 2:
FRAGMENT_ONE_POSITION = 0;
fragmentOneTransaction.replace(R.id.fragment_one_holder, new FragmentThree(LauncherActivity.this));
break;
default:
break;
}

// fragmentOneTransaction.addToBackStack(null);
fragmentOneTransaction.commit();
}
});


/**
* When we click on this button it will "Add" new fragment.
*/
addFragmentButton.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
FragmentTransaction fragmentTwoTransaction = getFragmentManager().beginTransaction();

switch (FRAGMENT_TWO_POSITION) {
case 0:
FRAGMENT_TWO_POSITION++;
fragmentTwoTransaction.add(R.id.fragment_two_holder, new FragmentOne(LauncherActivity.this));
break;
case 1:
FRAGMENT_TWO_POSITION++;
fragmentTwoTransaction.add(R.id.fragment_two_holder, new FragmentTwo(LauncherActivity.this));
break;
case 2:
FRAGMENT_TWO_POSITION = 0;
fragmentTwoTransaction.add(R.id.fragment_two_holder, new FragmentThree(LauncherActivity.this));
break;
default:
break;
}

/**
* Adding current fragment to back stack which can be pop back when we need.
* We can add name to this back stack and we can access this fragment by name later.
*/
fragmentTwoTransaction.addToBackStack(null);
fragmentTwoTransaction.commit();
}
});
}

/**************************************
* Overriding onBackPressed button and pop backStack fragment.
*
**************************************/
@Override
public void onBackPressed() {
FragmentManager fm = getFragmentManager();
if (fm.getBackStackEntryCount() > 0) {
fm.popBackStack();
} else {
super.onBackPressed();
}
}

}

You can download demo code from below url:
https://drive.google.com/file/d/0B0mH97AUwQqhMXVkc0N6VkY0cGM/edit?usp=sharing





Sunday 24 August 2014

Android: Navigation Drawer with Multiple activities.


Now a days most of the Android application are using Navigation Drawer/Sliding Drawer like view.
Some of them are using library for doing this. Android has also provided Navigation Drawer to achieve this.
http://developer.android.com/training/implementing-navigation/nav-drawer.html

In this above link we can find demo app to add navigation drawer in our app. But we have to use fragment for achieving this and it is recommend to use fragment.

But in case if we don't want to use fragment or we want to add Navigation Drawer in already existing app which contain activities and we don't want to replace them with fragment.

We can achieve same Navigation Drawer with activities too....I am going to add here demo app to add Navigation Drawer with multiple activities.


First of all we have to create on BaseActivity which will contain layout and all the code related to navigation drawer and then we will use this BaseActivity as parent activity to other activities.

We will extends this BaseActivity  to all the other activities rather than directly extending Activity class in our activities. This way our all the activities will contain same Navigation Drawer without adding any extra code in every activity.

About Code:::

First of all we have to create XML file for adding navigation drawer, we will use this layout xml file in our BaseActivity.

navigation_drawer_base_layout.xml

<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <ListView
        android:id="@+id/left_drawer"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="#111"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp" />
</android.support.v4.widget.DrawerLayout>

As we are already adding layout in BaseActivity we can not add layout in child activity..otherwise it will not work properly so we will add our own layout for the child activity in FrameLayout of above XML.

/* Layout Inflater to add view in frame layout*/
Code Example :: getLayoutInflater().inflate(R.layout.activity_main, frameLayout);
This way we will get our own layout in child activity. Now we can use this as any other normal activity.


BaseActivity.java:

package com.navigation.drawer.activity;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.widget.DrawerLayout;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.FrameLayout;
import android.widget.ListView;
import android.widget.Toast;

/**
 * @author dipenp
 *
 * This activity will add Navigation Drawer for our application and all the code related to navigation drawer.
 * We are going to extend all our other activites from this BaseActivity so that every activity will have Navigation Drawer in it.
 * This activity layout contain one frame layout in which we will add our child activity layout.  
 */
public class BaseActivity extends Activity {

/**
*  Frame layout: Which is going to be used as parent layout for child activity layout.
*  This layout is protected so that child activity can access this
*  */
protected FrameLayout frameLayout;

/**
* ListView to add navigation drawer item in it.
* We have made it protected to access it in child class. We will just use it in child class to make item selected according to activity opened.
*/

protected ListView mDrawerList;

/**
* List item array for navigation drawer items.
* */
protected String[] listArray = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };

/**
* Static variable for selected item position. Which can be used in child activity to know which item is selected from the list.
* */
protected static int position;

/**
*  This flag is used just to check that launcher activity is called first time
*  so that we can open appropriate Activity on launch and make list item position selected accordingly.  
* */
private static boolean isLaunch = true;

/**
*  Base layout node of this Activity.  
* */
private DrawerLayout mDrawerLayout;

/**
* Drawer listner class for drawer open, close etc.
*/
private ActionBarDrawerToggle actionBarDrawerToggle;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.navigation_drawer_base_layout);

frameLayout = (FrameLayout)findViewById(R.id.content_frame);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerList = (ListView) findViewById(R.id.left_drawer);

// set a custom shadow that overlays the main content when the drawer opens
//mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
     
// set up the drawer's list view with items and click listener
mDrawerList.setAdapter(new ArrayAdapter<String>(this, R.layout.drawer_list_item, listArray));
mDrawerList.setOnItemClickListener(new OnItemClickListener() {

@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {

openActivity(position);
}
});

// enable ActionBar app icon to behave as action to toggle nav drawer
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);

// ActionBarDrawerToggle ties together the the proper interactions between the sliding drawer and the action bar app icon
actionBarDrawerToggle = new ActionBarDrawerToggle(
this, /* host Activity */
mDrawerLayout, /* DrawerLayout object */
R.drawable.ic_launcher,     /* nav drawer image to replace 'Up' caret */
R.string.open_drawer,       /* "open drawer" description for accessibility */
R.string.close_drawer)      /* "close drawer" description for accessibility */
{
@Override
public void onDrawerClosed(View drawerView) {
getActionBar().setTitle(listArray[position]);
                invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
super.onDrawerClosed(drawerView);
}

@Override
public void onDrawerOpened(View drawerView) {
getActionBar().setTitle(getString(R.string.app_name));
                invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
super.onDrawerOpened(drawerView);
}

@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
super.onDrawerSlide(drawerView, slideOffset);
}

@Override
public void onDrawerStateChanged(int newState) {
super.onDrawerStateChanged(newState);
}
};
mDrawerLayout.setDrawerListener(actionBarDrawerToggle);


/**
* As we are calling BaseActivity from manifest file and this base activity is intended just to add navigation drawer in our app.
* We have to open some activity with layout on launch. So we are checking if this BaseActivity is called first time then we are opening our first activity.
* */
if(isLaunch){
/**
 *Setting this flag false so that next time it will not open our first activity.
 *We have to use this flag because we are using this BaseActivity as parent activity to our other activity.
 *In this case this base activity will always be call when any child activity will launch.
 */
isLaunch = false;
openActivity(0);
}
}

/**
* @param position
*
* Launching activity when any list item is clicked.
*/
protected void openActivity(int position) {

/**
* We can set title & itemChecked here but as this BaseActivity is parent for other activity,
* So whenever any activity is going to launch this BaseActivity is also going to be called and
* it will reset this value because of initialization in onCreate method.
* So that we are setting this in child activity.  
*/
// mDrawerList.setItemChecked(position, true);
// setTitle(listArray[position]);
mDrawerLayout.closeDrawer(mDrawerList);
BaseActivity.position = position; //Setting currently selected position in this field so that it will be available in our child activities.

switch (position) {
case 0:
startActivity(new Intent(this, Item1Activity.class));
break;
case 1:
startActivity(new Intent(this, Item2Activity.class));
break;
case 2:
startActivity(new Intent(this, Item3Activity.class));
break;
case 3:
startActivity(new Intent(this, Item4Activity.class));
break;
case 4:
startActivity(new Intent(this, Item5Activity.class));
break;

default:
break;
}

Toast.makeText(this, "Selected Item Position::"+position, Toast.LENGTH_LONG).show();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {

getMenuInflater().inflate(R.menu.main, menu);
return super.onCreateOptionsMenu(menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {

// The action bar home/up action should open or close the drawer.
// ActionBarDrawerToggle will take care of this.
if (actionBarDrawerToggle.onOptionsItemSelected(item)) {
            return true;
        }

switch (item.getItemId()) {
case R.id.action_settings:
return true;

default:
return super.onOptionsItemSelected(item);
}
}

/* Called whenever we call invalidateOptionsMenu() */
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        // If the nav drawer is open, hide action items related to the content view
        boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
        menu.findItem(R.id.action_settings).setVisible(!drawerOpen);
        return super.onPrepareOptionsMenu(menu);
    }
 
    /* We can override onBackPressed method to toggle navigation drawer*/
@Override
public void onBackPressed() {
if(mDrawerLayout.isDrawerOpen(mDrawerList)){
mDrawerLayout.closeDrawer(mDrawerList);
}else {
mDrawerLayout.openDrawer(mDrawerList);
}
}
}

Item1Activity.java

package com.navigation.drawer.activity;

import android.os.Bundle;
import android.widget.ImageView;

/**
 * @author dipenp
 *
 */
public class Item1Activity extends BaseActivity {

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

              /**
*  We will not use setContentView in this activty 
*  Rather than we will use layout inflater to add view in FrameLayout of our base activity layout*/

/**
* Adding our layout to parent class frame layout.
*/
getLayoutInflater().inflate(R.layout.activity_main, frameLayout);

/**
* Setting title and itemChecked
*/
mDrawerList.setItemChecked(position, true);
setTitle(listArray[position]);

((ImageView)findViewById(R.id.image_view)).setBackgroundResource(R.drawable.image1);
}
}

Final view of our demo app:::



You can download demo code from below url:
https://drive.google.com/file/d/0B0mH97AUwQqhNUlxdmkwZ1JsNW8/edit?usp=sharing


------------------------------------------------------------------------------------------------------------
Attaching another demo example here as lots of visitors are getting confused how to add different layout on different activity and how to add icon on navigation list view. 
As well as added header on listview to make it little bit attractive.






You can download demo code from below url:



Saturday 23 August 2014

Android: Location Listener app

In this demo we are going to fetch device current location using:

  • LocationListener
  • NETWORK_PROVIDER or GPS_PROVIDER 

First of all we have to set "uses-permission" in manifest:


As we are using both (NETWORK_PROVIDER  and GPS_PROVIDER ) we have to set ACCESS_FINE_LOCATION permission in manifest.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />

First of all we will take user's input to update location , Here user can set how frequently user want to update its location.

According to Android documentation:
The minimum time interval for notifications, This field is only used as a hint to conserve power, and actual time between location updates may be greater or lesser than this value.

Now when user tries to get its current location, we have to check if location provider is enable or not.
If location provider is disable we can give user option to enable "Access to my location" from settings.


When user will enable "Access to my location" setting user will get back to our activity and user will see its current location, we are also changing background color of screen when "onLocationChanged" called.


About Code::::::::::::::

We have GpsLocator class which implements LocationListener.

LocationListener has following callback methods...

/* This method will be called when device location is changed.
Or according to MIN_TIME_BW_LOCATION_UPDATES parameter value.
Which we have set when application launch.
*/
       @Override
public void onLocationChanged(Location location) {

}

@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}

/*Called when gps enable
*/
@Override
public void onProviderEnabled(String provider) {
}

/*Called when gps disable
*/
@Override
public void onProviderDisabled(String provider) {
}


We have to register above LocationListner interace with LocationManager class.

locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, // Type of location provider it can be GPS_PROVIDER
MIN_TIME_BW_LOCATION_UPDATES, // Minimum time interval to update location
MIN_DISTANCE_CHANGE_FOR_LOCATION_UPDATES, // Minimum Distance to update location
this // Instance of LocationListner interface which we have implemented in this class
);

Andoid has provided demo code to check that currently fetched location is better than previous one or not.(Reference: http://developer.android.com/guide/topics/location/strategies.html). Which can be very helpful when we want to do some heavy operation on location changed or when our app functionality is depend on correct location.

You can download demo code from below URL:
https://drive.google.com/file/d/0B0mH97AUwQqheGJmbGN3UnF0Wlk/edit?usp=sharing



Saturday 9 August 2014

Android: CursorLoader with ListView and ContentObserver

This post will cover following topics:


  • LoaderManager
  • AsyncTaskLoader
  • SimpleCursorAdapter
  • ContentObserver
  • SqliteDatabase


We are going to use LoaderManager  with ListView for updating ListView data.
When user will add a new record in table it will automatically populate in list view. We are using ContentObserver for observing any changes in cursor value.

We will implement LoaderCallbacks<Cursor> which contain following method:

onCreateLoader(int id, Bundle args) : We will initialize our custom CursorLoaderDemo class which will load data in background for ListView.

onLoadFinished(Loader<Cursor> loader, Cursor c): When our CursorLoaderDemo  class will load data in background it will be return in this method. We are using this data to populate in ListView.

Also we are adding ContentObserver to this cursor so that when new data will be available for this cursor it will call onChange(boolean selfChange) method of this ContentObserver class. Where we can reload LoaderManager.

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor c) {
Log.e(TAG, ":::: onLoadFinished");

cursorAdapter.swapCursor(c);

/**
* Registering content observer for this cursor, When this cursor value will be change
* This will notify our loader to reload its data*/
CursorObserver cursorObserver = new CursorObserver(new Handler(), loader);
c.registerContentObserver(cursorObserver);
c.setNotificationUri(getContentResolver(), DatabaseHelper.URI_TABLE_USERS);
}

onLoaderReset(Loader<Cursor> loader): This method will be called when loader will reset, where we are removing adapter value.
----------------------------------------------------------------------------------------------------------

We have to create URI for our table to add it in ContentResolver

public static final Uri URI_TABLE_USERS = Uri.parse("sqlite://com.loader.demo/table/" + TABLE_USERS);

When we will Add, Update or Delete any record of this table we can use this URI to notify that data is changed in this table.
----------------------------------------------------------------------------------------------------------


You can download example from below url:

Saturday 2 August 2014

Android: Supporting multiple language(Localization) in android apps

We can support different language in our Android application using resources file.
I am adding here example for the same.

We are going to support English, Hindi & Marathi language in this demo for this we have to create separate resources folder for all the three language and we will put different resource file in this folder and then we can change application locale using below code :

public static void setLocale(Context context, String locale) {
Locale myLocale = new Locale(locale);
Resources res = context.getResources();
DisplayMetrics dm = res.getDisplayMetrics();
Configuration conf = res.getConfiguration();
conf.locale = myLocale;
res.updateConfiguration(conf, dm);
}

We have to add three different string resource folder (e.g values-hi, values-en, values-ma) with resource file string.xml. Now when we will change application locale, application will automatically choose appropriate resource folder for rendering it on application.

Similarly we can also use different image resources in our application for that we have to create different drawable folder (eg. drawable-hi, drawable-en, drawable-ma) now we can put different image with same name in this drawable resource.


You can download example from below url:
https://drive.google.com/file/d/0B0mH97AUwQqhM0t2RXdMb3QxVHc/edit?usp=sharing

Friday 1 August 2014

Android: XML Parsing with DOM Parser, SAX Parser & XMLPull Parser

Hey I am adding here another demo for parsing XML content:

We are going to parse xml content with:

  • DOM Parser
  • SAX Parser
  • XMLPullParser
We will fetch XML content from below url:

And XML content will be something like below xml:

<?xml version="1.0" encoding="UTF-8"?>
<COMPANY name="XYZ Soft Solution">
       <EMPLOYEE>
<FIRSTNAME>Rahul</FIRSTNAME>
<LASTNAME>Sharma</LASTNAME>
<EMAIL>rs@xyz.com</EMAIL>
<DESIGNATION>Soft Developer</DESIGNATION>
<ADDRESS>
<STREET>MG road</STREET>
<CITY>Pune</CITY>
<STATE>M.H</STATE>
<ZIPCODE>450001</ZIPCODE>
</ADDRESS>
</EMPLOYEE>
</COMPANY>



You can download demo app here:
https://drive.google.com/file/d/0B0mH97AUwQqhVER3c3EteWI0ZVE/edit?usp=sharing