Here is source code of the Program to Demonstrate Loaders in Android. The program is successfully compiled and run on a Windows system using Eclipse Ide. The program output is also shown below.
MainActivity.java
package com.example.loaders; import android.annotation.SuppressLint; import android.app.ListActivity; import android.app.LoaderManager; import android.content.CursorLoader; import android.content.Intent; import android.content.Loader; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.ListView; import android.widget.SimpleCursorAdapter; @SuppressLint("NewApi") public class MainActivity extends ListActivity implements LoaderManager.LoaderCallbacks<Cursor> { private static final int ACTIVITY_CREATE = 0; private static final int ACTIVITY_EDIT = 1; private static final int DELETE_ID = Menu.FIRST + 1; private SimpleCursorAdapter adapter; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.todo_list); this.getListView().setDividerHeight(2); fillData(); registerForContextMenu(getListView()); } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.insert: createTodo(); return true; } return super.onOptionsItemSelected(item); } @Override public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { case DELETE_ID: AdapterContextMenuInfo info = (AdapterContextMenuInfo) item .getMenuInfo(); Uri uri = Uri.parse(MyTodoContentProvider.CONTENT_URI + "/" + info.id); getContentResolver().delete(uri, null, null); fillData(); return true; } return super.onContextItemSelected(item); } private void createTodo() { Intent i = new Intent(this, TodoDetailActivity.class); startActivity(i); } @Override protected void onListItemClick(ListView l, View v, int position, long id) { super.onListItemClick(l, v, position, id); Intent i = new Intent(this, TodoDetailActivity.class); Uri todoUri = Uri.parse(MyTodoContentProvider.CONTENT_URI + "/" + id); i.putExtra(MyTodoContentProvider.CONTENT_ITEM_TYPE, todoUri); startActivity(i); } private void fillData() { String[] from = new String[] { TodoTable.COLUMN_SUMMARY }; int[] to = new int[] { R.id.label }; getLoaderManager().initLoader(0, null, this); adapter = new SimpleCursorAdapter(this, R.layout.todo_row, null, from, to, 0); setListAdapter(adapter); } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); menu.add(0, DELETE_ID, 0, R.string.menu_delete); } // Creates a new loader after the initLoader () call @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { String[] projection = { TodoTable.COLUMN_ID, TodoTable.COLUMN_SUMMARY }; CursorLoader cursorLoader = new CursorLoader(this, MyTodoContentProvider.CONTENT_URI, projection, null, null, null); return cursorLoader; } @Override public void onLoadFinished(Loader<Cursor> loader, Cursor data) { adapter.swapCursor(data); } @Override public void onLoaderReset(Loader<Cursor> loader) { // data is not available anymore, delete reference adapter.swapCursor(null); } }
TodoDetail.java
package com.example.loaders; import android.app.Activity; import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.text.TextUtils; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Spinner; import android.widget.Toast; public class TodoDetailActivity extends Activity { private Spinner mCategory; private EditText mTitleText; private EditText mBodyText; private Uri todoUri; @Override protected void onCreate(Bundle bundle) { super.onCreate(bundle); setContentView(R.layout.todo_edit); mCategory = (Spinner) findViewById(R.id.category); mTitleText = (EditText) findViewById(R.id.todo_edit_summary); mBodyText = (EditText) findViewById(R.id.todo_edit_description); Button confirmButton = (Button) findViewById(R.id.todo_edit_button); Bundle extras = getIntent().getExtras(); // Check from the saved Instance todoUri = (bundle == null) ? null : (Uri) bundle .getParcelable(MyTodoContentProvider.CONTENT_ITEM_TYPE); // Or passed from the other activity if (extras != null) { todoUri = extras .getParcelable(MyTodoContentProvider.CONTENT_ITEM_TYPE); fillData(todoUri); } confirmButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { if (TextUtils.isEmpty(mTitleText.getText().toString())) { makeToast(); } else { setResult(RESULT_OK); finish(); } } }); } private void fillData(Uri uri) { String[] projection = { TodoTable.COLUMN_SUMMARY, TodoTable.COLUMN_DESCRIPTION, TodoTable.COLUMN_CATEGORY }; Cursor cursor = getContentResolver().query(uri, projection, null, null, null); if (cursor != null) { cursor.moveToFirst(); String category = cursor.getString(cursor .getColumnIndexOrThrow(TodoTable.COLUMN_CATEGORY)); for (int i = 0; i < mCategory.getCount(); i++) { String s = (String) mCategory.getItemAtPosition(i); if (s.equalsIgnoreCase(category)) { mCategory.setSelection(i); } } mTitleText.setText(cursor.getString(cursor .getColumnIndexOrThrow(TodoTable.COLUMN_SUMMARY))); mBodyText.setText(cursor.getString(cursor .getColumnIndexOrThrow(TodoTable.COLUMN_DESCRIPTION))); // Always close the cursor cursor.close(); } } protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); saveState(); outState.putParcelable(MyTodoContentProvider.CONTENT_ITEM_TYPE, todoUri); } @Override protected void onPause() { super.onPause(); saveState(); } private void saveState() { String category = (String) mCategory.getSelectedItem(); String summary = mTitleText.getText().toString(); String description = mBodyText.getText().toString(); if (description.length() == 0 && summary.length() == 0) { return; } ContentValues values = new ContentValues(); values.put(TodoTable.COLUMN_CATEGORY, category); values.put(TodoTable.COLUMN_SUMMARY, summary); values.put(TodoTable.COLUMN_DESCRIPTION, description); if (todoUri == null) { // New todo todoUri = getContentResolver().insert( MyTodoContentProvider.CONTENT_URI, values); } else { // Update todo getContentResolver().update(todoUri, values, null, null); } } private void makeToast() { Toast.makeText(TodoDetailActivity.this, "Please maintain a summary", Toast.LENGTH_LONG).show(); } }
TodoTable.xml
package com.example.loaders; import android.database.sqlite.SQLiteDatabase; import android.util.Log; public class TodoTable { // Database table public static final String TABLE_TODO = "todo"; public static final String COLUMN_ID = "_id"; public static final String COLUMN_CATEGORY = "category"; public static final String COLUMN_SUMMARY = "summary"; public static final String COLUMN_DESCRIPTION = "description"; // Database creation SQL statement private static final String DATABASE_CREATE = "create table " + TABLE_TODO + "(" + COLUMN_ID + " integer primary key autoincrement, " + COLUMN_CATEGORY + " text not null, " + COLUMN_SUMMARY + " text not null," + COLUMN_DESCRIPTION + " text not null" + ");"; public static void onCreate(SQLiteDatabase database) { database.execSQL(DATABASE_CREATE); } public static void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) { Log.w(TodoTable.class.getName(), "Upgrading database from version " + oldVersion + " to " + newVersion + ", which will destroy all old data"); database.execSQL("DROP TABLE IF EXISTS " + TABLE_TODO); onCreate(database); } }