MobileJava MobileHow to Load Data Asynchronously in Android Apps Using Loaders

How to Load Data Asynchronously in Android Apps Using Loaders

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Introduction To Loading Data Asynchronously in Android

Loaders are an Android construct that make it easy to load data in an activity or a fragment in an asynchronous manner.

Loaders can be bound to a data source and, when content changes in the data source, they can deliver refreshed results. Additionally, they keep the cursor context of a connection and, when they reconnect, they do not need to re-query the data.

Basics of Android Loaders

Each Activity or Fragment can have at most one LoaderManager class that is used to manage Loaders’ instances. Typically, to use loaders in an Android application, we need the following:

  • Activity or Fragment class
  • Instance of LoaderManager
  • CursorLoader class to load data
  • Widget to display loader’s data
  • Data source

Hands On with Android Loaders

Let’s create a simple Android application that demonstrates working with Loaders.

Fire up Android Studio and Start a new Android Studio Project.

Load1
Figure 1: Opening Android Studio

Provide LoaderDemo as the Application Name and click Next.

Load2
Figure 2: Naming the Application

On the next screen, leave the default values and click Next.

Load3
Figure 3: Leaving the default values in place

On the “Add an activity to Mobile” page, choose “Blank Activity”. This creates an application with a single activity.

Load4
Figure 4: Adding a Blank Activity

We then are prompted to customize the activity. We will leave the default values unchanged.

Load5
Figure 5: Again, leaving the default values in place

Click Finish to create the project files.

First, we declare the capability to read contacts in an application manifest.

//AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns_android="http://schemas.android.com/apk/res/android"
   package="com.example.vipul.loaderdemo" >
   <uses-permission android_name="android.permission.READ_CONTACTS" />
   <application
      android:allowBackup="true"
      android:icon="@mipmap/ic_launcher"
      android:label="@string/app_name"
      android:theme="@style/AppTheme" >
      <activity
         android:name=".MainActivity"
         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>

We then update the layout file to add a listview.

//activitymain.xml
<RelativeLayout xmlns_android=
      "http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:paddingLeft="@dimen/activity_horizontal_margin"
   android:paddingRight="@dimen/activity_horizontal_margin"
   android:paddingTop="@dimen/activity_vertical_margin"
   android:paddingBottom="@dimen/activity_vertical_margin"
   tools:context=".MainActivity">

   <ListView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:id="@+id/listView"
      android:layout_alignParentTop="true"
      android:layout_centerHorizontal="true"
      android:layout_marginTop="122dp" />
</RelativeLayout>

Open MainActivity.java and include a few imports.

//MainActivity.java
import android.app.ListActivity;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import android.provider.ContactsContract.Contacts;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.app.LoaderManager.LoaderCallbacks;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;

Next, we update the class declaration to extend LoaderCallbacks.

public class MainActivity
   extends ListActivity
   implements LoaderCallbacks<Cursor> {

We then add a few member variables.

CursorLoader myCursorLoader;
String currentFilter;
SimpleCursorAdapter myDisplayAdapter;
ListView yourListView = getListView();

static final String[] CONTACTS_SUMMARY_PROJECTION =
   new String[]{
      Contacts._ID,
      Contacts.DISPLAY_NAME
};

Next, we update the default code in the onCreate method to intiialize the loadermanager:

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);
   yourListView = getListView();

   myDisplayAdapter = new SimpleCursorAdapter(this,
      android.R.layout.simple_list_item_1, null,
      new String[] { Contacts.DISPLAY_NAME},
      new int[] { android.R.id.text1}, 0);
   setListAdapter(myDisplayAdapter);

   getLoaderManager().initLoader(0, null, this);
}

Lastly, we implement the callback methods for the loader.

// This method is called when initLoader is invoked.
// In this method, we create the CursorLoader
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {

   // Create a cursor
   // uri: The URI for the content to retrieve.
   // projection: A list of which columns to return.
   // Passing null will return all columns,
   // which is inefficient.
   // selection: A filter declaring which rows to return,
   // formatted as an SQL WHERE clause (excluding the WHERE itself).
   // Passing null will return all rows for the given URI.
   // selectionArgs: You may include ?s in the selection,
   // which will be replaced by the values from selectionArgs,
   // in the order that they appear in the selection.
   // The values will be bound as Strings.
   // sortOrder: How to order the rows, formatted as an SQL ORDER BY
   // clause (excluding the ORDER BY itself). Passing null will use
   // the default sort order, which may be unordered.

   Uri baseUri;
   if (currentFilter != null) {
      baseUri = Uri.withAppendedPath
            (ContactsContract.Contacts.CONTENT_FILTER_URI,
         Uri.encode(currentFilter));
   } else {
      baseUri = ContactsContract.Contacts.CONTENT_FILTER_URI;
   }

   String select = "((" + Contacts.DISPLAY_NAME
      + " NOTNULL) AND ("
      + Contacts.HAS_PHONE_NUMBER + "=1) AND ("
      + Contacts.DISPLAY_NAME + " != '' ))";
   myCursorLoader = new CursorLoader(this,
      baseUri,CONTACTS_SUMMARY_PROJECTION, select, null,
      Contacts.DISPLAY_NAME + " ASC");

   return myCursorLoader;
}

On the onLoadFinished callback, we swap the cursor with the data.

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
   myDisplayAdapter.swapCursor(data);
}

In the onLoaderReset callback, we set the swap to null.

@Override
public void onLoaderReset(Loader<Cursor> loader) {
   myDisplayAdapter.swapCursor(null);
}

Our application is now complete. When you run it, you will see the loaders in action.

Summary

In this article, we learned how to use loaders to get data loaded asynchronously in Android Applications. I hope you have found this information useful.

Resources

About the Author

Vipul Patel is a technology geek based in Seattle. He can be reached at vipul.patel@hotmail.com. You can visit his LinkedIn profile at https://www.linkedin.com/pub/vipul-patel/6/675/508.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories