Pages

Friday, 16 December 2011

Using android Date Picker




This is a sample activity which shows how to use Date picker control.
Underlying Algorithm:
Basic description of algorithm in step by step form:
1.) Create a Project DatePickerExample.
2.) Create a date_picker.xml in res/layout.
3.) Put the following code in date_picker.xml :
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:orientation="horizontal">
 <TextView android:id="@+id/dateDisplay"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:paddingLeft="4dip"
           android:text="@string/hello"/>
        <Button android:id="@+id/pickDate"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:paddingLeft="4dip"
           android:text="@string/hello"/>    
</LinearLayout>
4.) To create a date picker control we need the following imports :
import java.util.Calendar;
import android.app.DatePickerDialog;
import android.widget.DatePicker;
5.) Run the application.
Steps to Create:
1.) Open Eclipse. Use the New Project Wizard and select Android Project Give the respective project name i.e. DatePickerExample. Enter following information:
Project name: DatePickerExample
Build Target: Google APIs
Application name: DatePickerExample
Package name: com.sample.DatePickerExample
Create Activity: DatePickerExample
On Clicking Finish DatePickerExample code structure is generated with the necessary Android Packages being imported along with DatePickerExample.java. DatePickerExample class will look like following:
package com.sample.DatePickerExample;
import android.app.Activity;
import java.util.Calendar;
import android.app.DatePickerDialog;
import android.widget.DatePicker;
import android.app.Dialog;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class DatePickerExample extends Activity {
        private TextView mDateDisplay;
        private int mYear;
        private int mMonth;
        private int mDay;
        static final int DATE_DIALOG_ID = 1;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.date_picker);
                mDateDisplay = (TextView) findViewById(R.id.dateDisplay);
                Button pickDate = (Button) findViewById(R.id.pickDate);
                pickDate.setOnClickListener(new View.OnClickListener() {
                        public void onClick(View v) {
                                showDialog(DATE_DIALOG_ID);
                        }
                });
                final Calendar c = Calendar.getInstance();
                mYear = c.get(Calendar.YEAR);
                mMonth = c.get(Calendar.MONTH);
                mDay = c.get(Calendar.DAY_OF_MONTH);
                updateDisplay();
        }
        @Override
        protected Dialog onCreateDialog(int id) {
                switch (id) {
                case DATE_DIALOG_ID:
                        return new DatePickerDialog(this,
                                mDateSetListener,
                                mYear, mMonth, mDay);
                }
                return null;
        }
        protected void onPrepareDialog(int id, Dialog dialog) {
                switch (id) {
                case DATE_DIALOG_ID:
                        ((DatePickerDialog) dialog).updateDate(mYear, mMonth, mDay);
                        break;
                }
        }  
        private void updateDisplay() {
                mDateDisplay.setText(
                        new StringBuilder()
                        // Month is 0 based so add 1
                        .append(mMonth + 1).append("-")
                        .append(mDay).append("-")
                        .append(mYear).append(" "));
        }
        private DatePickerDialog.OnDateSetListener mDateSetListener =
                new DatePickerDialog.OnDateSetListener() {
                public void onDateSet(DatePicker view, int year, int monthOfYear,
                                int dayOfMonth) {
                        mYear = year;
                        mMonth = monthOfYear;
                        mDay = dayOfMonth;
                        updateDisplay();
                }
        };
}
Output –The final output:

Android Project structure



android-logo
PROJECT STRUCTURE:
When new Android Application created. It use specific directory tree structure showing in eclipse SDK platform .There are Eight key items show in project tree structure as follows
1. AndroidManifest.Xml
2. bulid.xml
3. bin/
4. libs
5. src/
6. res/
7. assests
8. gen
project structure
AndroidManifest.xml :
When creating Android application must have an AndroidManifest.xml file in its root directory. It is an XML file describing the application being built and it contains activity, services, uses permission etc.
When creating a new project automatically generated file in project it contains only single main activity of project.
  • It describes the components of the application‚ the activities, services, broadcast receivers, and content providers that the application is composed of. It names the classes that implement each of the components and publishes their capabilities .These declarations let the Android system know what the components are and under what conditions they can be launched.
  • IN AndroidManifest.xml ¬†uses-permission elements, to indicate what permissions your application will need in order to function properly,
Example
android.permission.CALL_EMERGENCY_NUMBERS
android.permission.READ_CONTACT
android.permission.SET_WALLPAPER.
  • permission elements, to declare permissions that activities or services might require other applications hold in order to use your application’s data or logic ‚
  • instrumentation elements, to indicate code that should be invoked on key system events, such as starting up activities, for the purposes of logging or monitoring
  • uses-library elements, to hook in optional Android components, such as mapping services
  • its declares the minimum level of the Android API that used in applications as well as it declare verion name and version code just like
Example
android:versionCode=“1″
android:minSdkVersion=“3″
android:versionName=“1.0″
Build.Xml:
It is an ANT script for compiling the application and installing on the device.
BIN /:
When you compile your project (via ant or the IDE), the results go into the bin/ directory under your project root.
bin/classes/ holds the compiled Java classes
Bin/classes.dex holds the executable created from those compiled Java classes
bin/nameapp.ap_ holds your application’s resources, packaged as a ZIP file
bin/namedebug.apk or bin/nameapp-unsigned.apk is the actual Android application (where nameap is the name of your application)
The .apk file is a ZIP archive containing the .dex file, the compiled edition of your resources, any un-compiled resources (such as what you put in and the AndroidManifest.xml file. )
SRC/:
It contains all source code file (.java file) of android application. E.g hello_world.java
RES/:
Resources are to store all external contents that used in android applications.
These are external elements that you want to include and reference within your application, like images, audio, video, text strings, layouts, themes, etc.It contains all resources that are used in android application
Root directory:
  1. res/drawable : its contain images ,pictures (png, jpeg etc) e.g. .icon.png
  2. res/layout : contains XML(User Interface) that UI layout used in Project or view window of an application.(E.g. main.xml)
  3. res/Values : it declare Arrays, colors, dimensions, strings, and styles.(E.g. strings.xml)
  4. res/raw : it contains non-complied file (e.g. Audio file .mp3, video file .mpg)
E.g. it create an xml file  in values directory
<?xml version=“1.0″ encoding=“utf-8″?>
<resources>
<string name=“hello”>Welcome to Mobisoft Infotech! </string>
<string name=“app_name”>Hello world</string>
</resources>
ASSETS:
Assets it also store an external content refer in android applications. Just like images, audio, video, text strings .It same as resources but different in assets directory will maintain its raw file format and, in order to read it, you must use the AssetManager to read the file as a stream of bytes. So keeping files and data in resources (res/) makes them easily accessible.
libs/:
It’s holds any third-party Java JARs your application Requires.
GEN:
In Eclipse create an application that time auto generated R.java file in gen directory. The R.java file is an index (id) into all the resources defined in the file. This class files use in source code file or it gives for reference or location user interface object that uses in sources code.
Imp Note: Don’t change any code or id (assign value).

Sunday, 4 December 2011

Android Threads, Handlers and AsyncTask


1. Overview

1.1. UI Thread and Background Processing

Android modifies the user interface via one thread, the UI Thread. If the programmer does not use any concurrency constructs, all code of an Android application runs in this UI thread. If you perform a long lasting operation the user interface of your Android Application will block until your code has finished.
This is especially important as Android will display an "Application not responding" (ANR) dialog if an activities does not react within 5 seconds. From this dialog the user can choose to stop the application.
Therefore all potentially slow running operations in an Android application should run in the background, e.g. via some way of concurrency constructs of the Java language or the Android framework. Potential slow operations are network, file and database access but also complex calculations.
This tutorial will teach how to use the special Android constructs for concurrency.

1.2. Android Basics

The following assumes that you have already basic knowledge in Android development . Please check the Android development tutorial to learn the basics.

2. Background Processing

2.1. Threads

Android supports standard Java Threads . You can use standard Threads and the tools from the package "java.util.concurrent" to put actions into the background. The only limitation is that you cannot directly update the UI from the a background process. See Java Concurrency Tutorial for an introduction into background processing with standard Java.
If you need to update the UI from a background task you need to use some Android specific classes. You can use the class "android.os.Handler" for this or the class "AsyncTasks".

2.2. Handler

The class "Handler" can update the UI. A handle provides methods for receiving messages and for runnables. To use a handler you have to subclass it and overide handleMessage() to process messages. To process runables you can use the method post(); You only need one instance of a handler in your activity.
You thread can post messages via the method sendMessage(Message msg) or sendEmptyMessage.

2.3. AsyncTask

The class AsyncTask encapsulates the creation of Threads and Handlers. You must implement the method "doInBackground()", which defines what action should be done in the background. This method is be automatically run in a separate Thread. To update the UI you can override the method "onPostExecute()". This method will be called by the framework once your action is done and runs within the UI thread. AsyncTask
To use AsyncTask you must subclass it. AsyncTask uses generics and varargs.The parameters are the following AsyncTask <TypeOfVarArgParams , ProgressValue , ResultValue> . TypeOfVarArgParams is passed into the doInBackground(), ProgressValueis used for progress information and ResultValue must be returned from doInBackground() and is passed to onPostExecute() as parameter.

2.4. UI Feedback via ProgressBar

For providing feedback to the user you can use the view "ProgressBar" which allow to display progress to the user. The Javadoc of "ProgressBar" gives a nice example of its usage.
Alternatively you can provide progress feedback in the activities title bar.

2.5. Concurrency and lifecyle

One challenge in using threads is to consider the lifecycle of the application . The Android system may kill your activity or trigger a configuration change which also will restart your activity.
You also need to handle open dialogs, as dialogs are always connected to the activity which created them. In case the activity gets restarted and you access an existing dialog you receive an "View not attached to window manager" exception.
To save an object your can use the method onRetainNonConfigurationInstance() and to retrieve this object getLastNonConfigurationInstance(). This way can you can save a running thread even if the activity is restarted. getLastNonConfigurationInstance() returns null if the activity is started the first time of if the it has been finished via the finish() method.
If more then one object should be saved then you can implement the class "Application". This class can be used to access object which should be cross activities or available for the whole application lifecycle. In the onCreate() and onTerminate() you can create / destroy the object and make them available via public fields or getters. To use your application class assign the classname to the android:name attribute of your application.

    
 <application android:icon="@drawable/icon" android:label="@string/app_name"
  android:name="MyApplicationClass">
  <activity android:name=".ThreadsLifecycleActivity"
   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>
   

You can acess the Application via the getApplication() method in your activity.

3. Handler Example

In this example we use the class "Handler" to update a ProgressBar in a background thread.
Create a new Android project "de.vogella.android.handler" with the activity "ProgressTestActivity". Create the following layout "main.xml". This layout contains the ProgressBar and sets its appearance via a style.

   
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical" android:layout_width="fill_parent"
 android:layout_height="fill_parent">
 <ProgressBar android:id="@+id/progressBar1"
  style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent"
  android:layout_height="wrap_content" android:indeterminate="false"
  android:max="10" android:padding="4dip"></ProgressBar>
 <Button android:text="Start Progress" android:onClick="startProgress"
  android:id="@+id/button1" android:layout_width="wrap_content"
  android:layout_height="wrap_content"></Button>
</LinearLayout>

  

Change your activity to the following:

   
package de.vogella.android.handler;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.ProgressBar;

public class ProgressTestActivity extends Activity {
 private Handler handler;
 private ProgressBar progress;

 
/** Called when the activity is first created. */
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); progress = (ProgressBar) findViewById(R.id.progressBar1); handler = new Handler(); } public void startProgress(View view) { // Do something long Runnable runnable = new Runnable() { @Override public void run() { for (int i = 0; i <= 10; i++) { final int value = i; try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } handler.post(new Runnable() { @Override public void run() { progress.setProgress(value); } }); } } }; new Thread(runnable).start(); } }

Run your application. Once you press your button the ProgressBar will get updated from the background thread.

4. AsyncTask Example

In this example we will use AsyncTask to download the content of a webpage. We use Android HttpClient for this. Create a new Android project "de.vogella.android.asynctask" with the activity "ReadWebpageAsyncTask". Add the permission "android.permission.INTERNET". Create the following layout.

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

<Button android:layout_height="wrap_content" android:layout_width="match_parent" android:id="@+id/readWebpage" android:onClick="readWebpage" android:text="Load Webpage"></Button>
<TextView android:id="@+id/TextView01" android:layout_width="match_parent" android:layout_height="match_parent" android:text="Example Text"></TextView>
</LinearLayout>

  

Change your activity to the following:

   
package de.vogella.android.asynctask;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

public class ReadWebpageAsyncTask extends Activity {
 private TextView textView;

 
/** Called when the activity is first created. */
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); textView = (TextView) findViewById(R.id.TextView01); } private class DownloadWebPageTask extends AsyncTask<String, Void, String> { @Override protected String doInBackground(String... urls) { String response = ""; for (String url : urls) { DefaultHttpClient client = new DefaultHttpClient(); HttpGet httpGet = new HttpGet(url); try { HttpResponse execute = client.execute(httpGet); InputStream content = execute.getEntity().getContent(); BufferedReader buffer = new BufferedReader( new InputStreamReader(content)); String s = ""; while ((s = buffer.readLine()) != null) { response += s; } } catch (Exception e) { e.printStackTrace(); } } return response; } @Override protected void onPostExecute(String result) { textView.setText(result); } } public void readWebpage(View view) { DownloadWebPageTask task = new DownloadWebPageTask(); task.execute(new String[] { "http://www.vogella.de" }); } }

If you run your application and press your button then the content of the defined webpage should be read in the background. Once this process is done your TextView will be updated.

5. Activity lifecycle and thread example

The following example will download an image from the Internet in a thread and displays a dialog until the download is done. We will make sure that the thread is preserved even if the activity is restarted and that the dialog is correctly displayed and closed.
For this example create the Android project "de.vogella.android.threadslifecycle" and the Activity "ThreadsLifecycleActivity". Also add the the permission to use the Internet to your app. Details for this can found here: Networking with Android .
You should have the following AndroidManifest.xml

   
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 package="de.vogella.android.threadslifecycle" android:versionCode="1"
 android:versionName="1.0">
 <uses-sdk android:minSdkVersion="10" />
 <uses-permission android:name="android.permission.INTERNET"></uses-permission>

 <application android:icon="@drawable/icon" android:label="@string/app_name">
  <activity android:name=".ThreadsLifecycleActivity"
   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>
  

Change the layout "main.xml" to the following.

   
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical" android:layout_width="fill_parent"
 android:layout_height="fill_parent">
 <LinearLayout android:layout_height="wrap_content"
  android:layout_width="match_parent" android:id="@+id/linearLayout1">
  <Button android:onClick="downloadPicture"
   android:layout_height="wrap_content" android:text="Click to start download"
   android:layout_width="wrap_content"></Button>
  <Button android:onClick="resetPicture" android:layout_height="wrap_content"
   android:text="Reset Picture"
   android:layout_width="wrap_content"></Button>
 </LinearLayout>
 <ImageView android:src="@drawable/icon" android:id="@+id/imageView1"
  android:layout_height="match_parent" android:layout_width="match_parent"></ImageView>
</LinearLayout>
  

Now adjust your activity. In this activity the thread is saved and the dialog is closed if the activity is destroyed.

   
package de.vogella.android.threadslifecycle;

import java.io.IOException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.ImageView;

public class ThreadsLifecycleActivity extends Activity {
 // Static so that the thread access the latest attribute
 private static ProgressDialog dialog;
 private static ImageView imageView;
 private static Bitmap downloadBitmap;
 private static Handler handler;
 private Thread downloadThread;

 
/** Called when the activity is first created. */
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // Create a handler to update the UI handler = new Handler(); // get the latest imageView after restart of the application imageView = (ImageView) findViewById(R.id.imageView1); // Did we already download the image? if (downloadBitmap != null) { imageView.setImageBitmap(downloadBitmap); } // Check if the thread is already running downloadThread = (Thread) getLastNonConfigurationInstance(); if (downloadThread != null && downloadThread.isAlive()) { dialog = ProgressDialog.show(this, "Download", "downloading"); } } public void resetPicture(View view) { if (downloadBitmap != null) { downloadBitmap = null; } imageView.setImageResource(R.drawable.icon); } public void downloadPicture(View view) { dialog = ProgressDialog.show(this, "Download", "downloading"); downloadThread = new MyThread(); downloadThread.start(); } // Save the thread @Override public Object onRetainNonConfigurationInstance() { return downloadThread; } // dismiss dialog if activity is destroyed @Override protected void onDestroy() { if (dialog != null && dialog.isShowing()) { dialog.dismiss(); dialog = null; } super.onDestroy(); } // Utiliy method to download image from the internet static private Bitmap downloadBitmap(String url) throws IOException { HttpUriRequest request = new HttpGet(url.toString()); HttpClient httpClient = new DefaultHttpClient(); HttpResponse response = httpClient.execute(request); StatusLine statusLine = response.getStatusLine(); int statusCode = statusLine.getStatusCode(); if (statusCode == 200) { HttpEntity entity = response.getEntity(); byte[] bytes = EntityUtils.toByteArray(entity); Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); return bitmap; } else { throw new IOException("Download failed, HTTP response code " + statusCode + " - " + statusLine.getReasonPhrase()); } } static public class MyThread extends Thread { @Override public void run() { try { // Simulate a slow network try { new Thread().sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } downloadBitmap = downloadBitmap("http://www.vogella.de/img/lars/LarsVogelArticle7.png"); handler.post(new MyRunnable()); } catch (IOException e) { e.printStackTrace(); } finally { } } } static public class MyRunnable implements Runnable { public void run() { imageView.setImageBitmap(downloadBitmap); dialog.dismiss(); } } }

Run your application and press the button to start a download. You can test the correct lifecycle behavior in the emulator via pressing "CNTR+F11" as this changes the orientation.
It is important to note that the Thread is a static inner class. It is important to use a static inner class for your background process because otherwise the inner class will contain a reference to the class in which is was created. As the thread is passed to the new instance of your activity this would create a memory leak as the old activity would still be referred to by the Thread.

6. StrictMode

StrictMode is available as of API 9, therefore make sure to use Android 2.3.3. As discussed you should avoid performing long running operations on the UI thread. This includes file and network access. It is sometimes difficult to remember to make all the right things in your application during development. That is were StrictMode comes in. It allows to setup policies in your application to avoid doing incorrect things. For example the following setup will crash your application if it violates some of the Android policies. StrictMode should only be used during development and not in your live application.
Create for example "de.vogella.android.strictmode" with the activity "TestStrictMode". The following will set strict rules for your application. As the activity violates these settings you application will crash.
   
package de.vogella.android.strictmode;

import java.io.BufferedWriter;
import java.io.OutputStreamWriter;

import android.app.Activity;
import android.os.Bundle;
import android.os.StrictMode;

public class TestStrictMode extends Activity {
 @Override
 public void onCreate(Bundle savedInstanceState) {
  StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
    .detectAll().penaltyLog().penaltyDeath().build());
  StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll()
    .penaltyLog().penaltyDeath().build());

  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  String eol = System.getProperty("line.separator");
  try {
   BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
     openFileOutput("myfile", MODE_WORLD_WRITEABLE)));
   writer.write("This is a test1." + eol);
   writer.write("This is a test2." + eol);
   writer.write("This is a test3." + eol);
   writer.write("This is a test4." + eol);
   writer.write("This is a test5." + eol);
   writer.close();
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
}
  

7. TraceView and Memory Dump

Traceview is a graphical viewer to see logs created by an Android application. Via Traceview you can find errors in your application and measure its performance.

7.1. Using TraceView in Eclipse

Eclipse supports tracing directly in the DDMS perspective. In the devices view select your application process and select "Start Method Profiling".


Use your application and re-press the same button to stop profiling. This will open a new editor which shows you the result of traceview.




You can zoom into the graphic to get more details.

7.2. Using TraceView from the command line

To start tracing some code put the following code snippet around it.

    
android.os.Debug.startMethodTracing("yourstring");

// ... your code is here

android.os.Debug.stopMethodTracing();

   

The parameter "yourstring" tells the system that it should store the data under "/sdcard/yourstring.trace". To save data on the sdcard your application needs the WRITE_EXTERNAL_STORAGE permission. After running your application you can use Traceview via adb .

    
adb pull /sdcard/yourstring.trace
traceview yourstring

   

This will start Traceview which allow you to analyse your performance data via a graphical way. The DDMS view has also a trace button available. This will trace the running application and does not require an additional authorization.