Android View Basics: Coordinates,Margin,Padding,Dip,Px



In this post,I am going to go for the basics of Android Views like its co-ordinates,difference between margin and padding and what is dip and conversion from dip to px and vice versa. In order to proceed,let’s first get some understanding about Android device Screen Size and Screen Density. For these two terms, I will take help from Supporting Multiple Screens

  1. Screen Size: This is simply the width and height of the device rectangular screen. So,when we say 480×800 device,we are referring to the screen size whose width = 480 px and height =800 px


  2. 480x800 screen

  3. Screen density: It means how many pixels are present in a given area of the screen. Let’s say we have 1 square inch of area (i.e. width=1 inch and height =1 inch) on 480 x 800 screen size device. The number of pixels on that 1 square inch of area determines the density of pixels. If that 1 square inch of area holds more number of pixels,then that screen has high density. Meaning greater the number of pixels,the greater is its density and if lower the number of pixels,lower its density . Look at the picture below to understand the concept visually (taken from BBC site ). This indicates that 480×800 device can be ldpi,mdpi or hdpi as per its screen density . But, if screen size is large,then large pixels can be accommodated compared to small screen size devices.
  4. pixel-density-1


Let us know more about dip now.
dip: We all know that Android devices comes with different density and screen sizes. While giving View attributes like layout_width,layout_height,layout_margin,padding etc we use values with dip unit. So when we say android:layout_width=45dip and android:layout_height=45dip,we are drawing a view with 45 width and 45 height. The analogy which I am going to present is not accurate,but it helps in understanding dip concept. Say to draw 45 width line 45 pixels is needed.And if there was no dip ,then on higher density device the width seems smaller( as more pixels are found in a given area) but on lower density the width seems larger( as less pixels are found in a given area). Take a look at the picture below where there is not dip usage

View without dip consideration


Now when we use dip values,Android automatically takes screen density into consideration and then distributes the value as per the density, such that the view appears more or less similar in all the screens. Take a look at the picture below where there is dip usage.

View with dip consideration

Now comes the role of px.Whatever value in dip we represent,it has to be converted on actual screen unit or pixel. So px is the actual dimension that a view holds in screen. This conversion is handled by Android system. Meaning ,whatever we write in dip,it will convert those values to its relevant px unit,so that it could be drawn on the screen.For this,it takes the screen density into consideration.

If you write 5 dip,its pixel value will be different on different screen density.Using online dp to px calculator ,we get following px values for 5 dip on different screen densities
dp to px calculator


If you want to look upon the formula involved for dp to px conversion and vice versa ,you can look upon this conversion gist
Just check view.getWidth() or view.getHeight() ,it will give you different values than that, you have written on your layout.xml. Meaning,if you have given width and height as 45 dip on your layout.xml file,then calling view.getWidth() or view.getHeight() ,you will receive their respective px values.

Let’s now focus on to Android View Co-ordinates.In Android ,all the co-ordinates will be represented on px values. Android Screen as well as its view coordinates origin is (0,0) i.e. it starts from top left corner. Moving right from origin is positive X-axis and moving down from origin is positive Y-axis. Take a look upon the figure below

Screenshot from 2013-12-10 16:39:29

Screenshot from 2013-12-10 16:34:54


Let us take a following

 
   <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/firstLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <LinearLayout
        android:id="@+id/secondLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" 
        android:background="@color/color_yellow">

        <ImageView
            android:id="@+id/firstImageView"
            android:layout_width="48dip"
            android:layout_height="48dip"
            android:layout_margin="5dip"
            android:background="@android:color/darker_gray"
            android:padding="5dip"
            android:src="@drawable/ic_launcher" />

        <ImageView
            android:id="@+id/secondImageImageView"
            android:layout_width="48dip"
            android:layout_height="48dip"
            android:background="@android:color/black"
            android:src="@drawable/ic_launcher" />
    </LinearLayout>

    <ImageView
        android:id="@+id/thirdImageView"
        android:layout_width="48dip"
        android:layout_height="48dip"
        android:src="@drawable/ic_launcher"
        android:background="@android:color/black" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" 
        android:id="@+id/thirdLayout"
        android:background="@color/color_orange">

        <ImageView
            android:id="@+id/fourthImageView"
            android:layout_width="48dip"
            android:layout_height="48dip"
            android:src="@drawable/ic_launcher"
            android:background="@android:color/darker_gray" />

        <ImageView
            android:id="@+id/fifthImageView"
            android:layout_width="48dp"
            android:layout_height="48dip" 
            android:src="@drawable/ic_launcher"
            android:background="@android:color/black"/>
    </LinearLayout>
</LinearLayout>
  

I am making all the test on my Samsung Galaxy S I8262 device which has a screen size of 480×800 px and screen density of 240 dpi. So, the values which I illustrate on px is equivalent to this device only and you may yield different values of px on your devices. If you look upon the layout.xml,I have used mainly two dip values, 48dip and 5dip. The respective value of them in px is 48dip=72px and 5dip=8px. So ,let us now calculate,the co-ordinate of each of the views. For that we must understand these terms view.getLeft(),view.getRight(),view.getTop(),view.getBottom(). These values are always taken in reference to their parent i.e. how far to the left and bottom of the viewgroup/parent is the view lying.Look upon the figure below
Screenshot from 2013-12-11 17:33:45
Figure A
Screenshot from 2013-12-11 19:19:18
Figure B
Screenshot from 2013-12-12 14:16:28
Figure C
Looking at the figure above,following points can be gathered

1) getLeft() : distance between leftmost edge of parent and leftmost edge of view
2) getRight(): distance between leftmost edge of parent and rightmost edge of view
3) getTop(): distance between topmost edge of parent and topmost edge of view
4) getBottom(): distance between topmost edge of parent and bottom most edge of view
5) View position or location inside parent: (getLeft(),getTop())
6) view width = getRight()-getLeft()
7) view height = getBottom()-getTop()

Look at Figure B and note down firstLayout getRight() and getBottom() values. We have 480×800 px screen,and firstLayout is our main layout, which has the freedom to occupy whole screen(look upon layout.xml). Here getRight()=480px and getBottom=690px. firstLayout fills entire screen and its width value equals width of screen. But is height=690px-0px != 800px. I am not running this sample on fullscreen mode,so while launching the app,I will have status bar and ActionBar (if I am running on Android 3.0 and above or if I am using ActionbarSherlock). In my case,I have both status bar and ActionBar. These two views also take portion on screen and in my case I am using portrait mode ,where status bar height=38px and actionbarHeight=72px. So

firstLayout getBottom() = screenHeight()-(status bar height+action bar height)
=800 -(38+72)
=690px


Look at the following figure,to understand more.
Screenshot from 2013-12-12 17:04:48
But If I had run my app on fullScreen mode,then firstLayout height would have been 800px. For calculating status bar height and action bar height,you can refer to following gists
status bar height:
action bar height:

getLeft(),getTop() gives view's position inside parent/viewgroup co-ordinates. But If you want to get the position or location of view in the screen you have to use

 int[] xy = new int[2];
 view.getLocationOnScreen(xy);
 int xPosition =xy[0];
 int yPosition= xy[1];						

Screenshot from 2013-12-12 16:40:25
I hope,all the explanation gives you idea about Android View Co-ordinates .
Lastly, I want to briefly explain about Margin and Padding . Consider the following

  <LinearLayout
        android:id="@+id/secondLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" 
        android:background="@color/color_yellow">

        <ImageView
            android:id="@+id/firstImageView"
            android:layout_width="48dip"
            android:layout_height="48dip"
            android:layout_margin="15dip"
            android:background="@android:color/darker_gray"
            
            android:src="@drawable/ic_launcher" />

        <ImageView
            android:id="@+id/secondImageImageView"
            android:layout_width="48dip"
            android:layout_height="48dip"
            android:padding ="10dip"
            android:background="@android:color/black"
            android:src="@drawable/ic_launcher" />
    </LinearLayout>

which is visually seen as
Screenshot from 2013-12-12 17:22:38
Here both ImageView has width and height of 48 dip. firstImageView has layout margin=15dip and secondImageView has padding =10dip . By adding padding/margin , the view height and width remains same,there won’t be any change. While doing margin ,the view will be moved margin distance to left,right,top or bottom within parent view . So, while accessing view margin programmatically ,you have use view layoutParams . When we do padding, the view moves its content (in our case the ImageView src) to padding distance to left,right,top or bottom within the view itself. Maybe the pictorial representation,above would highlight this.
This is all,for now and if you are reading this,then probably you haven’t slept while reading this long blog list. The main reason,I wrote this post is that,I wanted to visually represent Android Co-ordinates and make understand basics of dip,px,margin,padding .
If you want to find out by yourself,the dimension represented on the figure(though value may differ as per screen density),you can play with this source at laaptu’s github.
Till next time have fun and enjoy ;)

How to check whether your push notification/GCM message receive logic on app is working or not



In this post,I am not trying to teach the basics of GCM/push notification.You can easily get started with GCM from Android GCM. This post is for those developers who have

  • Successfully registered their device to GCM server and received GCM phone registration id
  • Implemented the logic to receive notification from their server
  • and are relying on back end developers to send test notification message


Frankly speaking I am writing this post out of frustration of dealing with back end developers who simply say that app logic is not right but back end is error proof.And they constantly force us to check our code. So,in this case if any back end developer say that their process of sending push notification to app is right and you also feel that your logic is right,then simply test your logic with HTTP post request.For this purpose I am using a Chrome app named Dev Http Client,which is BTW great great tool for any app developer doing REST API.I assume you have done the following

  1. Created a Google Project on Google API console
  2. Activated Google Cloud Messaging for Android service on that project
  3. Created an API key for that project,so that Google API can be accessed using this key
  4. And all the procedures I have described in above list


Now carefully look upon the following images

01_notification_format

01_notification_msg


So,on above image you see that you have to put

  1. Google API console API key on header
  2. Phone registration id on body part
  3. On data you have to put what kind of message you want to pass
  4. Press Send button to send the push notification


You can see the message response on second picture i.e. what have been sent by Google GCM server. So,if you receive the notification using above procedure,your app logic is right otherwise you have to make some changes. Further,to simply check whether your GCM/push notification receive logic is working or not,you don’t have to rely on back end developers,you can do on your own.

If you have any questions on this,feel free to ask me on comments.Till then Happy KitKat (as KitKat along with Nexus 5 was released yesterday) ;)

Android update app widget with ListView after phone reboot



This tutorial is followup of previous tutorial of mine named Android Showing Remote Image on ImageView of App-Widget ListView. If you look upon the WidgetProvider.java class,I haven’t included any functional statement on onUpdate() method except super.onUpdate(context,appWidgetManager,appWidgetIds).


I have stated earlier that onUpdate() method is called on every update interval that is set on appwidget-provider xml file( in our case xml/widgetinfo.xml) and on every phone bootup. So, in our case as there is no functional statement on onUpdate() method, our widget will be blank after phone reboot or on phone start.If one includes,update logic on onUpdate() method of appwidget,then there is no need to care about phone reboot. But in our case we need to address phone reboot/start issue as our appwidget will be blank after phone reboot/start.


I will first point out the logic,I am going to implement on this tutorial

  1. Find out phone boot completion using BroadCastReceiver and listening to android.intent.action.BOOT_COMPLETED intent
  2. Then on appwidget provider simply update the appwidget
  3. I am just using a boolean value,but one can send custom broadcast to appwidget provider,notifying about phone boot completion and making necessary updates out there


Let’s create our BroadcastReceiver to listen to phone boot completed broadcast.

public class PhoneBootCompleteReceiver extends BroadcastReceiver {

	public static boolean wasPhoneBootSucessful = false;

	/**
	 * Just changing the boolean value on Phone Boot Complete event one can send
	 * custom broadcast from here as well send these broadcast of appwidget
	 * provider to make necessary updates
	 */
	@Override
	public void onReceive(Context context, Intent intent) {
		if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
			wasPhoneBootSucessful = true;
		}
	}
}


For this PhoneBootCompleteReceiver to work,one must include following on their manifest.xml file.

<!-- Permission to receive boot completed intent or broadcast -->
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<!-- Broadcast receiver that responds when phone successfully boots -->
        <receiver android:name=".PhoneBootCompleteReceiver" >
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>


Now moving on the our appwidgetprovide class i.e.WidgetProvider,following changes are to be made

	/*
	 * this method is called every 30 mins as specified on widgetinfo.xml this
	 * method is also called on every phone reboot so on phone reboot,we need to
	 * once again update the widget i.e populate the listview of the widget
	 */
	@Override
	public void onUpdate(Context context, AppWidgetManager appWidgetManager,
			int[] appWidgetIds) {

		if (PhoneBootCompleteReceiver.wasPhoneBootSucessful) {
			PhoneBootCompleteReceiver.wasPhoneBootSucessful = false;
			final int N = appWidgetIds.length;
			for (int i = 0; i < N; i++) {
				RemoteViews remoteViews = updateWidgetListView(context,
						appWidgetIds[i]);
				appWidgetManager.updateAppWidget(appWidgetIds[i], remoteViews);
			}
		}

		super.onUpdate(context, appWidgetManager, appWidgetIds);
	}


This is all one has to do, in order to update appwidget on phone startup. All these tutorials of AppWidget ListView is to show the basics of appwidget containing ListView,along with procedure to fill up data from remote or web.


One important thing I want to mention is that, while implementing own update interval i.e. not relying upon update interval set at appwidget-provider.xml,one has to use appWidgetManager.notifyAppWidgetViewDataChanged() instead of appWidgetManager.updateAppWidget(). This alone doesn’t change the data of the ListView.This process calls onDataSetChanged() of RemoteViewsFactory. So at onDataSetChanged,you have to again fetch data that is supplied to RemoteViewsFactory. Then only,the changed data is reflected upon appwidget ListView.


Finally,you can download the whole source code from my github. Till next time,enjoy coding ;)

Android Setting Update Interval On Appwidget With Listview



My initial plan was to set an update interval for appwidget which I have developed through my previous series of tutorials

  1. Android app widget with ListView
  2. Populate AppWidget ListView with remote data(data from web)
  3. Android Showing Remote Image on ImageView of App-Widget ListView

Truly speaking,I got the idea of using update interval on appwidget following malubu’s blog. This blog entry about widget update interval, from my point of view is one of the best guide available on the web right now. So ,if I am going to write about update interval for my listview appwidget ,I will be basically writing the same stuff. So,referencing malubu’s blog will be the best where you can go and find out the concept behind setting update interval for any appwidget . Finally I want to thank Luong for this awesome tutorial.
Finally check out Luong’s github to access the entire source code

Android Showing Remote Image on ImageView of App-Widget ListView


This is followup tutorial of my previous tutorials on Android AppWidget ListView.

  1. Android app widget with ListView
  2. Populate AppWidget ListView with remote data(data from web)


In this part of tutorial,I am going to explain on how to download images from server and show those images on Android AppWidget ListView's ImageView. As I stated earlier on my AppWidget ListView tutorial,it is better to use Database rather than static ArrayList. So ,here first of all I am going to implement a Database,where I will store all the data fetched from the web. Before going down to code, I will explain the logic that will be implemented in this tutorial.

  1. First fetch the content of json file
  2. Save the fetched content into database
  3. Download images from web
  4. Save the image Bitmap on file
  5. Populate appwidget listview with data from Database and image from File


Let’s first create our Database which holds content,heading,image url of our remote json file. Further,this Database of ours will also hold the file path where our images will be saved.Let’s create SQListOpenHelper class which will define our Database and table structure. Let’s name it

public class DatabaseHelper extends SQLiteOpenHelper {

	public static final String WIDGET_TABLE = "widgetContentTable",
			WIDGET_ID = "widgetId", HEADING = "heading", CONTENT = "content",
			IMAGE_REMOTE_URL = "imageUrl", IMAGE_FILE_URL = "fileUrl";
	public static final int DB_VERSION = 1;
	public static final String DB_NAME = "listViewWidgetDB";

	public static final String CREATE_TABLE_QUERY = "create table if not exists "
			+ WIDGET_TABLE
			+ " (_id integer primary key autoincrement,"
			+ WIDGET_ID
			+ " text, "
			+ HEADING
			+ " text, "
			+ CONTENT
			+ " text, "
			+ IMAGE_REMOTE_URL + " text," + IMAGE_FILE_URL + " text);";

	public DatabaseHelper(Context context) {
		super(context, DB_NAME, null, DB_VERSION);
	}

	@Override
	public void onCreate(SQLiteDatabase db) {
		db.execSQL(CREATE_TABLE_QUERY);
	}

	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		db.execSQL("drop table if exists " + WIDGET_TABLE);
		onCreate(db);
	}

}


The DatabaseHelper class is pretty self-explanatory to those who have already worked on Android SQLite. Moving on,let’s create a class which manages actions like adding,retrieving,updating database record and let’s name it

/**
 * A singleton class of manage all the Database related work
 */
public enum DatabaseManager {
	INSTANCE;

	private SQLiteDatabase db;
	private boolean isDbClosed = true;

	/**
	 * Initializng SQListDatabase with help of our SQLiteOpenHelper class
	 * DatabaseHelper
	 */
	public void init(Context context) {
		if (context != null && isDbClosed) {
			isDbClosed = false;
			DatabaseHelper dbHelper = new DatabaseHelper(context);
			db = dbHelper.getWritableDatabase();
		}

	}

	/**
	 * Closing already opened writable database
	 */
	public void closeDatabase() {
		if (!isDbClosed && db != null) {
			isDbClosed = true;
			db.close();
		}
	}

	/**
	 * Knowing the opened or closed state of writable database
	 */
	public boolean isDbClosed() {
		return isDbClosed;
	}

	/**
	 * Storing the fetched and parsed content of Json file on database
	 */
	public void storeListItems(int widgetId, ArrayList<ListItem> listItems) {
		String widgetIdValue = Integer.toString(widgetId);
		db.delete(DatabaseHelper.WIDGET_TABLE, DatabaseHelper.WIDGET_ID + "=?",
				new String[] { widgetIdValue });
		for (ListItem listItem : listItems) {
			ContentValues cv = new ContentValues();
			cv.put(DatabaseHelper.WIDGET_ID, widgetIdValue);
			cv.put(DatabaseHelper.HEADING, listItem.heading);
			cv.put(DatabaseHelper.CONTENT, listItem.content);
			cv.put(DatabaseHelper.IMAGE_REMOTE_URL, listItem.imageUrl);
			Log.i("listtem image url @ databaseManger", listItem.imageUrl);
			db.insert(DatabaseHelper.WIDGET_TABLE, null, cv);
		}
	}

	/**
	 * 
	 * Fetching the stored items with given widget id
	 */
	public ArrayList<ListItem> getStoredListItems(int widgetId) {
		String widgetIdValue = Integer.toString(widgetId);
		Cursor cursor = db.query(DatabaseHelper.WIDGET_TABLE, null,
				DatabaseHelper.WIDGET_ID + "=?",
				new String[] { widgetIdValue }, null, null, null);
		ArrayList<ListItem> listItems = new ArrayList<ListItem>();
		while (cursor.moveToNext()) {
			ListItem listItem = new ListItem();
			listItem.heading = cursor.getString(cursor
					.getColumnIndex(DatabaseHelper.HEADING));
			listItem.content = cursor.getString(cursor
					.getColumnIndex(DatabaseHelper.CONTENT));
			listItem.imageUrl = cursor.getString(cursor
					.getColumnIndex(DatabaseHelper.IMAGE_REMOTE_URL));
			listItem.fileUrl = cursor.getString(cursor
					.getColumnIndex(DatabaseHelper.IMAGE_FILE_URL));
			listItems.add(listItem);
		}

		cursor.close();
		return listItems.size() == 0 ? null : listItems;
	}

	/**
	 * Once Image have been downloaded and saved on file then update the file
	 * path of saved image to database row
	 * 
	 */
	public boolean updateImageFilePath(int widgetId, String filePath,
			String heading) {
		ContentValues cv = new ContentValues();
		cv.put(DatabaseHelper.IMAGE_FILE_URL, filePath);
		return db.update(DatabaseHelper.WIDGET_TABLE, cv,
				DatabaseHelper.WIDGET_ID + "=? and " + DatabaseHelper.HEADING
						+ "=?", new String[] { Integer.toString(widgetId),
						heading }) > 0;
	}
}


Moving on,we need to create a class which handles file writing operation i.e. using the Bitmap of downloaded images and converting them or writing them to jpeg images. This class is

/**
 * A singleton class to manage file operation
 */
public enum FileManager {
    INSTANCE;
    
	String directoryName = Environment.getExternalStorageDirectory()
			+ "/appwidgetlistview/";

    /**
     * creating a file or initializing a file
     * here I haven't checked sdcard availability
     * so while doing any file operation,better to check
     * sdcard state first
     */
    public void init(String fileName){
    	File file = new File(directoryName+fileName+"/");
    	if(!file.exists())
    		file.mkdirs();
    }
    
    /**
     * Making a jpeg file with downloaded bitmap
     * and giving the database the image path to be updated on
     * its equivalent record
     */
    public void storeBitmap(int appWidgetId,Bitmap bitmap,String heading,Context context){
    	init(Integer.toString(appWidgetId));
    	String fileName = directoryName+Integer.toString(appWidgetId)+"/"+heading+".jpg";
    	try {
			FileOutputStream fileOutputStream =new FileOutputStream(fileName);
			bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fileOutputStream);
			fileOutputStream.close();
			fileOutputStream.flush();
			DatabaseManager dbManager = DatabaseManager.INSTANCE;
			dbManager.init(context);
			dbManager.updateImageFilePath(appWidgetId, fileName, heading);
    	} catch (FileNotFoundException e) {
			e.printStackTrace();
		}catch(Exception e){
			e.printStackTrace();
		}
    }
}


FileManager not only saves images on file but also updates the database record with the saved image path. Now we need to modify our RemoteService.java class to accommodate function like storing json content to database,downloading images and saving them to file. I will just point out the added portion on the code

	/**
	 * Json parsing of result and populating ArrayList<ListItem> as per json
	 * data retrieved from the string
	 */
	private void processResult(String result) {
		Log.i("Resutl", result);
		listItemList = new ArrayList<ListItem>();
		try {
			JSONArray jsonArray = new JSONArray(result);
			int length = jsonArray.length();
			for (int i = 0; i < length; i++) {
				JSONObject jsonObject = jsonArray.getJSONObject(i);
				ListItem listItem = new ListItem();
				listItem.heading = jsonObject.getString("heading");
				listItem.content = jsonObject.getString("content");
				listItem.imageUrl = jsonObject.getString("imageUrl");
				listItemList.add(listItem);
			}
			storeListItem();

		} catch (JSONException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Instead of using static ArrayList as we have used before,no we rely upon
	 * data stored on database so saving the fetched json file content into
	 * database and at same time downloading the image from web as well
	 */
	private void storeListItem() {
		DatabaseManager dbManager = DatabaseManager.INSTANCE;
		dbManager.init(getBaseContext());
		dbManager.storeListItems(appWidgetId, listItemList);

		int length = listItemList.size();
		for (int i = 0; i < length; i++) {
			ListItem listItem = listItemList.get(i);
			final int index = i;
			aquery.ajax(listItem.imageUrl, Bitmap.class,
					new AjaxCallback<Bitmap>() {
						@Override
						public void callback(String url, Bitmap bitmap,
								AjaxStatus status) {
							super.callback(url, bitmap, status);
							storeBitmap(index, bitmap);
						};
					});
		}
	}

	/**
	 * Saving the downloaded images into file and after all the download of
	 * images be complete begin to populate widget as done previously
	 */
	private void storeBitmap(int index, Bitmap bitmap) {
		FileManager.INSTANCE.storeBitmap(appWidgetId, bitmap,
				listItemList.get(index).heading, getBaseContext());
		count++;
		Log.i("count",
				String.valueOf(count) + "::"
						+ Integer.toString(listItemList.size()));
		if (count == listItemList.size()) {
			count = 0;
			populateWidget();
		}

	}


All above procedure is done to save content on database and file. Now, instead of using static ArrayList as we had done previously,we will fetch the content from database and update or populate the appwidget listview with those contents.We need to modify our WidgetService.java and ListProvider.java classes a little. On our WidgetService class,we fetch the data from database and supply those data to our ListProvider class.

public class WidgetService extends RemoteViewsService {
	/*
	 * So pretty simple just defining the Adapter of the listview here Adapter
	 * is ListProvider and fetching the stored data from Database and providing
	 * it to ListProvider
	 */

	@Override
	public RemoteViewsFactory onGetViewFactory(Intent intent) {
		int appWidgetId = intent.getIntExtra(
				AppWidgetManager.EXTRA_APPWIDGET_ID,
				AppWidgetManager.INVALID_APPWIDGET_ID);
		DatabaseManager dbManager = DatabaseManager.INSTANCE;
		dbManager.init(getBaseContext());
		return (new ListProvider(this.getApplicationContext(), intent,
				dbManager.getStoredListItems(appWidgetId)));
	}

}


And moving on to ListProvider class,we simply use the imagepath to show images on ImageView of appwidget listview .

public ListProvider(Context context, Intent intent,
			ArrayList<ListItem> listItems) {
		this.context = context;
		appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
				AppWidgetManager.INVALID_APPWIDGET_ID);
		if (listItems != null)
			this.listItemList = (ArrayList<ListItem>) listItems.clone();
	}
/*
	 * Similar to getView of Adapter where instead of View return RemoteViews
	 * And using the saved ImagePath to show images on ImageView
	 */
	@Override
	public RemoteViews getViewAt(int position) {
		final RemoteViews remoteView = new RemoteViews(
				context.getPackageName(), R.layout.list_row);
		ListItem listItem = listItemList.get(position);
		remoteView.setTextViewText(R.id.heading, listItem.heading);
		remoteView.setTextViewText(R.id.content, listItem.content);
		Bitmap bitmap = BitmapFactory.decodeFile(listItem.fileUrl);
		if (bitmap != null)
			remoteView.setImageViewBitmap(R.id.imageView, bitmap);

		return remoteView;
	}


This is all one have to do in order to show downloaded images on appwidget listview's imageview.Further this tutorial is just a barebone implementation on how to download content(images or other) and populate them on appwidget listview. There may be better ways to do also and if anyone has done so in efficient manner please share us also.
Finally all the source code can be downloaded from my github. Till next time,enjoy life.

Populate AppWidget ListView with remote data(data from web)



This tutorial is follow up of previous tutorial AppWidget With ListView. In this tutorial,we will just populate the AppWidget ListView with data downloaded from web. For this purpose we are using

  1. Json Data
  2. AQuery


AQuery is an awesome library to work out with remote data be it simple json files,xml files or images,bitmaps to name a few. Go to AQuery to know more about this library. Now let us create a appwidget configuration activity. This appwidget configuration Activty is the Activity which gets launched when appwidget is placed on homescreen i.e. when appwidget is selected from widgets of phone and drag and dropped to homescreen. For any appwidget configuration activity to work it must be declared on

  1. AndroidManifest.xml file with intent action android.appwidget.action.APPWIDGET_CONFIGURE
  2. <!-- Configuration activity which gets 
         launched  on widget being placed on
         homescreen for first time  -->
    <activity android:name=".ConfigActivity" >
    <!-- This intent is required to be recognized
         this activity as appwidget configuration activity -->
       <intent-filter>
           <action android:name=
               "android.appwidget.action.APPWIDGET_CONFIGURE" />
       </intent-filter>
    </activity>
    
  3. And be mentioned on appwidget-provider xml file @res/xml/widgetinfo.xml on attribute android:configure
    <?xml version="1.0" encoding="utf-8"?>
    <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
      android:configure="com.wordpress.laaptu.ConfigActivity"
      android:initialLayout="@layout/widget_layout"
      android:minHeight="110dip"
      android:minWidth="250dip"
      android:previewImage="@drawable/widget_preview"
      android:resizeMode="vertical|horizontal"  
      android:updatePeriodMillis="1800000" />
    


Now let us fill up our ConfigActivity. This Activity is launched once AppWidget is placed and it contains simply a Button. Upon click of ConfigActivity's Button, AppWidget is launched along with a Service is started to fetch our json data.

public class ConfigActivity extends Activity implements OnClickListener {

	private int appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;

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

		assignAppWidgetId();
		findViewById(R.id.widgetStartButton).setOnClickListener(this);
	}

	/**
	 * Widget configuration activity,always receives appwidget Id appWidget Id =
	 * unique id that identifies your widget analogy : same as setting view id
	 * via @+id/viewname on layout but appwidget id is assigned by the system
	 * itself
	 */
	private void assignAppWidgetId() {
		Bundle extras = getIntent().getExtras();
		if (extras != null)
			appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,
					AppWidgetManager.INVALID_APPWIDGET_ID);
	}

	@Override
	public void onClick(View v) {
		if (v.getId() == R.id.widgetStartButton)
			startWidget();
	}

	/**
	 * This method right now displays the widget and starts a Service to fetch
	 * remote data from Server
	 */
	private void startWidget() {

		// this intent is essential to show the widget
		// if this intent is not included,you can't show
		// widget on homescreen
		Intent intent = new Intent();
		intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
		setResult(Activity.RESULT_OK, intent);

		// start your service
		// to fetch data from web
		Intent serviceIntent = new Intent(this, RemoteFetchService.class);
		serviceIntent
				.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
		startService(serviceIntent);

		// finish this activity
		this.finish();

	}

}


Read out the comments on ConfigActivity to know about its working. Now let’s create our Service whose main task is to

  • Fetch data from web
  • Populate AppWidget ListView with fetched data

An AppWidgetProvider is basically a BroadCastReciever,so whenever one needs to communicate to AppWidgetProvider,one must send broadcast from activity,service with necessary action string. And this is the pattern on which AppWidgetProvider works.Though this is not compulsory,try to create RemoteViews on AppWidgetProvider and call update from within AppWidgetProvider.
Let’s go through this one by one. First let’s create our remote data fetch service and name it as

public class RemoteFetchService extends Service {

	private int appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
	private AQuery aquery;
	private String remoteJsonUrl = "http://laaptu.files.wordpress.com/2013/07/widgetlist.key";

	public static ArrayList<ListItem> listItemList;

	@Override
	public IBinder onBind(Intent arg0) {
		return null;
	}

	/**
	 * Retrieve appwidget id from intent it is needed to update widget later
	 * initialize our AQuery class
	 */
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		if (intent.hasExtra(AppWidgetManager.EXTRA_APPWIDGET_ID))
			appWidgetId = intent.getIntExtra(
					AppWidgetManager.EXTRA_APPWIDGET_ID,
					AppWidgetManager.INVALID_APPWIDGET_ID);
		aquery = new AQuery(getBaseContext());
		fetchDataFromWeb();
		return super.onStartCommand(intent, flags, startId);
	}

	/**
	 * method which fetches data(json) from web aquery takes params
	 * remoteJsonUrl = from where data to be fetched String.class = return
	 * format of data once fetched i.e. in which format the fetched data be
	 * returned AjaxCallback = class to notify with data once it is fetched
	 */
	private void fetchDataFromWeb() {
		aquery.ajax(remoteJsonUrl, String.class, new AjaxCallback<String>() {
			@Override
			public void callback(String url, String result, AjaxStatus status) {
				processResult(result);
				super.callback(url, result, status);
			}
		});
	}

	/**
	 * Json parsing of result and populating ArrayList<ListItem> as per json
	 * data retrieved from the string
	 */
	private void processResult(String result) {
		listItemList = new ArrayList<ListItem>();
		try {
			JSONArray jsonArray = new JSONArray(result);
			int length = jsonArray.length();
			for (int i = 0; i < length; i++) {
				JSONObject jsonObject = jsonArray.getJSONObject(i);
				ListItem listItem = new ListItem();
				listItem.heading = jsonObject.getString("heading");
				listItem.content = jsonObject.getString("content");
				listItem.imageUrl = jsonObject.getString("imageUrl");
				listItemList.add(listItem);
			}

		} catch (JSONException e) {
			e.printStackTrace();
		}
		populateWidget();
	}

	/**
	 * Method which sends broadcast to WidgetProvider
	 * so that widget is notified to do necessary action
	 * and here action == WidgetProvider.DATA_FETCHED
	 */
	private void populateWidget() {

		Intent widgetUpdateIntent = new Intent();
		widgetUpdateIntent.setAction(WidgetProvider.DATA_FETCHED);
		widgetUpdateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
				appWidgetId);
		sendBroadcast(widgetUpdateIntent);

		this.stopSelf();
	}
}


Look upon method populateWidget(),where I have created a broadcast with action WidgetProvider.DATA_FETCHED which is a simple string

public static final String DATA_FETCHED="com.wordpress.laaptu.DATA_FETCHED";

For this broadcast to be received by our AppWidgetProvider named WidgetProvider.java,this action string must be included on intent-filter action at AndroidManifest.xml

 <receiver android:name=".WidgetProvider" >
    <intent-filter>
       <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
       <!-- To receive broadcast with this string name -->
       <action android:name="com.wordpress.laaptu.DATA_FETCHED" />
     </intent-filter>
        <meta-data
           android:name="android.appwidget.provider"
            android:resource="@xml/widgetinfo" />
     </receiver>

Now let us modify our WidgetProvider.java to reflect the changes. Previously ,all the updates of widget were handled on onUpdate() method.But from now on onUpdate() will just start RemoteFetchService i.e. on every 30 min interval,to fetch new data RemoteFetchService will be called to fetch data from web and notify WidgetProvider with broadcast. Just like any BroadCastReceiver, WidgetProvider onReceive() method will receive the sent broadcast. And we just find out the broadcast action and carry out necessary updates through AppWidgetManger. Check out our modified WidgetProvider.java to know more

public class WidgetProvider extends AppWidgetProvider {

	// String to be sent on Broadcast as soon as Data is Fetched
	// should be included on WidgetProvider manifest intent action
	// to be recognized by this WidgetProvider to receive broadcast
	public static final String DATA_FETCHED = "com.wordpress.laaptu.DATA_FETCHED";

	/**
	 * this method is called every 30 mins as specified on widgetinfo.xml this
	 * method is also called on every phone reboot from this method nothing is
	 * updated right now but instead RetmoteFetchService class is called this
	 * service will fetch data,and send broadcast to WidgetProvider this
	 * broadcast will be received by WidgetProvider onReceive which in turn
	 * updates the widget
	 */
	@Override
	public void onUpdate(Context context, AppWidgetManager appWidgetManager,
			int[] appWidgetIds) {
		final int N = appWidgetIds.length;
		for (int i = 0; i < N; i++) {
			Intent serviceIntent = new Intent(context, RemoteFetchService.class);
			serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
					appWidgetIds[i]);
			context.startService(serviceIntent);
		}
		super.onUpdate(context, appWidgetManager, appWidgetIds);
	}

	private RemoteViews updateWidgetListView(Context context, int appWidgetId) {

		// which layout to show on widget
		RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
				R.layout.widget_layout);

		// RemoteViews Service needed to provide adapter for ListView
		Intent svcIntent = new Intent(context, WidgetService.class);
		// passing app widget id to that RemoteViews Service
		svcIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
		// setting a unique Uri to the intent
		// don't know its purpose to me right now
		svcIntent.setData(Uri.parse(svcIntent.toUri(Intent.URI_INTENT_SCHEME)));
		// setting adapter to listview of the widget
		remoteViews.setRemoteAdapter(appWidgetId, R.id.listViewWidget,
				svcIntent);
		// setting an empty view in case of no data
		remoteViews.setEmptyView(R.id.listViewWidget, R.id.empty_view);
		return remoteViews;
	}

	/**
	 * It receives the broadcast as per the action set on intent filters on
	 * Manifest.xml once data is fetched from RemotePostService,it sends
	 * broadcast and WidgetProvider notifies to change the data the data change
	 * right now happens on ListProvider as it takes RemoteFetchService
	 * listItemList as data
	 */
	@Override
	public void onReceive(Context context, Intent intent) {
		super.onReceive(context, intent);
		if (intent.getAction().equals(DATA_FETCHED)) {
			int appWidgetId = intent.getIntExtra(
					AppWidgetManager.EXTRA_APPWIDGET_ID,
					AppWidgetManager.INVALID_APPWIDGET_ID);
			AppWidgetManager appWidgetManager = AppWidgetManager
					.getInstance(context);
			RemoteViews remoteViews = updateWidgetListView(context, appWidgetId);
			appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
		}

	}


Finally the updated data is now referenced from ListProvider.java class,which just clones the ArrayList of RemoteFetchService class as

private void populateListItem() {
  listItemList = (ArrayList<ListItem>)
                 RemoteFetchService.listItemList
				.clone();
}


In this manner the fetched data from the web is now received ListProvider which in turn is reflected on our AppWidget. This approach of using public static ArrayList has a major flaw. When they are more than 2 AppWidgets and they at the same time fetch and begin to modify public static ArrayList of RemoteFetchService,then the last modified value will be taken by both the AppWidget which is incorrect for one of the widget. So,in order to resolve this,better use Database to store values with given AppWidget Id. And on RemoteViewsService or on RemoteViewsFactory,simply fetch the data from Database with that AppWidget Id.
I have put the entire project My Github. Till next time, enjoy life.

Android app widget with ListView


Finally I got a taste of App Widget while doing a recent project.So, I am going to publish a series of tutorial on App Widget which may include

  1. app widget with listview
  2. populate app widget listview with data from web
  3. download images and show on imageview of appwidget with listview
  4. setting update interval on appwidget with listview
  5. how to make appwidget update work after phone reboot

Let’s first dive into basics of App Widget.
1: AppWidgetProvider
This is governing body of App Widget. Meaning everything of App Widget is controlled from here. By control means

  • Widget Update
  • Widget Delete
  • Widget enabled/disabled

to name a few.
2: Xml file for AppWidgetProvider:
Let’s make it an analogy like Activity has Layout.xml file,App Widget has appwidget-provider xml file @res/xml So every AppWidget must have these two building blocks. Let’s look upon Xml file for AppWidgetProvider and name it widgetinfo.xml

<?xml version="1.0" encoding="utf-8"?>
<!--Activity to be launched,when you first install widget(drag n drop widget to homescreen) we will ignore this now -->
android:configure="com.wordpress.laaptu.ConfigActivity"

<!-- the layout of the widget,just like setContentView(id) of Activity-->
android:initialLayout="@layout/widget_layout"

<!-- Minimum width and height of the widget -->
android:minHeight="110dip"
android:minWidth="250dip"

<!-- Image to be seen when you go to select a widget -->
android:previewImage="@drawable/widget_preview"

<!-- How to resize the widget -->
android:resizeMode="vertical|horizontal"

<!-- Update interval i.e. @ this interval WidgetProvider onUpdate method will be called -->
<!-- Default is 30 min,you can set lower value,but it will take 30 min ,but it takes higher value than 30 min-->
<!-- 30 min =30x60x1000 -->
android:updatePeriodMillis="1800000"/>





For widget to be recognized,you must set it on AndroidManifest.xml just like you set Activity,in following manner

 <receiver android:name=".WidgetProvider" >
            <intent-filter>

            <!-- This widget provider receives broadcast with following action 
name or simply onUpdate of AppWidgetProvider is called -->
            <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>
            <!-- linking up xml file of appwidget-provider to AppWidgetProvider -->
            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/widgetinfo" />
        </receiver>

Now let us create a layout.xml file for our appwidget and let’s name it widget_layout.xml @ res/layout which contains ListView

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="@android:color/black" >

    <!-- ListView to be shown on widget -->
    <ListView
        android:id="@+id/listViewWidget"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <!-- Empty view is show if list items are empty -->
    <TextView
        android:id="@+id/empty_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="@string/empty_string"
        android:textColor="#ffffff"
        android:textSize="20sp"
        android:visibility="gone" />

</LinearLayout>

Now,in order for ListView to be populated,we need few more classes

  1. RemoteViewsService
  2. RemoteViewsFactory

1:RemoteViewsService:
Just consider this class as the class which tells the ListView of appwidget to take what type of data. By data meaning what RemoteViewsFactory.To make it more simple,if you have done ListView population,this class defines the Adapter for the ListView.Let us name RemoteViewsService as WidgetService.java

public class WidgetService extends RemoteViewsService {
/*
* So pretty simple just defining the Adapter of the listview
* here Adapter is ListProvider
* */

@Override
public RemoteViewsFactory onGetViewFactory(Intent intent) {
int appWidgetId = intent.getIntExtra(
AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);

return (new ListProvider(this.getApplicationContext(), intent));
}

}



2:RemoteViewsFactory:
If you have done ListView population,this class is the Adpater of ListView. Let us name our RemoteViewsFactory as

/**
* If you are familiar with Adapter of ListView,this is the same as adapter
* with few changes
*
*/
public class ListProvider implements RemoteViewsFactory {
private ArrayList listItemList = new ArrayList();
private Context context = null;
private int appWidgetId;

public ListProvider(Context context, Intent intent) {
this.context = context;
appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);

populateListItem();
}

private void populateListItem() {
for (int i = 0; i &lt; 10; i++) {
ListItem listItem = new ListItem();
listItem.heading = "Heading" + i;
listItem.content = i
+ " This is the content of the app widget listview.Nice content though";
listItemList.add(listItem);
}

}

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

@Override
public long getItemId(int position) {
return position;
}

/*
*Similar to getView of Adapter where instead of View
*we return RemoteViews
*
*/
@Override
public RemoteViews getViewAt(int position) {
final RemoteViews remoteView = new RemoteViews(
context.getPackageName(), R.layout.list_row);
ListItem listItem = listItemList.get(position);
remoteView.setTextViewText(R.id.heading, listItem.heading);
remoteView.setTextViewText(R.id.content, listItem.content);

return remoteView;
}
}

Now let us go to governing body of widget i.e. AppWidgetProvider

public class WidgetProvider extends AppWidgetProvider {

/**
* this method is called every 30 mins as specified on widgetinfo.xml
* this method is also called on every phone reboot
**/

@Override
public void onUpdate(Context context, AppWidgetManager 
                appWidgetManager,int[] appWidgetIds) {

/*int[] appWidgetIds holds ids of multiple instance 
 * of your widget
 * meaning you are placing more than one widgets on 
 * your homescreen*/
 final int N = appWidgetIds.length;
 for (int i = 0; i &lt; N; ++i) {
     RemoteViews remoteViews = updateWidgetListView(context,
                                           appWidgetIds[i]);
     appWidgetManager.updateAppWidget(appWidgetIds[i], 
                                           remoteViews);
    }
 super.onUpdate(context, appWidgetManager, appWidgetIds);
}

private RemoteViews updateWidgetListView(Context context,
                                     int appWidgetId) {

   //which layout to show on widget
   RemoteViews remoteViews = new RemoteViews(
         context.getPackageName(),R.layout.widget_layout);

  //RemoteViews Service needed to provide adapter for ListView
  Intent svcIntent = new Intent(context, WidgetService.class);
  //passing app widget id to that RemoteViews Service
  svcIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
  //setting a unique Uri to the intent
  //don't know its purpose to me right now
  svcIntent.setData(Uri.parse(
                    svcIntent.toUri(Intent.URI_INTENT_SCHEME)));
  //setting adapter to listview of the widget
  remoteViews.setRemoteAdapter(appWidgetId, R.id.listViewWidget,
                                svcIntent);
  //setting an empty view in case of no data
  remoteViews.setEmptyView(R.id.listViewWidget, R.id.empty_view);
  return remoteViews;
 }

}


I have put comments on the code to let you understand different aspect of the AppWidgetProvider. Lastly,to make the AppWidget ListView to use Adapter,on must define RemoteViewsService on AndroidManifest.xml as well.

 <service
   android:name=".WidgetService"
   android:permission="android.permission.BIND_REMOTEVIEWS" />

This is all,to show an AppWidget with ListView on it. You can checkout My Github to download all the codes of this tutorial. On next tutorial,I will show how to populate app widget listview from remote data(i.e from web). Till then Happy Coding

Cancelling Aquery Ajax request



In our ongoing project we are heavily relying on network calls i.e. fetching data from the server and posting data to the server.Previously,we used AsyncTask and right now we found an awesome open source library named Aquery. This library is equipped with large set of functionality like image loading from server,using HTTP POST and GET,easy XML parsing with Aquery implemented XmlDom, easy object mapping to server response and many others. Moreover, this library is very easy to use and implement and kudos to all developer of Aquery for making such an useful and powerful class.
While using Aquery we needed to perform cancel to any server request via user button click action.But, first lets start with small Aquery demo

private Aquery aquery;
private String remoteUrl ="some remote url where you fetch some data";
protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      aquery = new Aquery(this);
      //Aquery lets you define what type of class you are expecting as server request response like String,JSON,XML 
     //We are dealing with String class in this example
     //All the result is received via AjaxCallback class  callback() method,where you can do necessary operation
     aquery.ajax(remoteUrl,String.class,new AjaxCallback<String>(){
         @Override
        public void callback(String url, String result, AjaxStatus status) {
          //do your processing with server response
          processInformation(result);
        }
    });
}



My previous implementation on cancelling Aquery was outdated. So it wasn’t working anymore. Then a fellow developer named ariellopezf
had found the correct way to cancel Aquery of recent version. Though,I haven’t tested myself,I am completely relying on ariellopezf words and giving his solution of properly cancelling Aquery. See the comment’s of this post to know more about ariellopezf


 private AjaxCallback<String> ajaxCallback = new AjaxCallback<String>(){
    	@Override
    	public void callback(String url, String object, AjaxStatus status) {
    		   //do your processing with server response
                   processInformation(result);
    	};
    };
   //on our previous code
   query.ajax(remoteUrl,String.class,ajaxCallback);

   public void cancelAquery(){
      //this statement does cancel the request i.e. we won't receive any information on callback method
     //ajaxCallback.async(null);  
     
     ajaxCallback.abort();
}



This is all needed to cancel Aquery ajax request. And Aquery is very useful library to be used ,if app needs to communicate to server frequently and I urge every Android Developer to use it. I believe that someday Aquery will pave its usage to Android Framework
Till then enjoy coding,enjoy blogging ;)

Android effectively communicating between Fragments and Activities to avoid null pointer exception errors



Recently we uploaded a new project named Facebook Scheduler which allows the user to schedule wall post messages to his/her own timeline or to his/her friends’ and groups timeline.Here we relied heavily on android compatibility library,Fragment,FragmentAdapter,FragementActivity.

We used android compatibility library ,looking upon the examples provided and we didn’t go deep into it. And all the problem started right from there. After lots of null pointer exception and force closes ,we finally figured out how to communicate between Activity(Fragment Activity) and Fragment. So before diving into solution ,I would like you to explain in brief simple life cycle of Fragment

fragment view


A Fragment is always dependent on FragmentActivity and it always rests or to say lives on FragmentActivity . So life cycle of Fragment depends upon the life cycle of FragmentActivity . Let’s now explain those portion of fragments life cycle that is important in this context

onAttach():
This signifies that the Activity has attached fragment on it and it doesn’t mean that all the views of Activity are created not it means that Activity is fully functional. This is just a point where you can reference the activity

onCreate():
Just a point which shows that Fragment is in the process of creation and in this method just try to access those values that you have saved on onSavedInstanceState(Bundle outState)

onCreateView():
Here we inflate the layout or simply create the view and further if you have to do anything that takes reference to Activity don’t do it like creating dialogs,accessing views of Activity etc because,this place doesn’t ensure that hosting Activity is fully functional

onActivityCreated():
This place signifies that our hosting Activity views are created and hosting Activity is functional and this is the right place to do all your Activity related task.

onResume():
This is the place where I prefer to do all the actions of the fragment



Now moving away from theory lets create a means of communication between Fragment and Activity. Communication should be done with interfaces and interface initialization should be done on Fragment.Lets consider a scenario
1: Fragment has a button named activityButton and Activity has button named fragmentButton on their respective layout

2: On click of activityButton Fragment sends data to Activity and on click of fragmentButton Activity sends data to fragment

3: Further Fragment has ListView,ProgressDialog,Adapters,just to show where to initialize those on fragment

Lets’ create two interfaces named FragmentCommunicator which is used to pass data from Activity to Fragment and ActivityCommunicator which is used to pass data from Fragment to Activity

public interface FragmentCommunicator{
   public void passDataToFragment(String someValue);
}

public interface ActivityCommunicator{
    public void passDataToActivity(String someValue);
}



Now let’s define our Fragment named CustomFragment and as per Android documentation on Fragment it is advisable to add an empty constructor to any subclasses of Fragment

public class CustomFragment extends Fragments implements FragmentCommunicator{
      public Context context;
      private ListView listView;
      private TextView;
      private CustomAdapter customAdapter;
      private ProgressDialog dialog;
      private Button activityButton;
      //interface via which we communicate to hosting Activity
      private ActivityCommunicator activityCommunicator;
      private String activityAssignedValue ="";
      private static final String STRING_VALUE ="stringValue";
      //as per Android Fragment documentation an empty constructor
      public CustomFragment(){    
      }
      public static CustomFragment newInstance(){
        return new CustomFragment();
      }
      //since Fragment is Activity dependent you need Activity context in various cases
      @Override
      public void onAttach(Activity activity){
        super.onAttach(activity);
        context = getActivity();
        activityCommunicator =(ActivityCommunicator)context;
      }
      //now on your entire fragment use context rather than getActivity()
      @Override
      public void onCreate(Bundle savedInstanceState){
       super.onCreate(savedInstanceState);
       if(savedInstanceState != null)
            activityAssignedValue = savedInstanceState.getString(STRING_VALUE);
      }
      @Override
      public void onSaveInstanceState(Bundle outState){
         super.onSaveInstanceState(outState);
         outState.putString(STRING_VALUE,activityAssignedValue);
      }
     //create your fragment view via layout or other views
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
            View fragmentView = inflater.inflate(R.layout.fb_friends_list_view, container, false);
             listView = (ListView)fragmentView.findViewById(R.id.listView);
             activityButton =(Button)fragmentView.findViewById(R.id.activityButton);
             textView =(TextView)fragmentView.findViewById(R.id.textView);
             //don't populate listview,create progress dialog or any other activity related task here
             setRetainInstance(true);
             return fragmentView;
    }
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
	 super.onActivityCreated(savedInstanceState);
	 init();
    }
    public void init() {
     dialog = new ProgressDialog(context);
     dialog.setCancelable(true);
     customAdapter = new CustomAdapter(context,
				R.layout.fb_friend_list_item, new ArrayList());
     listView.setAdapter(customAdapter);
     //communicating to activity via ActivityCommunicator interface
     activityButton.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {
				activityCommunicator.passDataToActivity("Hi from Custom Fragment");
			}
		});
   }
   @Override
   public void onResume() {
    super.onResume();
    textView.setText(activityAssignedValue); 
  }
  //FragmentCommunicator interface implementation
  @Override
  public void passDataToFragment(String someValue){
   activityAssignedValue = someValue;
   textView.setText(activityAssignedValue); 
  }
}

Lets define our FragmentStatePagerAdapter named CustomFragmentAdapter and according to Android documentation better to use FragmentStatePagerAdapter than FragmentPagerAdapter to save the state of the fragments

public class CustomFragmentAdapter extends FragmentStatePagerAdapter {
   private ArrayList<Fragment> list;
   	public CustomFragmentAdapter(FragmentManager fm, ArrayList<Fragment> list) {
		super(fm);
		this.list = list; 
	}
	
	@Override
	public Fragment getItem(int position) {
		return list.get(position);
	}

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

Now lets finally create our Activity class named MainActivity

 public class MainActivity extends FragmentActivity implements ActivityCommunicator{
    	//interface through which communication is made to fragment
        public FragmentCommunicator fragmentCommunicator;
        private Button fragmentButton;
        private ViewPager viewPager;
        private CustomAdapter customAdapter;
        private TextView textView;
        public static ArrayList<Fragment> listFragments;
        
        @Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
                setContentView(R.layout.title_viewpager);
                fragmentButton = (Button)findViewById(R.id.fragmentButton);
                viewPager =(ViewPager)findViewById(R.id.viewPager);
                textView =(TextView)findViewById(R.id.textView);
                listFragments = new ArrayList<Fragment>();
                CustomFragment customFragment = CustomFragment.newInstance();
                WallPostFragment wallPostFragment = WallPostFragment.newInstance();
                listFragments.add(customFragment);
                listFragments.add(wallPostFragment);
                customAdapter = new CustomAdapter(getSupportFragmentManager(),listFragments);
                viewPager.setAdapter(customAdapter);
                setUIListeners();
              
        }

        private void setUIListeners(){
          		fragmentButton.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
                                if(fragmentCommunicator != null)
				fragmentCommunicator.passDataToFragment("Hi from FragmentActivity");
			}
		});

       }
       @Override
       public void passDataToActivity(String someValue){
          textView.setText(someValue); 
      }
}

If you have noticed carefully ,I haven’t initialized fragmentCommunicator anywhere on the Activity, one should initialize it on CustomFragments onAttach() method

   @Override 
   public void onAttach(Activity activity){
    super.onAttach(activity);
    context = getActivity();
    activityCommunicator =(ActivityCommunicator)context;
    ((MainActivity)context).fragmentCommunicator = this;
  }

This is just a mechanism on how to communicate between fragment and activity and it has one flaw.Since we initialized the fragmentCommunicator on CustomFragment and if we need to pass some data on onCreate() method of Activity like

  fragmentCommunicator.passDataToFragment("Hello I am created");

Then it won’t be always certain that Fragment is created and its possible fragmentCommunicator may be null and result in app force close .If cases are like those,don’t pass values directly to Fragment but instead create a mechanism on Fragment to retrieve values of Activity.Let’s say our Fragment needs to look some value of Activity and then only do its work then

  // on Activity
   public int someIntValue =1;
 
  //on Fragment do this onResume() or on  onActivityCreated() only
  @Override
  public void onResume(){
     super.onResume();
     int activityValue =((MainActivity)context).someIntValue;
     if(activityValue == 0){
        //show one view
     }else{
       // show other view
    } 
      
}

This is just a rough implementation,but you can devise a better way to implement this solution.Hope, you didn’t sleep halfway reading this.The reason ,I made this tutorial,is I couldn’t find a better explanation on the any site,on how to properly communicate between Activity and Fragment without lots of null pointer exception. And if you find any other better implementation than me ,do comment or forward me links. Till then, keep on coding ;)