Cdacians

Cdacians
Cdacians

Thursday, 23 August 2012

File based persistence in Android


File based persistence in Android
This tutorial describes how to save key-value pairs using the preference API in Android. It also explains how to read and write files in Android. It is based on Eclipse 3.7, Java 1.6 and Android 4.0 (Ice Cream Sandwich).

1. Android File Based Persistence

1.1. Methods of persistence

Android allows to store local data as files. Android uses file based storage for handling application settings (Preferences) and instances of the SQLite database.
For each application the Android system creates a data/data/package.of.the.application directory.
Files are saved in the files folder and application settings are saved as XML files in the shared_prefsfolder.
If your application creates an SQLite database this database is saved in the main application directory under the databases folder.
The following screenshot shows a filesystem which contains file, cache files and preferences.
Screenshot of the file system with a few files
Only the application can write into its application directory. It can create additional subdirectories in this application directory. For these subdirectories, the application can grant read or write permissions for other applications.

1.2. Internal vs. external storage

Android has internal storage and external storage. External storage is not private and may not always be available.

1.3. Application on external storage

As of Android 8 SDK level it is possible to define that the application can or should be placed on external storage. For this set the android:installLocation to preferExternal or auto.
In this case certain application components may be stored on an encrypted external mount point. Database and other private data will still be stored in the internal storage system.

2. Preferences

2.1. API

Android supports the usage of Preferences to allow you to save data for your application. Preferences are stored as key values. The definition of Preferences can also be done via an XML resource.
The PreferenceManager gives access to the preference values. The following code snippets shows how to access your default preferences.
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); 
Values can get accessed via the key of the preference setting.
String username = preferences.getString("username", "n/a"); 
To create or change preferences you have to call the edit() method on the SharedPreferences object. Once you have changed the value you have to call the commit() to apply your changes.
Editor edit = preferences.edit();
edit.putString("username", "new_value_for_user");
edit.commit(); 

2.2. PreferenceActivity

Android provides the PreferenceActivity class which extends the Activity class.PreferenceActivity supports the simple handling of preferences. It can load a preference definition resources via the method addPreferencesFromResource().
To communicate between different components Android uses Intents. Typically thePreferenceActivity is started from another Activity via an Intent.

2.3. Preference Listener

You can listen to changes in the preferences via theregisterOnSharedPreferenceChangeListener() method on SharedPreferences.
SharedPreferences prefs = 
    PreferenceManager.getDefaultSharedPreferences(this);

// Instance field for listener
listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
  public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
    // Your Implementation
  }
};

prefs.registerOnSharedPreferenceChangeListener(listener); 
One watch out is that SharedPreferences keeps listeners in a WeakHashMap hence listener may be recycled if your code does not hold a reference to it. .

3. Tutorial: Prerequirements

The following tutorial is based on the "de.vogella.android.socialapp" example from Android ActionBar Tutorial .

4. Tutorial: Preferences

4.1. Using preferences

We will continue using the example project "de.vogella.android.social".
Create an Android XML resource "preferences.xml" of type "PreferenceScreen".
How to create a XML file for storing preference value definitions
Open the file via right-mouse click and Open with → Android XML Resource Editor. Press Add, add a "PreferenceCategory" and add two preferences "EditTextPreferences" to this category : "User" and "Password".
Adding a category to the preference XML file
Adding the field "user" to the preference XML file
Adding the field "password" to the preference XML file
You can also enter values for other properties of EditTextField, e.g. the inputMethod.
Add the following attribute to the XML definition of your password field to make the input quoted with *.
android:inputType="textPassword" 
Create the class MyPreferencesActivity which extends PreferenceActivity. ThisActivity will load the "preference.xml" file and will allow the user to change the values.
package de.vogella.android.socialapp;

import android.os.Bundle;
import android.preference.PreferenceActivity;

public class MyPreferencesActivity extends PreferenceActivity {
  @Override
  public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      addPreferencesFromResource(R.xml.preferences);
  }
} 
To make this class available as an activity for Android you need to register it in your AndroidManifest.xmlfile. Select AndroidManifest.xml and the tab "Application". Scroll to the botton of the view and add your new activity via the Add button.
How to define a new activity in the AndroidManifest.xml
To make use of our new preference activity and the preference values we adjust the "OverviewActivity". The first button will show the current values of the preferences via a Toast and the second button will revert the maintained user name to demonstrate how you could change the preferences via code.
package de.vogella.android.socialapp;

import android.app.Activity;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class OverviewActivity extends Activity {
  SharedPreferences preferences;
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    Button button = (Button) findViewById(R.id.Button01);
    // Initialize preferences
    preferences = PreferenceManager.getDefaultSharedPreferences(this);

    button.setOnClickListener(new OnClickListener() {
      public void onClick(View v) {
        String username = preferences.getString("username", "n/a");
        String password = preferences.getString("password", "n/a");
        showPrefs(username, password);
      }
    });

    Button buttonChangePreferences = (Button) findViewById(R.id.Button02);
    buttonChangePreferences.setOnClickListener(new OnClickListener() {
      public void onClick(View v) {
        
        updatePreferenceValue();
      }
    });
  }
  
  private void showPrefs(String username, String password){
    Toast.makeText(OverviewActivity.this,
        "Input: " + username + " and password: "
            + password, Toast.LENGTH_LONG).show();

  }
  
  private void updatePreferenceValue(){
    Editor edit = preferences.edit();
    String username = preferences.getString("username", "n/a");
    // We will just revert the current user name and save again
    StringBuffer buffer = new StringBuffer();
    for (int i = username.length() - 1; i >= 0; i--) {
      buffer.append(username.charAt(i));
    }
    edit.putString("username", buffer.toString());
    edit.commit();
    // A toast is a view containing a quick little message for the
    // user. We give a little feedback
    Toast.makeText(OverviewActivity.this,
        "Reverted string sequence of user name.",
        Toast.LENGTH_LONG).show();
  } 
To open the new preference Activity we will use the onOptionsItemSelected() method. Even though we currently have only one option in our menu we use a switch to be ready for several new menu entries. To see the current values of the preferences we define a button and use the classPreferenceManager to get the sharedPreferences.
@Override
public boolean onCreateOptionsMenu(Menu menu) {
  MenuInflater inflater = getMenuInflater();
  inflater.inflate(R.menu.mainmenu, menu);
  return true;
}

// This method is called once the menu is selected
@Override
public boolean onOptionsItemSelected(MenuItem item) {
  switch (item.getItemId()) {
  // We have only one menu option
  case R.id.preferences:
    // Launch Preference activity
    Intent i = new Intent(OverviewActivity.this, MyPreferencesActivity.class);
    startActivity(i);
    // Some feedback to the user
    Toast.makeText(OverviewActivity.this, "Enter your user credentials.",
      Toast.LENGTH_LONG).show();
    break;

  }
  return true;
} 

4.2. Run

Run your application. Press the "menu" hardware button and then select your menu item "Preferences". You should be able to enter your user settings then press the back hardware button to return to your main activity. The saved values should be displayed in a small message windows (Toast) if you press your first button. If you press the second button the username should be reversed.
The running application showing the maintenance dialog for the field "user" in the preference activity

5. Android File API

5.1. Overview

Access to the file system is performed via the standard java.io classes.
Android provides also helper classes for creating and accessing new files and directories. For example the getDir(String, int) method would create or access a directory. TheopenFileInput(String s) method would open a file for input and openFileOutput(String s, int) would create a file.
int specifies the permissions which are:
  • MODE_PRIVATE - No access for other applications
  • MODE_WORLD_READABLE - Read access for other applications
  • MODE_WORLD_WRITABLE - Write access for other applications
  • MODE_WORLD_READABLE | MODE_WORLD_WRITABLE - Read / Write access
The following example shows the API usage.
private void writeFileToInternalStorage() {
  String eol = System.getProperty("line.separator");
  BufferedWriter writer = null;
  try {
    writer = new BufferedWriter(new OutputStreamWriter(openFileOutput("myfile", MODE_WORLD_WRITEABLE)));
    writer.write("This is a test1." + eol);
    writer.write("This is a test2." + eol);
  } catch (Exception e) {
      e.printStackTrace();
  } finally {
    if (writer != null) {
    try {
      writer.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
    }
  }
} 
private void readFileFromInternalStorage() {
  String eol = System.getProperty("line.separator");
  BufferedReader input = null;
  try {
    input = new BufferedReader(new InputStreamReader(openFileInput("myfile")));
    String line;
    StringBuffer buffer = new StringBuffer();
    while ((line = input.readLine()) != null) {
    buffer.append(line + eol);
    }
  } catch (Exception e) {
     e.printStackTrace();
  } finally {
  if (input != null) {
    try {
    input.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
    }
  }
} 

5.2. How to access a shared file

Another application can access a file, which has been created with the MODE_WORLD_READABLE model. For this, it need to knows the package and file name. The following example shows this.
FileInputStream openFileInput = createPackageContext("the_package", 0).openFileInput("thefile"); 

5.3. External storage

Android supports also access to an external storage system e.g. the SD card. All files and directories on the external storage system are readable for all applications.
To write to the external storage system your application needs theandroid.permission.WRITE_EXTERNAL_STORAGE permission. You get the path to the external storage system via the Environment.getExternalStorageDirectory() method.
Via the following method call you can check the state of the external storage system. If the Android device is connected via USB to a computer, a SD card which might be used for the external storage system is not available.
Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) 
The following shows an example for reading from the external storage system.
private void readFileFromSDCard() {
  File directory = Environment.getExternalStorageDirectory();
  // Assumes that a file article.rss is available on the SD card
  File file = new File(directory + "/article.rss");
  if (!file.exists()) {
    throw new RuntimeException("File not found");
  }
  Log.e("Testing", "Starting to read");
  BufferedReader reader = null;
  try {
    reader = new BufferedReader(new FileReader(file));
    StringBuilder builder = new StringBuilder();
    String line;
    while ((line = reader.readLine()) != null) {
      builder.append(line);
    }
  } catch (Exception e) {
    e.printStackTrace();
  } finally {
    if (reader != null) {
      try {
        reader.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
} 

6. Thank you

Please help me to support this article:

Thanks
akm
www.cdacians.com

Android Threads, Handlers AsyncTask


This tutorial describes the usage of Threads, Handlers and AsyncTask 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 4.0 (Ice Cream Sandwitch)

1. Android Threads and Background Processing

Android modifies the user interface and handles input events from one single user interface thread which is also called the main thread.
If the programmer does not use any concurrency constructs, all code of an Android application runs in this thread.
If you perform a long lasting operation, e.g. loading a file or accessing data from the Internet, the user interface of your Android Application will block until the corresonding code has finished.
To provide a good user experience all potentially slow running operations in an Android application should run asynchronously, e.g. via some way of concurrency constructs of the Java language or the Android framework. This includes all potential slow operations, like network, file and database access and complex calculations.
Android enforced that with an Application not responding (ANR) dialog if an Activity does not react within 5 seconds to user input. From this dialog the user can choose to stop the application.

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.

3. Background Processing

3.1. Threads

Android supports the usage of the Threads class to perform asynchronous processing.
Android also supplies the java.util.concurrent package to perform something in the background, e.g. using the ThreadPools and Executor classes.
If you need to update the user interface from a new Thread, you need to synchronize with the user interface thread.
You can use the android.os.Handler class or the AsyncTasks class for this.

3.2. Handler

The Handler class can update the user interface. A Handler provides methods for receiving instances of the Message or Runnable class.
To use a handler you have to subclass it and override the handleMessage() to process messages. To process a Runnable you can use the post() method. You only need one instance of a Handler in your Activity.
You thread can post messages via the sendMessage(Message msg) method or via thesendEmptyMessage() method.

3.3. AsyncTask

The AsyncTask class encapsulates the creation of Threads and Handlers. An AsyncTask is started via the execute() method.
The execute() method calls the doInBackground() and the onPostExecute() method.
The doInBackground() method contains the coding instruction which should be performed in a background thread. This method runs automatically in a separate Thread.
The onPostExecute() method synchronize itself again with the user interface thread and allows to update it. This method is called by the framework once the doInBackground() method finishes.
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() method as input, ProgressValue is used for progress information and ResultValue must be returned from doInBackground() method and is passed to onPostExecute() as parameter.

3.4. Feedback via ProgressBar

For providing feedback to the user you can use the ProgressBar dialog, 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.

3.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() method. This method allows to save one object if the activity will be soon restarted.
To retrieve this object you can use the getLastNonConfigurationInstance() method. This way can you can save an object, e.g. a running thread, even if the activity is restarted.
getLastNonConfigurationInstance() returns null if the Activity is started the first time or if 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.

4. Tutorial: Handler

In this example we use the Handler class to update a ProgressBar view in a background Thread.
Create a new Android project called "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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <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:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="startProgress"
        android:text="Start Progress" >
    </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.

5. Tutorial: AsyncTask

In this example we will use an instance of the AsyncTask class to download the content of a webpage. We use Android HttpClient for this. Create a new Android project called de.vogella.android.asynctaskwith an Activity called ReadWebpageAsyncTask. Add the android.permission.INTERNETpermission to your <filenname>AndroidManifest.xml</filenname> file. .
Create the following 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:orientation="vertical" >

    <Button
        android:id="@+id/readWebpage"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        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.com" }); } }
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.

6. Tutorial: Activity lifecycle and Thread

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 permission to use the Internet to your app. Details for this can found here: Networking with Android.
You should have the following AndroidManifest.xml file.
<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:id="@+id/linearLayout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="downloadPicture"
            android:text="Click to start download" >
        </Button>

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="resetPicture"
            android:text="Reset Picture" >
        </Button>
    </LinearLayout>

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/icon" >
    </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.com/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 "Ctrl+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.

7. 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 the project called "de.vogella.android.strictmode" with the Activity called 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();
    }
  }
} 

8. 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.

8.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.

8.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.

8.3. Memory Dumps

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

9. Thank you

Please help me to support this article:

Thanks
akm
www.cdacians.com