29 Haziran 2011 Çarşamba

Android Gestures - Tutorial


Lars Vogel

Version 0.1
04.01.2011
Revision History
Revision 0.104.01.2011Lars Vogel
Created
Android Gestures
This tutorial describes how to use Gestures and the GestureOverylayVIew in Android. The tutorial is based on Eclipse 3.6, Java 1.6 and Android 2.3 (Gingerbread).

1. Android Gestures

Android supports gestures. To use this support your application must use the view "GestureOverlayView". In this view you place your other views.
Gestures are defined by a binary resources which can be created with an example program from the Android SDK. In your activity you can load Gestures via GestureLib.fromRawResource(). If a gesture is detected then the method "onGesturePerformedListener" is called. For this the activity must implement the interface "OnGesturePerformedListener" and must register itself at the GestureOverlayView with the method "addOnGesturePerformedListener()".
Android shows the gestures in yellow for recognized gestures and a ligher yellow for not recognized gestures. You can turn this off, via setGestureColor(Color.TRANSPARENT) or setUncertainGestureColor(Color.TRANSPARENT) on the GestureOverlayView.
If you create the gesture in the Android simulator via the program "GestureBuilder". You can create several gestures with the same name. That may help you to determine the right one. If you create an Android Emulator for Android 1.6 this application will be preinstalled on your device. Make sure to create a device with sdcard otherwise you cannot save gestures. All gestures will be saved in a file called "gestures" on your emulator.
You can copy the gestures from the emulator via the adb onto your local machine via the command:

./adb pull /sdcard/gestures ~/test

The gesture file must be copied into your application under "res/raw". Afterwards it can be used in your GestureOverlayView.

2. Example

Create a new Android project "de.vogella.android.gestures" with the activity "GestureTest". Create a few gestures and copy them to your application as described in the last chapter.


Unfortunately the UI builder does not support GestureOverlayView, please see Bug report GestureOverlayView not working in the layout builder , therefore we have to build a layout without the gesture view and add this view via code to the GestureOverlayView.
Create the following layout "main.xml".

<?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"
>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/hello"/>
</LinearLayout>


Create the following Activity.

package de.vogella.android.gestures;

import java.util.ArrayList;

import android.app.Activity;
import android.gesture.Gesture;
import android.gesture.GestureLibraries;
import android.gesture.GestureLibrary;
import android.gesture.GestureOverlayView;
import android.gesture.GestureOverlayView.OnGesturePerformedListener;
import android.gesture.Prediction;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

public class GestureTest extends Activity implements OnGesturePerformedListener {
private GestureLibrary gestureLib;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GestureOverlayView gestureOverlayView = new GestureOverlayView(this);
View inflate = getLayoutInflater().inflate(R.layout.main, null);
gestureOverlayView.addView(inflate);
gestureOverlayView.addOnGesturePerformedListener(this);
gestureLib = GestureLibraries.fromRawResource(this, R.raw.gestures);
if (!gestureLib.load()) {
finish();
}
setContentView(gestureOverlayView);
}

@Override
public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
ArrayList<Prediction> predictions = gestureLib.recognize(gesture);
for (Prediction prediction : predictions) {
if (prediction.score > 1.0) {
Toast.makeText(this, prediction.name, Toast.LENGTH_SHORT)
.show();
}
}
}
}

Start your application. As a result you should be able to perform gestures and see the result. We only show a Toast but of course you could perform all kind of actions.

3. Thank you

Android Sensor - Tutorial


Lars Vogel

Version 0.2
14.06.2011
Revision History
Revision 0.105.01.2011Lars Vogel
Created
Revision 0.214.06.2011Lars Vogel
bugfixes and enhancements
Android Sensor
This tutorial describes how to use the Androids Sensor manager. It currently demonstrates the accelerometer. The tutorial is based on Eclipse 3.6, Java 1.6 and Android 2.3.3 (Gingerbread).

1. Android Sensors

Android supports several sensors via the SensorManager, for example the accelerometer. Unfortunately you cannot test the accelerometer on the Android emulator.
Once you get the ServiceManager via getSystemService(SENSOR_SERVICE) you can register a "SensorEventListener" to it. To avoid the unnecessary usage of battery you register your listener in the onResume method and de-register on the onPause method.

2. Example

Create a new Android project "de.vogella.android.sensor" with the activity "SensorTest".
Change your 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">
<TextView android:id="@+id/textView" android:layout_width="match_parent"
android:layout_height="match_parent" android:text="Shake to get a toast and to switch color" />
</LinearLayout>


Change the coding of your activity Activity.

package de.vogella.android.sensor;

import android.app.Activity;
import android.graphics.Color;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Toast;

public class SensorTest extends Activity implements SensorEventListener {
private SensorManager sensorManager;
private boolean color = false;
private View view;
private long lastUpdate;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);

super.onCreate(savedInstanceState);
setContentView(R.layout.main);
view = findViewById(R.id.textView);
view.setBackgroundColor(Color.GREEN);

sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
sensorManager.registerListener(this,
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_NORMAL);
lastUpdate = System.currentTimeMillis();
}

@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
float[] values = event.values;
// Movement
float x = values[0];
float y = values[1];
float z = values[2];

float accelationSquareRoot = (x * x + y * y + z * z)
/ (SensorManager.GRAVITY_EARTH * SensorManager.GRAVITY_EARTH);
long actualTime = System.currentTimeMillis();
if (accelationSquareRoot >= 2) //
{
if (actualTime - lastUpdate < 200) {
return;
}
lastUpdate = actualTime;
Toast.makeText(this, "Device was shuffed", Toast.LENGTH_SHORT)
.show();
if (color) {
view.setBackgroundColor(Color.GREEN);

} else {
view.setBackgroundColor(Color.RED);
}
color = !color;
}

}

}

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub

}

@Override
protected void onResume() {
super.onResume();
// register this class as a listener for the orientation and
// accelerometer sensors
sensorManager.registerListener(this,
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_NORMAL);
}

@Override
protected void onPause() {
// unregister listener
sensorManager.unregisterListener(this);
super.onStop();
}
}

3. Thank you

Android Widgets- Tutorial


Lars Vogel

Version 1.2
01.09.2010 - 20.06.2011
Revision History
Revision 0.101.09.2010Lars Vogel
Created
Revision 0.2 - 1.213.12.2010 - 20.06.2011Lars Vogel
bug fixes and enhancements
Developing Android Widgets
This article describes how to create widgets in Android. It is based on Eclipse 3.6, Java 1.6 and Android 2.3.3 (Gingerbread).

1. Android Widgets

1.1. Widgets

Widgets are little applications which can be placed on the home screen of your Android device. An widget gets its data on a periodic timetable. There are two methods to update a widget, one is based on an XML configuration file and the other is based on AlarmManager. The XML configuration will wake up the device and can the smallest possible update interval is 30 minutes. The alarm manager allows you to be more resource efficient and to have a higher frequency of updates.
To create a App Widget you:
  • Define a layout file for your widget.
  • Maintain an XML file (AppWidgetProviderInfo) which describes the properties of the widget, e.g. size or fixed update frequency.
  • Create a broadcast receiver which will be used to update the widgets. This receiver extends AppWidgetProvider which provides additional lifecycle hooks for widgets.
  • Maintain the App Widget configuration in the "AndroidManifest.xml" file.
  • Optional you can also specify a configuration activities which is called once one instance of the widget is added to the homescreen.

1.2. Available views and layouts

A widget is restricted in the elements it can use. For layouts you can use "FrameLayout", "LinearLayout" and "RelativeLayout". As views you can use "AnalogClock", "Button", "Chromometer", "ImageButton", "ImageView", "ProgressBar" and "TextView".

1.3. Widget size

A widget will take a certain amount of cells on the homescreen. A cell is usually used to display the icon of one application. As a calculation rule you should define the size of the widget with the formula: ((Number of columns / rows)* 74)- 2. These are device independent pixels and the -2 is used to avoid rounding issues.

1.4. Widget updates and RemoteViews

To save power consumption a widget does not have its own process but is part of the homescreen process. Therefore the widget UI is created as a RemoteView. A RemoteView can be executed by another process with the same permissions as the original application.
In the widget configuration file you can specify a fixed update interval. The system will wake up after this time interval and call your broadcast receiver to udpate the widget. The smallest update interval is 180000 milliseconds (30 minutes). A more flexible update can be archived with the AlarmManager which we will demonstrate later in this tutorial.
Here you see an example configuration file for a widget.

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:updatePeriodMillis="180000"
android:initialLayout="@layout/widget_layout"
android:minHeight="72dp" android:minWidth="146dp">
</appwidget-provider>

1.5. AppWidgetProvider

Your broadcast receiver extends AppWidgetProvider. The AppWidgetProvider class implements the onReceive() method, extracts the required information and calls the following widget lifecycle methods.
As you can added several instances of a widget to the homescreen you have lifecycle methods which are called only for the first instance added / removed to the homescreen and others which are called for every instance of your widget.
Table 1. Lifecycle method
MethodDescription
onEnabled()Called the first time an instance of your widget is added to the homescreen
onDisabled()Called once the last instance of your widget is removed from the homescreen.
onUpdate()Called for every update of the widget. Contains the ID's of the widgets currently on the homescreen.
onDeleted()Widget instance is removed from the homescreen

All long running operations in these methods should be performed in a service, as the execution time for a broadcast receiver is limited. Also using asynchronous processing does not help as the system can kill the broadcast process after his onReceive() method.

1.6. 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. Example with fixed update interval

The following will create a simple example for a widget, we will create a widget which displays a random number and updates this number every 30 minutes. The resulting widget will look like the following.


Create a new Android project "de.vogella.android.widget.example" with no activity in the package "de.vogella.android.widget.example".
Create a new file "myshape.xml" under "/res/drawable-mdpi". This file will define the background we use in your widget.

<?xml version="1.0" encoding="UTF-8"?> 
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke android:width="2dp" android:color="#FFFFFFFF" />
<gradient android:startColor="#DD000000" android:endColor="#DD2ECCFA"
android:angle="225"/>

<corners android:bottomRightRadius="7dp" android:bottomLeftRadius="7dp"
android:topLeftRadius="7dp" android:topRightRadius="7dp"/>
</shape>

Define the following "widget_layout.xml" file under res/layout.

<?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:background="@drawable/myshape" android:layout_margin="8dip">
<TextView android:layout_margin="4dip" android:text="Static Text"
android:id="@+id/TextView01" android:layout_width="match_parent"
android:layout_height="match_parent" style="@android:style/TextAppearance.Medium"
android:layout_gravity="center"></TextView>
</LinearLayout>


Create the "AppWidget Provider" Metadata file "widget_info.xml", via File -> New -> Android -> Android XML File.





<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:updatePeriodMillis="300000" android:minWidth="300dp"
android:minHeight="72dp" android:initialLayout="@layout/widget_layout">
</appwidget-provider>


Create the broadcast receiver which will be called for updates.

package de.vogella.android.widget.example;

import java.util.Random;

import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.widget.RemoteViews;

public class MyWidgetProvider extends AppWidgetProvider {

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
// Create some random data
String fakeUpdate = "Random: ";
Random random = new Random();
int nextInt = random.nextInt(100);
fakeUpdate += String.valueOf(nextInt);
for (int i : appWidgetIds) {
int widgetId = appWidgetIds[i];
int number = (new Random().nextInt(100));

RemoteViews views = new RemoteViews(context.getPackageName(),
R.layout.widget_layout);
views.setTextViewText(R.id.TextView01, String.valueOf(number));
appWidgetManager.updateAppWidget(widgetId, views);
}
}
}


Open "AndroidManifest.xml" and maintain the following.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.vogella.android.widget.example"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<receiver android:name="MyWidgetProvider">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/widget_info" />
</receiver>
</application>
<uses-sdk android:minSdkVersion="8" />

</manifest>

This attribute specifies that the AppWidgetProvider accepts the ACTION_APPWIDGET_UPDATE broadcast. This is the only broadcast that you must explicitly declare.
Run your app. Once your app has been deployed, long press on your desktop and install your new widget.



3. Update via a service and onClickListener

If you widget requires longer processing time you should do this processing in a service and perform the update of the widgets from their. The following will demonstrate the usage of a service. It will also show how to add a onClickListner to the widget. We will implement the onClickListener so that all widgets will be updated if one widget is selected.
First create a UpdateWidgetService Service in your existing project. For on introduction into services please see Android Service Tu torial

package de.vogella.android.widget.example;

import java.util.Random;

import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import android.widget.RemoteViews;

public class UpdateWidgetService extends Service {
@Override
public void onStart(Intent intent, int startId) {
Log.i("UpdateWidgetService", "Called");
// Create some random data
String fakeUpdate = null;
Random random = new Random();

AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this
.getApplicationContext());

int[] appWidgetIds = intent
.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
if (appWidgetIds.length > 0) {
for (int widgetId : appWidgetIds) {
int nextInt = random.nextInt(100);
fakeUpdate = "Random: " + String.valueOf(nextInt);
RemoteViews remoteViews = new RemoteViews(getPackageName(),
R.layout.widget_layout);
remoteViews.setTextViewText(R.id.TextView01, fakeUpdate);
appWidgetManager.updateAppWidget(widgetId, remoteViews);
}
stopSelf();
}
super.onStart(intent, startId);
}

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


Change MyWidgetProvider to the following.

package de.vogella.android.widget.example;

import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.widget.RemoteViews;

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

// Build the intent to call the service
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
R.layout.widget_layout);
Intent intent = new Intent(context.getApplicationContext(),
UpdateWidgetService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);

// To react to a click we have to use a pending intent as the
// onClickListener is
// excecuted by the homescreen application
PendingIntent pendingIntent = PendingIntent.getService(
context.getApplicationContext(), 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.layout, pendingIntent);

// Finally update all widgets with the information about the click
// listener
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);

// Update the widgets via the service
context.startService(intent);
}
}


Once called this service will update all widgets. You can click on one of the widgets to update all widgets.

4. Thank you

Android Threads, Handlers and AsyncTask - Tutorial


Lars Vogel

Version 1.6
25.06.2011
Revision History
Revision 0.121.10.2010Lars Vogel
Created
Revision 0.2 - 1.621.12.2010 - 25.06.2011Lars Vogel
bug fixes and updates
Android Threads, Handlers AsyncTask
This tutorial describes the usage of Threads, Handlers and AsynTask in your application. It also covers how to handle the application lifecycle together with threads. It also describes Traceview to trace an application for performance problems. It is based on Eclipse 3.7, Java 1.6 and Android 2.3.3 (Gingerbread).

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 "AsynTasks".

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. AsynTask
To use AsyncTask you must subclass it. AsynTask 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.asyntask" with the activity "ReadWebpageAsynTask". 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.asyntask;

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 ReadWebpageAsynTask 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

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.

7.3. Memory Dumps

You can create a memory snapshot and analyse it with the Eclipse Memory Analyzer .

8. Thank you