Skip to content

Commit

Permalink
1.14 Implement ContentProvider update() method
Browse files Browse the repository at this point in the history
  • Loading branch information
Beginning Android committed Aug 23, 2016
1 parent 6861be5 commit a1bcc0c
Showing 1 changed file with 64 additions and 2 deletions.
66 changes: 64 additions & 2 deletions app/src/main/java/com/example/android/pets/data/PetProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,69 @@ public int delete(Uri uri, String s, String[] strings) {
}

@Override
public int update(Uri uri, ContentValues contentValues, String s, String[] strings) {
return 0;
public int update(Uri uri, ContentValues contentValues, String selection,
String[] selectionArgs) {
final int match = sUriMatcher.match(uri);
switch (match) {
case PETS:
return updatePet(uri, contentValues, selection, selectionArgs);
case PET_ID:
// For the PET_ID code, extract out the ID from the URI,
// so we know which row to update. Selection will be "_id=?" and selection
// arguments will be a String array containing the actual ID.
selection = PetEntry._ID + "=?";

This comment has been minimized.

Copy link
@yiwp9

yiwp9 Sep 14, 2017

我想问下 , 在updata中将selection 赋值为 petEntry._ID + "=?" , 并且将selectionArgs赋值为URI中传入的Id值 . 那么是不是在EditActivity中调用update的时候始终都不需要selection 和selectionArgs 这两个参数呀 . 谢谢 .

This comment has been minimized.

Copy link
@yellowf7ash

yellowf7ash Sep 7, 2018

I believe this is an English site

selectionArgs = new String[] { String.valueOf(ContentUris.parseId(uri)) };
return updatePet(uri, contentValues, selection, selectionArgs);
default:
throw new IllegalArgumentException("Update is not supported for " + uri);
}
}

/**
* Update pets in the database with the given content values. Apply the changes to the rows
* specified in the selection and selection arguments (which could be 0 or 1 or more pets).
* Return the number of rows that were successfully updated.
*/
private int updatePet(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
// If the {@link PetEntry#COLUMN_PET_NAME} key is present,

This comment has been minimized.

Copy link
@schv09

schv09 Jun 22, 2017

The uri paramter is never used in this method, we should leave it out.

This comment has been minimized.

Copy link
@randomdev-731

randomdev-731 Aug 1, 2017

The uri is used in lesson four.

This comment has been minimized.

Copy link
@schv09

schv09 Aug 1, 2017

Yeah, that's right, I noticed later. Thanks 👍.

This comment has been minimized.

Copy link
@Stizzler

Stizzler Dec 3, 2017

you can make a helper method for sanity check:

private void sanityCheck(ContentValues values, Boolean update){

        // Check that the name is not null
        String name = values.getAsString(PetEntry.COLUMN_PET_NAME);
        if (name == null) {
            if (update && !values.containsKey(PetEntry.COLUMN_PET_NAME)) {}
            else throw new IllegalArgumentException("Pet requires a name");
        }
        //Check that the gender is not null
        Integer gender = values.getAsInteger(PetEntry.COLUMN_PET_GENDER);
        if (gender == null || !PetEntry.isValidGender(gender)) {
            if (update && !values.containsKey(PetEntry.COLUMN_PET_GENDER)) {}
            else throw new IllegalArgumentException("Pet requires a gender");
        }
        //Check that the weight is not null
        Integer weight = values.getAsInteger(PetEntry.COLUMN_PET_WEIGHT);
        if (weight < 0 || weight == null ) {
            if (update && !values.containsKey(PetEntry.COLUMN_PET_WEIGHT)) {}
            else throw new IllegalArgumentException("Pet requires a weight");
        }

    }

Then call in insert:

sanityCheck(values, false);

and in update:

sanityCheck(values, true);


        // If there are no values to update, then don't try to update the database
        if (values.size() == 0) {
            return 0;
        }

This comment has been minimized.

Copy link
@shilpamahendriker

shilpamahendriker Aug 22, 2018

That is a good thought, it makes code more readable

// check that the name value is not null.
if (values.containsKey(PetEntry.COLUMN_PET_NAME)) {
String name = values.getAsString(PetEntry.COLUMN_PET_NAME);
if (name == null) {
throw new IllegalArgumentException("Pet requires a name");
}
}

// If the {@link PetEntry#COLUMN_PET_GENDER} key is present,
// check that the gender value is valid.
if (values.containsKey(PetEntry.COLUMN_PET_GENDER)) {
Integer gender = values.getAsInteger(PetEntry.COLUMN_PET_GENDER);

This comment has been minimized.

Copy link
@samsofa

samsofa Dec 14, 2019

could you please tell me why we use Integer gender not int gender?

Integer gender = values.getAsInteger(PetEntry.COLUMN_PET_GENDER);

This comment has been minimized.

Copy link
@Hasanabbas

Hasanabbas Jun 20, 2020

I guess it's because the ContentProvider will return the value as an Integer object instead of the int primitive type. If you change it to int that will work as well

This comment has been minimized.

Copy link
@umeransari91

umeransari91 Jul 15, 2020

I guess because you cannot compare a primitive type to a null in the next line therefore you need an Object type i.e. Integer in this case.

if (gender == null || !PetEntry.isValidGender(gender)) {

This comment has been minimized.

Copy link
@otkrivashkin

otkrivashkin Nov 8, 2016

Where is isValidGender(gender) ?

This comment has been minimized.

Copy link
@mahye82

mahye82 Nov 17, 2016

@otkrivashkin isValidGender(int gender) was defined in PetContract.PetEntry during a previous commit.

You needed isValidGender(int gender) for the step where you had to add data validation for the insert() method.

This comment has been minimized.

Copy link
@gargvarsha

gargvarsha Aug 5, 2017

@mahye82 will u plz provide the code for isValidGender(gender)?/???

This comment has been minimized.

Copy link
@randomdev-731

randomdev-731 Aug 6, 2017

public static boolean isValidGender(int gender) {
         if (gender == GENDER_UNKNOWN || gender == GENDER_MALE || gender == GENDER_FEMALE) {
                return true;
            }
          return false;
        }

also this is the reference - https://github.com/udacity/ud845-Pets/blob/lesson-three/app/src/main/java/com/example/android/pets/data/PetContract.java

This comment has been minimized.

Copy link
@gargvarsha

gargvarsha via email Aug 16, 2017

This comment has been minimized.

Copy link
@nikhilsutar123

nikhilsutar123 Oct 22, 2019

Where is isValidGender(gender) ?

Where is isValidGender(gender) ?

In the PetsEntry class

throw new IllegalArgumentException("Pet requires valid gender");
}
}

// If the {@link PetEntry#COLUMN_PET_WEIGHT} key is present,
// check that the weight value is valid.
if (values.containsKey(PetEntry.COLUMN_PET_WEIGHT)) {
// Check that the weight is greater than or equal to 0 kg
Integer weight = values.getAsInteger(PetEntry.COLUMN_PET_WEIGHT);
if (weight != null && weight < 0) {

This comment has been minimized.

Copy link
@jlin27

jlin27 Nov 21, 2016

Contributor

Instructor Note: The (weight != null) part of the logic in line 231 is redundant and we should throw an exception for either of those situations. In other words, the weight check should throw an exception if weight is null OR if weight is less than 0. Code should be if (weight == null || weight < 0)

This comment has been minimized.

Copy link
@MohamedMohy9192

MohamedMohy9192 Mar 15, 2017

data base accept 0 value for weight by default so we cant throw exception if the input in 0

This comment has been minimized.

Copy link
@owolabiezekiel

owolabiezekiel Oct 6, 2017

What if the input is less than 0 say -1

This comment has been minimized.

Copy link
@magician20

magician20 Oct 25, 2017

I believe the problem not about null ,but it's about what type of data we pass int or Integer (Autoboxing and Unboxing happen automatic ) :
An int is not null, it may be 0 if not initialized.
an Integer can be null.

This comment has been minimized.

Copy link
@shining-cat

shining-cat Nov 21, 2017

this line is the same in insertPet and updatePet methods, but since weight is an Integer, and not an int, weight could be a null object (as well as gender could be), but with
if (weight != null && weight < 0)
we would throw no exception and the sanitization would fail.
I also coded
if (weight == null || weight < 0)
first, then stumbled upon this line in the provided code, but I do not understand how the given version here could be correct...

This comment has been minimized.

Copy link
@randomdev-731

randomdev-731 Nov 21, 2017

@shining-cat
Check case 1: (weight != null && weight < 0)
This is a faulty validation rule because this only checks if the pet weight is a positive integer while ignoring null value cases. As @jlin27 pointed out, the first portion of the rule (weight != null) is merely redundant because negative numbers are obviously not null. It is easy to explain with an example, consider that an user has entered -1 for pet weight, by this virtue the weight variable is not null albeit negative. So, it gets caught by the validation rule and as a result -1 is not stored. Hence, guarding only against negative integers. Consequently, null values completely escape this validation rule.

Check case 2: (weight == null || weight < 0)
Note the use of the or operator. As you can see, if the weight is either null or an negative integer the value is caught by the validation rule and the below IllegalArgumentException is thrown.

Hope this helped, if not, let me know.

This comment has been minimized.

Copy link
@shining-cat

shining-cat Nov 27, 2017

@SrChip15
Exactly as I understood it, I just feared I had missed something in the proposed code, since the samples are usually corrected quite quickly and this one still isn't.
Thank you very much!

This comment has been minimized.

Copy link
@nedgit

nedgit Oct 15, 2018

surely the sanity check logic should be
if (weight == null || weight <= 0) {
throw new IllegalArgumentException("Pet requires valid weight");

throw new IllegalArgumentException("Pet requires valid weight");
}
}

// No need to check the breed, any value is valid (including null).

// If there are no values to update, then don't try to update the database
if (values.size() == 0) {
return 0;
}

This comment has been minimized.

Copy link
@jlin27

jlin27 Nov 21, 2016

Contributor

Instructor Note: This snippet of code (lines 238-240) that check if there are no values to update would logically be more efficient if placed before the data validation (rather than after as it currently exists).

This comment has been minimized.

Copy link
@faustodc

faustodc Feb 12, 2018

It totally would, it's redundant to check if the values size is 0 when you already determined that it isn't.
If values successfully passed all the if tests, then it can't be 0.

This comment has been minimized.

Copy link
@alexejmamaev

alexejmamaev Mar 6, 2018

The code works as it is. Even if values.size() == 0 the app goes down and checks for the empty values and if they are it skips operation on database which saves memory. BUT there is no need to go through all those sanity checks if the values.size() == 0. So I totally agree with you guys. This check should be the first in the updatePet method

This comment has been minimized.

Copy link
@Akash1234saini

Akash1234saini May 1, 2020

Yes i was also thinking like this if we will check it first then there is no need to check for sanity,
### Right?
@jlin27


// Otherwise, get writeable database to update the data
SQLiteDatabase database = mDbHelper.getWritableDatabase();

// Returns the number of database rows affected by the update statement
return database.update(PetEntry.TABLE_NAME, values, selection, selectionArgs);
}
}

16 comments on commit a1bcc0c

@luismu78
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is the notifyChange() we should be calling after updating?

@PraneethYerra
Copy link

@PraneethYerra PraneethYerra commented on a1bcc0c May 24, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this the code for the isValidGEnder
i added it in the PetContract class

public static boolean isValidGender(Integer gender) {
if(gender !=0||gender !=1||gender !=1)
return false;
else
return true;

    }

@aswinawien
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wait you should add the notifyChange() too ?

@nonevietnam
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is the BREED?

@moiscye
Copy link

@moiscye moiscye commented on a1bcc0c Feb 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello I have the following problem :(

02-09 01:41:06.367 3614-3614/? E/ActivityThread: Failed to find provider info for com.example.android.pets
02-09 01:41:06.368 3614-3614/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.android.pets, PID: 3614
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.android.pets/com.example.android.pets.CatalogActivity}: java.lang.NullPointerException: Attempt to invoke interface method 'void android.database.Cursor.close()' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'void android.database.Cursor.close()' on a null object reference
at com.example.android.pets.CatalogActivity.displayDatabaseInfo(CatalogActivity.java:125)
at com.example.android.pets.CatalogActivity.onStart(CatalogActivity.java:56)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1237)
at android.app.Activity.performStart(Activity.java:6253)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2379)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476) 
at android.app.ActivityThread.-wrap11(ActivityThread.java) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:148) 
at android.app.ActivityThread.main(ActivityThread.java:5417) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 

@randomdev-731
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@moiscye did you declare your content provider in the manifest?

@moiscye
Copy link

@moiscye moiscye commented on a1bcc0c Feb 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, I did. It was all there. I rebuild the project and now it's working. cheers

@RuslanPrimak
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (values.containsKey(PetEntry.COLUMN_PET_WEIGHT)) {
        // Check that the weight is greater than or equal to 0 kg
        Integer weight = values.getAsInteger(PetEntry.COLUMN_PET_WEIGHT);
        if (weight != null && weight < 0) {
            throw new IllegalArgumentException("Pet requires valid weight");
        }
    }

Could be simplified to

Integer weight = values.getAsInteger(PetEntry.COLUMN_PET_WEIGHT);
        if (weight != null && weight < 0) {
            throw new IllegalArgumentException("Pet requires valid weight");
        }

@RuslanPrimak
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

    switch (match) {
        case PETS:
            return updatePet(uri, contentValues, selection, selectionArgs);
        case PET_ID:
            // For the PET_ID code, extract out the ID from the URI,
            // so we know which row to update. Selection will be "_id=?" and selection
            // arguments will be a String array containing the actual ID.
            selection = PetEntry._ID + "=?";
            selectionArgs = new String[] { String.valueOf(ContentUris.parseId(uri)) };
            return updatePet(uri, contentValues, selection, selectionArgs);
        default:
            throw new IllegalArgumentException("Update is not supported for " + uri);
    }

Could be simplified to

    switch (match) {
            case PET_ID:
                // For the PET_ID code, extract out the ID from the URI,
                // so we know which row to update. Selection will be "_id=?" and selection
                // arguments will be a String array containing the actual ID.
                selection = PetEntry._ID + "=?";
                selectionArgs = new String[] { String.valueOf(ContentUris.parseId(uri)) };
            case PETS:
                return updatePet(uri, values, selection, selectionArgs);
            default:
                throw new IllegalArgumentException("Update is not supported for " + uri);
        }

@RuslanPrimak
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is my version of the helper method for validation:

   /**
     * Validates the pet values before insertion
     */
    private void ValidatePetValues(@NonNull ContentValues values) {
        ValidatePetValues(values, true);
    }

    /**
     * Validates the pet values before insertion or updating
     */
    private void ValidatePetValues(@NonNull ContentValues values, boolean isInsert) {
        // Check that the name is not null
        if (isInsert || values.containsKey(PetEntry.COLUMN_PET_NAME)) {
            String name = values.getAsString(PetEntry.COLUMN_PET_NAME);
            if (name.isEmpty()) {
                throw new IllegalArgumentException("Pet requires a name");
            }
        }

        // Check that the gender is valid
        if (isInsert || values.containsKey(PetEntry.COLUMN_PET_GENDER)) {
            Integer gender = values.getAsInteger(PetEntry.COLUMN_PET_GENDER);
            if (gender == null || !PetEntry.isValidGender(gender)) {
                throw new IllegalArgumentException("Pet requires valid gender");
            }
        }

        // If the weight is provided, check that it's greater than or equal to 0 kg
        Integer weight = values.getAsInteger(PetEntry.COLUMN_PET_WEIGHT);
        if (weight != null && weight < 0) {
            throw new IllegalArgumentException("Pet requires valid weight");
        }

        // No need to check the breed, any value is valid (including null).
    }

@Babadzhanov
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was useful! 👍

@TheGoldenMan99
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RuslanPrimak
Why do I need the first ValidatePetValues method? Looks to me like the second one can handle both insertion and updating.

@mouad-hachemi
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why using uri as input paremeter in update helper method and we don't even use it

@01knowyourself
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm getting below error and unable to proceed further in class. Please help me

2020-08-11 15:52:54.670 13849-13849/com.beenumandroiddevelopers.petsapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.beenumandroiddevelopers.petsapp, PID: 13849
java.lang.NullPointerException: Attempt to invoke interface method 'void android.database.Cursor.close()' on a null object reference
at com.beenumandroiddevelopers.petsapp.CatalogActivity.displayDatabaseInfo(CatalogActivity.java:110)
at com.beenumandroiddevelopers.petsapp.CatalogActivity.onStart(CatalogActivity.java:41)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1435)
at android.app.Activity.performStart(Activity.java:8008)
at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3382)
at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221)
at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2049)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7523)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:941)
2020-08-11 15:52:54.956 13849-13849/com.beenumandroiddevelopers.petsapp I/Process: Sending signal. PID: 13849 SIG: 9

@umeransari91
Copy link

@umeransari91 umeransari91 commented on a1bcc0c Aug 11, 2020 via email

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@01knowyourself
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello sir. You are trying to close a cursor that was never initialized. Get Outlook for Androidhttps://aka.ms/ghei36

________________________________ From: 01knowyourself [email protected] Sent: Tuesday, 11 August 2020, 15:24 To: udacity/ud845-Pets Cc: umeransari91; Comment Subject: Re: [udacity/ud845-Pets] 1.14 Implement ContentProvider update() method (a1bcc0c) I'm getting below error and unable to proceed further in class. Please help me 2020-08-11 15:52:54.670 13849-13849/com.beenumandroiddevelopers.petsapp E/AndroidRuntime: FATAL EXCEPTION: main Process: com.beenumandroiddevelopers.petsapp, PID: 13849 java.lang.NullPointerException: Attempt to invoke interface method 'void android.database.Cursor.close()' on a null object reference at com.beenumandroiddevelopers.petsapp.CatalogActivity.displayDatabaseInfo(CatalogActivity.java:110) at com.beenumandroiddevelopers.petsapp.CatalogActivity.onStart(CatalogActivity.java:41) at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1435) at android.app.Activity.performStart(Activity.java:8008) at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3382) at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221) at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201) at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2049) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:223) at android.app.ActivityThread.main(ActivityThread.java:7523) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:941) 2020-08-11 15:52:54.956 13849-13849/com.beenumandroiddevelopers.petsapp I/Process: Sending signal. PID: 13849 SIG: 9 — You are receiving this because you commented. Reply to this email directly, view it on GitHub<a1bcc0c#commitcomment-41364960>, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AKZERWVSA6WU2V2TF3KZ5YDSAEL53ANCNFSM4CVSFHEQ.

My code is in Sync with the code in Git Hub, i don't know why am i getting this error. Please help as i'm stuck at this point and unable to proceed with the course.

Please sign in to comment.