Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lesson four #6

Open
wants to merge 23 commits into
base: lesson-two
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
7d0e356
1.7 Add ContentProvider
Jul 19, 2016
07f3866
1.8 Add constants for pet content URIs
Jul 21, 2016
b34ac1f
1.9 Add UriMatcher to ContentProvider
Jul 19, 2016
b295107
1.10 Implement ContentProvider query() method
Jul 19, 2016
bf44f26
1.11 Query the provider using the pet content URI
Jul 21, 2016
c64812e
1.12 Implement and use ContentProvider insert() method
Jul 20, 2016
6861be5
1.13 Add input validation to ContentProvider insert() method
Jul 22, 2016
a1bcc0c
1.14 Implement ContentProvider update() method
Jul 20, 2016
81fe10a
1.15 Implement ContentProvider delete() method
Jul 20, 2016
a244b5a
1.16 Implement ContentProvider getType() method
Jul 20, 2016
feca5f2
1.17 Create PetCursorAdapter to display list of pets in ListView
Jul 25, 2016
636e6bd
1.18 Add empty view to the ListView
Jul 27, 2016
dec30b1
1.19 Switch to CursorLoader
Jul 27, 2016
e587771
1.20 Modify ContentProvider so Loader refreshes data automatically
Jul 28, 2016
c0d42fb
1.21 Clicking on list item opens EditorActivity
Jul 28, 2016
8d4b875
1.22 Load existing pet data from database
Jul 28, 2016
20d0524
1.23 Save changes to existing pet if it already exists
Aug 2, 2016
6a82f79
1.24 Prevent crash with blank editor
Aug 2, 2016
bea7d90
1.25 Warn user about losing unsaved changes
Aug 2, 2016
d90609a
1.26 Hide delete menu option for new pets
Aug 4, 2016
c1a4418
1.27 Delete pet from editor menu item
Aug 2, 2016
311f80d
1.28 Delete all pets from catalog menu item
Aug 2, 2016
d942c19
1.29 Display “Unknown breed” for pets without breed
Aug 4, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,17 @@
</activity>
<activity
android:name=".EditorActivity"
android:label="@string/editor_activity_title_new_pet"
android:theme="@style/EditorTheme"
android:parentActivityName=".CatalogActivity" >
<!-- Parent activity meta-data to support 4.0 and lower -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".CatalogActivity" />
</activity>
<provider
android:name=".data.PetProvider"
android:authorities="com.example.android.pets"
android:exported="false" />
</application>

</manifest>
177 changes: 80 additions & 97 deletions app/src/main/java/com/example/android/pets/CatalogActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,36 @@
*/
package com.example.android.pets;

import android.app.LoaderManager;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.CursorLoader;
import android.content.Intent;
import android.content.Loader;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.AdapterView;
import android.widget.ListView;

import com.example.android.pets.data.PetContract.PetEntry;
import com.example.android.pets.data.PetDbHelper;

/**
* Displays list of pets that were entered and stored in the app.
*/
public class CatalogActivity extends AppCompatActivity {
public class CatalogActivity extends AppCompatActivity implements
LoaderManager.LoaderCallbacks<Cursor> {

/** Database helper that will provide us access to the database */
private PetDbHelper mDbHelper;
/** Identifier for the pet data loader */
private static final int PET_LOADER = 0;

/** Adapter for the ListView */
PetCursorAdapter mCursorAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
Expand All @@ -53,98 +61,48 @@ public void onClick(View view) {
}
});

// To access our database, we instantiate our subclass of SQLiteOpenHelper
// and pass the context, which is the current activity.
mDbHelper = new PetDbHelper(this);
}
// Find the ListView which will be populated with the pet data
ListView petListView = (ListView) findViewById(R.id.list);

@Override
protected void onStart() {
super.onStart();
displayDatabaseInfo();
}
// Find and set empty view on the ListView, so that it only shows when the list has 0 items.
View emptyView = findViewById(R.id.empty_view);
petListView.setEmptyView(emptyView);

/**
* Temporary helper method to display information in the onscreen TextView about the state of
* the pets database.
*/
private void displayDatabaseInfo() {
// Create and/or open a database to read from it
SQLiteDatabase db = mDbHelper.getReadableDatabase();
// Setup an Adapter to create a list item for each row of pet data in the Cursor.
// There is no pet data yet (until the loader finishes) so pass in null for the Cursor.
mCursorAdapter = new PetCursorAdapter(this, null);
petListView.setAdapter(mCursorAdapter);

// Define a projection that specifies which columns from the database
// you will actually use after this query.
String[] projection = {
PetEntry._ID,
PetEntry.COLUMN_PET_NAME,
PetEntry.COLUMN_PET_BREED,
PetEntry.COLUMN_PET_GENDER,
PetEntry.COLUMN_PET_WEIGHT };

// Perform a query on the pets table
Cursor cursor = db.query(
PetEntry.TABLE_NAME, // The table to query
projection, // The columns to return
null, // The columns for the WHERE clause
null, // The values for the WHERE clause
null, // Don't group the rows
null, // Don't filter by row groups
null); // The sort order

TextView displayView = (TextView) findViewById(R.id.text_view_pet);

try {
// Create a header in the Text View that looks like this:
//
// The pets table contains <number of rows in Cursor> pets.
// _id - name - breed - gender - weight
//
// In the while loop below, iterate through the rows of the cursor and display
// the information from each column in this order.
displayView.setText("The pets table contains " + cursor.getCount() + " pets.\n\n");
displayView.append(PetEntry._ID + " - " +
PetEntry.COLUMN_PET_NAME + " - " +
PetEntry.COLUMN_PET_BREED + " - " +
PetEntry.COLUMN_PET_GENDER + " - " +
PetEntry.COLUMN_PET_WEIGHT + "\n");

// Figure out the index of each column
int idColumnIndex = cursor.getColumnIndex(PetEntry._ID);
int nameColumnIndex = cursor.getColumnIndex(PetEntry.COLUMN_PET_NAME);
int breedColumnIndex = cursor.getColumnIndex(PetEntry.COLUMN_PET_BREED);
int genderColumnIndex = cursor.getColumnIndex(PetEntry.COLUMN_PET_GENDER);
int weightColumnIndex = cursor.getColumnIndex(PetEntry.COLUMN_PET_WEIGHT);

// Iterate through all the returned rows in the cursor
while (cursor.moveToNext()) {
// Use that index to extract the String or Int value of the word
// at the current row the cursor is on.
int currentID = cursor.getInt(idColumnIndex);
String currentName = cursor.getString(nameColumnIndex);
String currentBreed = cursor.getString(breedColumnIndex);
int currentGender = cursor.getInt(genderColumnIndex);
int currentWeight = cursor.getInt(weightColumnIndex);
// Display the values from each column of the current row in the cursor in the TextView
displayView.append(("\n" + currentID + " - " +
currentName + " - " +
currentBreed + " - " +
currentGender + " - " +
currentWeight));
// Setup the item click listener
petListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
// Create new intent to go to {@link EditorActivity}
Intent intent = new Intent(CatalogActivity.this, EditorActivity.class);

// Form the content URI that represents the specific pet that was clicked on,
// by appending the "id" (passed as input to this method) onto the
// {@link PetEntry#CONTENT_URI}.
// For example, the URI would be "content://com.example.android.pets/pets/2"
// if the pet with ID 2 was clicked on.
Uri currentPetUri = ContentUris.withAppendedId(PetEntry.CONTENT_URI, id);

// Set the URI on the data field of the intent
intent.setData(currentPetUri);

// Launch the {@link EditorActivity} to display the data for the current pet.
startActivity(intent);
}
} finally {
// Always close the cursor when you're done reading from it. This releases all its
// resources and makes it invalid.
cursor.close();
}
});

// Kick off the loader
getLoaderManager().initLoader(PET_LOADER, null, this);
}

/**
* Helper method to insert hardcoded pet data into the database. For debugging purposes only.
*/
private void insertPet() {
// Gets the database in write mode
SQLiteDatabase db = mDbHelper.getWritableDatabase();

// Create a ContentValues object where column names are the keys,
// and Toto's pet attributes are the values.
ContentValues values = new ContentValues();
Expand All @@ -153,14 +111,11 @@ private void insertPet() {
values.put(PetEntry.COLUMN_PET_GENDER, PetEntry.GENDER_MALE);
values.put(PetEntry.COLUMN_PET_WEIGHT, 7);

// Insert a new row for Toto in the database, returning the ID of that new row.
// The first argument for db.insert() is the pets table name.
// The second argument provides the name of a column in which the framework
// can insert NULL in the event that the ContentValues is empty (if
// this is set to "null", then the framework will not insert a row when
// there are no values).
// The third argument is the ContentValues object containing the info for Toto.
long newRowId = db.insert(PetEntry.TABLE_NAME, null, values);
// Insert a new row for Toto into the provider using the ContentResolver.
// Use the {@link PetEntry#CONTENT_URI} to indicate that we want to insert
// into the pets database table.
// Receive the new content URI that will allow us to access Toto's data in the future.
Uri newUri = getContentResolver().insert(PetEntry.CONTENT_URI, values);
}

@Override
Expand All @@ -178,7 +133,6 @@ public boolean onOptionsItemSelected(MenuItem item) {
// Respond to a click on the "Insert dummy data" menu option
case R.id.action_insert_dummy_data:
insertPet();
displayDatabaseInfo();
return true;
// Respond to a click on the "Delete all entries" menu option
case R.id.action_delete_all_entries:
Expand All @@ -187,4 +141,33 @@ public boolean onOptionsItemSelected(MenuItem item) {
}
return super.onOptionsItemSelected(item);
}

@Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
// Define a projection that specifies the columns from the table we care about.
String[] projection = {
PetEntry._ID,
PetEntry.COLUMN_PET_NAME,
PetEntry.COLUMN_PET_BREED };

// This loader will execute the ContentProvider's query method on a background thread
return new CursorLoader(this, // Parent activity context
PetEntry.CONTENT_URI, // Provider content URI to query
projection, // Columns to include in the resulting Cursor
null, // No selection clause
null, // No selection arguments
null); // Default sort order
}

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Update {@link PetCursorAdapter} with this new cursor containing updated pet data
mCursorAdapter.swapCursor(data);
}

@Override
public void onLoaderReset(Loader<Cursor> loader) {
// Callback called when the data needs to be deleted
mCursorAdapter.swapCursor(null);
}
}
Loading