Skip to content

Commit

Permalink
1.22 Load existing pet data from database
Browse files Browse the repository at this point in the history
  • Loading branch information
Beginning Android committed Aug 23, 2016
1 parent c0d42fb commit 8d4b875
Showing 1 changed file with 91 additions and 3 deletions.
94 changes: 91 additions & 3 deletions app/src/main/java/com/example/android/pets/EditorActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@
*/
package com.example.android.pets;

import android.app.LoaderManager;
import android.content.ContentValues;
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.support.v4.app.NavUtils;
Expand All @@ -36,7 +40,14 @@
/**
* Allows user to create a new pet or edit an existing one.
*/
public class EditorActivity extends AppCompatActivity {
public class EditorActivity extends AppCompatActivity implements
LoaderManager.LoaderCallbacks<Cursor> {

/** Identifier for the pet data loader */
private static final int EXISTING_PET_LOADER = 0;

/** Content URI for the existing pet (null if it's a new pet) */
private Uri mCurrentPetUri;

/** EditText field to enter the pet's name */
private EditText mNameEditText;
Expand Down Expand Up @@ -65,16 +76,20 @@ protected void onCreate(Bundle savedInstanceState) {
// Examine the intent that was used to launch this activity,
// in order to figure out if we're creating a new pet or editing an existing one.
Intent intent = getIntent();
Uri currentPetUri = intent.getData();
mCurrentPetUri = intent.getData();

This comment has been minimized.

Copy link
@TinaT2

TinaT2 Sep 26, 2017

I have problem in this line of code. My code won't work because the query which this URI makes, is not valid. Instead I've written this code: (uri = mCurrentPetUri in my code)

@OverRide
public Loader onCreateLoader(int id, Bundle args) {
uri = getIntent().getData();
String selection = PetEntry._ID+ "=?";
String[] selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
String[] projection = {
PetEntry._ID,
PetEntry.COLUMN_PET_NAME,
PetEntry.COLUMN_PET_BREED,
PetEntry.COLUMN_PET_GENDER,
PetEntry.COLUMN_PET_WEIGHT };
CursorLoader loader = new CursorLoader(this, PetEntry.CONTENT_URI, projection, selection,selectionArgs , null);
return loader;
}

Why mCurrentPetUri does not works?

This comment has been minimized.

Copy link
@th3oxen

th3oxen Sep 26, 2017

Can you be more specific?

This comment has been minimized.

Copy link
@owolabiezekiel

owolabiezekiel Oct 9, 2017

uri = getIntent().getData(). the variable uri here is of which data type?

This comment has been minimized.

Copy link
@kwhitejr

kwhitejr Nov 15, 2017

You need to assign getIntent().getData() to the globally declared Uri, in this case mCurrentPetUri and not uri; though if you gave your global variable a different name, use that.


// If the intent DOES NOT contain a pet content URI, then we know that we are
// creating a new pet.
if (currentPetUri == null) {
if (mCurrentPetUri == null) {
// This is a new pet, so change the app bar to say "Add a Pet"
setTitle(getString(R.string.editor_activity_title_new_pet));
} else {
// Otherwise this is an existing pet, so change app bar to say "Edit Pet"
setTitle(getString(R.string.editor_activity_title_edit_pet));

// Initialize a loader to read the pet data from the database
// and display the current values in the editor
getLoaderManager().initLoader(EXISTING_PET_LOADER, null, this);

This comment has been minimized.

Copy link
@chrisjeremi98

chrisjeremi98 Jan 15, 2018

Got problem with getLoaderManager().initLoader(EXISTING_PET_LOADER, null, this);
it always show wrong 3rd argument type

This comment has been minimized.

Copy link
@Thanassiz

Thanassiz Jan 18, 2018

use getSupportLoaderManager()
getSupportLoaderManager().initLoader(EXISTING_PET_LOADER, null, this);

This comment has been minimized.

Copy link
@Basem10

Basem10 Feb 23, 2019

But getSupportLoaderManager() is deprecated

This comment has been minimized.

Copy link
@chillmonk2

chillmonk2 Jun 6, 2019

In import files remove the v4 and and include only android.app.<..>;

This comment has been minimized.

Copy link
@zxkfall

zxkfall Mar 14, 2020

Error:
java.lang.RuntimeException: An error occurred while executing doInBackground()
Caused by: java.lang.NullPointerException: uri

The program will crash when I click the floating button,.Is there any simple way to replace getSupportLoaderManager().initLoader(EXISTING_PET_LOADER, null, this); or getLoaderManager().initLoader(EXISTING_PET_LOADER, null, this);?

This comment has been minimized.

Copy link
@soumahaka

soumahaka Jun 12, 2020

Error:
java.lang.RuntimeException: An error occurred while executing doInBackground()
Caused by: java.lang.NullPointerException: uri

The program will crash when I click the floating button,.Is there any simple way to replace getSupportLoaderManager().initLoader(EXISTING_PET_LOADER, null, this); or getLoaderManager().initLoader(EXISTING_PET_LOADER, null, this);?

How did you solve the problem bro ?

This comment has been minimized.

Copy link
@zxkfall

zxkfall Jun 13, 2020

//This is outdated, so it needs to be commented out, it can't be used in 28 and above
// getLoaderManager().initLoader(PET_LOADER, null, this);
//It can replace with
LoaderManager.getInstance(this).initLoader(PET_LOADER,null,this);

This comment has been minimized.

Copy link
@soumahaka

soumahaka Jun 18, 2020

//This is outdated, so it needs to be commented out, it can't be used in 28 and above
// getLoaderManager().initLoader(PET_LOADER, null, this);
//It can replace with
LoaderManager.getInstance(this).initLoader(PET_LOADER,null,this);

Thank you brother

This comment has been minimized.

Copy link
@KushanTharaka97

KushanTharaka97 Jul 10, 2020

Ya previous two
-getSupportLoaderManager();
-getSupportLoaderManager().initLoader(EXISTING_PET_LOADER, null, this);
are now out dated
In 2020, we have to use that as
LoaderManager.getInstance(this).initLoader(PET_LOADER, null, this);

This comment has been minimized.

Copy link
@CashatSD2020

CashatSD2020 Sep 15, 2020

but this yet is not working with me , the IDE tell me to create this method >>getInstance() ?!

This comment has been minimized.

Copy link
@WANYUTONG

WANYUTONG Sep 18, 2020

Error:
java.lang.RuntimeException: An error occurred while executing doInBackground()
Caused by: java.lang.NullPointerException: uri
The program will crash when I click the floating button,.Is there any simple way to replace getSupportLoaderManager().initLoader(EXISTING_PET_LOADER, null, this); or getLoaderManager().initLoader(EXISTING_PET_LOADER, null, this);?

How did you solve the problem bro ?

use the statement listed below:
LoaderManager.getInstance(this).initLoader(PET_LOADER,null,this);

This comment has been minimized.

Copy link
@gulshanpatidar

gulshanpatidar Jan 8, 2021

but this yet is not working with me , the IDE tell me to create this method >>getInstance() ?!

did you got any solution?

This comment has been minimized.

Copy link
@Yogesh-droid-spec

Yogesh-droid-spec Feb 11, 2021

but this yet is not working with me , the IDE tell me to create this method >>getInstance() ?!

so you got any solution of this error(im stuck here because of this!!

}

// Find all relevant views that we will need to read user input from
Expand Down Expand Up @@ -190,4 +205,77 @@ public boolean onOptionsItemSelected(MenuItem item) {
}
return super.onOptionsItemSelected(item);
}

@Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
// Since the editor shows all pet attributes, define a projection that contains
// all columns from the pet table
String[] projection = {
PetEntry._ID,
PetEntry.COLUMN_PET_NAME,
PetEntry.COLUMN_PET_BREED,
PetEntry.COLUMN_PET_GENDER,
PetEntry.COLUMN_PET_WEIGHT };

This comment has been minimized.

Copy link
@alexejmamaev

alexejmamaev Mar 14, 2018

Android documentation says for projection: "//The array of columns to return (pass null to get all)". Since we need all attributes we may omit this snippet and pass null directly when we return a new CursorLoader.

This comment has been minimized.

Copy link
@KDNY

KDNY Nov 14, 2018

I agree.

// This loader will execute the ContentProvider's query method on a background thread
return new CursorLoader(this, // Parent activity context
mCurrentPetUri, // Query the content URI for the current pet

This comment has been minimized.

Copy link
@atarancon

atarancon Jul 15, 2017

I get all the pets in the table even though i doubled checked my uri was for a specific pet with the log Tag
content://com.example.android.pets/pets/2

This comment has been minimized.

Copy link
@azzumw

azzumw May 20, 2018

get an error: incompatible return type. Required: android.support.v4.content.Loader
Found: content.Loader

This comment has been minimized.

Copy link
@Babadzhanov

Babadzhanov Jun 5, 2018

@azzumw you have imported the wrong Loader !! Where imports are at the top of the file change the 'Found' with the 'Required' and you are good to go! 👍

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 cursor) {
// Bail early if the cursor is null or there is less than 1 row in the cursor
if (cursor == null || cursor.getCount() < 1) {
return;
}

// Proceed with moving to the first row of the cursor and reading data from it
// (This should be the only row in the cursor)
if (cursor.moveToFirst()) {

This comment has been minimized.

Copy link
@karkinissan

karkinissan Jun 23, 2017

Do we really need this when we're already checking if the cursor is null or less than 1? Wont this line always be true?

This comment has been minimized.

Copy link
@faustodc

faustodc Feb 16, 2018

Yeah, we don't, also if cursor.getCount () < 1 is true it means it's null right? It can't be a 0 size cursor and still be considered not null.

This comment has been minimized.

Copy link
@alexejmamaev

alexejmamaev Mar 14, 2018

Not exactly. The Cursor is not null when cursor.getCount () < 1. It is just empty.

This comment has been minimized.

Copy link
@AbdallahShaqrah

AbdallahShaqrah Sep 28, 2018

now when i press the fab button the app crash ! so whats the problem

// Find the columns of pet attributes that we're interested in
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);

// Extract out the value from the Cursor for the given column index
String name = cursor.getString(nameColumnIndex);
String breed = cursor.getString(breedColumnIndex);
int gender = cursor.getInt(genderColumnIndex);
int weight = cursor.getInt(weightColumnIndex);

// Update the views on the screen with the values from the database
mNameEditText.setText(name);
mBreedEditText.setText(breed);
mWeightEditText.setText(Integer.toString(weight));

// Gender is a dropdown spinner, so map the constant value from the database
// into one of the dropdown options (0 is Unknown, 1 is Male, 2 is Female).
// Then call setSelection() so that option is displayed on screen as the current selection.
switch (gender) {
case PetEntry.GENDER_MALE:

This comment has been minimized.

Copy link
@jensgreiner

jensgreiner Jul 10, 2017

How about just using the gender integer we get back to set the mGenderSpinner.setSelection(gender);?
This way we don't map again the spinner value with the corresponding gender value and don't do any mistake here.

This comment has been minimized.

Copy link
@schv09

schv09 Jul 11, 2017

I thought the same thing and did it like this in my code just because it's more efficient.

This comment has been minimized.

Copy link
@akobartek

akobartek Jul 18, 2017

I also think this switch is redunant and bad for the performance.

This comment has been minimized.

Copy link
@th3oxen

th3oxen Sep 15, 2017

mGenderSpinner.setSelection(gender); is fine but make sure you use the same values for constants and indexes of the spinner because if you set different adapters to the spinner based on add mode or edit mode and you have different values and indexes then you need to use this switch.
I set that in edit mode the spinner doesn't show up the Unknown gender and because of this, when the retrived value was 1 (gender male=1) and I set this as the index, the spinner showed Female (index 0=male, 1=female), or even crash with ArrayIndexOutOfBoundsException (Female = 2, index=2 does not exist)

This comment has been minimized.

Copy link
@n-abdelmaksoud

n-abdelmaksoud Nov 21, 2017

That's actually what i did...
i have a question here .. when i tried to set EditText text to int not String, it crashes
mWeightEditText.setText(weight);
i thought that the primitive types can be set directly without converting into String!!??

This comment has been minimized.

Copy link
@n-abdelmaksoud

n-abdelmaksoud Dec 14, 2017

I figured out the reason.
There is two methods of setText(): one taking char and the other taking int as a parameter.

setText (int res) so when i pass an integer to it, it should've be a resource id of String not an integer to display.

This comment has been minimized.

Copy link
@prajwalkulkarni

prajwalkulkarni May 17, 2019

I'm unable to load text into their respective EditText field's though there are no errors thrown.
Tried to debug ,but i'm unable to figure out the reason,
anybody please help me.

This comment has been minimized.

Copy link
@JacobKyeong

JacobKyeong May 29, 2019

I had the same problem and went through all the other java files.
I fixed it by changing the
selectionArgs = new String[]{String.valueOf(uri)};
line to
selectionArgs = new String[]{String.valueOf(Contenturis.parseId(uri))};
under the PETS_ID line of the PetProvider.java file

mGenderSpinner.setSelection(1);
break;
case PetEntry.GENDER_FEMALE:
mGenderSpinner.setSelection(2);
break;
default:
mGenderSpinner.setSelection(0);
break;
}
}
}

@Override
public void onLoaderReset(Loader<Cursor> loader) {
// If the loader is invalidated, clear out all the data from the input fields.
mNameEditText.setText("");
mBreedEditText.setText("");
mWeightEditText.setText("");
mGenderSpinner.setSelection(0); // Select "Unknown" gender
}
}

27 comments on commit 8d4b875

@mdansei
Copy link

@mdansei mdansei commented on 8d4b875 Feb 5, 2017

Choose a reason for hiding this comment

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

The solution code here is a little different from the one in the classroom answer, like the onLoaderReset() body and the first two lines from onLoadFinish() are missing!

@linucksrox
Copy link

@linucksrox linucksrox commented on 8d4b875 Mar 10, 2017

Choose a reason for hiding this comment

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

Add new pet was causing a crash after making these code changes. It turns out you need to check if mCurrentPetUri is null and return null from onCreateLoader if it is.

@Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
    if (mCurrentPetUri == null) {
        return null;
    }
    // Since the editor shows all pet attributes, define a projection that contains
    // all columns from the pet table
    String[] projection = {

@namclu
Copy link

@namclu namclu commented on 8d4b875 Jun 1, 2017

Choose a reason for hiding this comment

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

On line 220, when we're creating a new CursorLoader, I don't understand why we're loading all Pet data into EditorActivity when we will ever only need a single Pet data. Shouldn't we set the selection and selectionArgs for a single Pet?

@linucksrox
Copy link

Choose a reason for hiding this comment

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

We're not. Notice how we pass mCurrentPetUri in on line 222. So that is only querying the name, breed, gender and weight for that specific pet Uri which includes the pet _ID that was passed in from the main activity. The actual query would look something like
SELECT name, breed, gender, weight FROM pets WHERE _ID = 5

@namclu
Copy link

@namclu namclu commented on 8d4b875 Jun 1, 2017

Choose a reason for hiding this comment

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

Thanks @linucksrox . I see, I was getting and setting the selection and selectionArgs but the solution's method is much better.

@namclu
Copy link

@namclu namclu commented on 8d4b875 Jun 1, 2017

Choose a reason for hiding this comment

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

@linucksrox in your code:

@Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
    if (mCurrentPetUri == null) {
        return null;
    }
    // Since the editor shows all pet attributes, define a projection that contains
    // all columns from the pet table
    String[] projection = {

When you return null, does that:

  1. Exit us out of onCreateLoader()
  2. Essentially no CursorLoader is created so then EditorActivity defaults to not filling the text fields

I encountered the same problem and just want to understand the solution in case I run into it next time.

@linucksrox
Copy link

Choose a reason for hiding this comment

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

  1. Yes, any return statement will exit out of that method
  2. Correct, no CursorLoader is created because there's nothing to query.

@jensgreiner
Copy link

Choose a reason for hiding this comment

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

One way is to use a global variable for URI of the item, another way is to put the id part of the URI into a Bundle object and set it in the initLoader call. Within onCreateLoader(...) the Bundle data is retrieved and the URI is build again using ContentUris.appendedWithId(). Is a bit more complicated but works as designed.

@jensgreiner
Copy link

@jensgreiner jensgreiner commented on 8d4b875 Jul 11, 2017

Choose a reason for hiding this comment

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

One way is to use a global variable for URI of the item

Well, it seems in one of the very next steps this global variable path will be used for another reason too.

@Wolf2231
Copy link

@Wolf2231 Wolf2231 commented on 8d4b875 Aug 21, 2017

Choose a reason for hiding this comment

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

@linucksrox

Add new pet was causing a crash after making these code changes. It turns out you need to check if mCurrentPetUri is null and return null from onCreateLoader if it is.

When you add a new pet, the Loader should not be initialized if you use this code in the onCreate in the EditorActivity.

`
Intent intent = getIntent();
mCurrentPetUri = intent.getData();

    if (mCurrentPetUri == null) {
        setTitle(getString(R.string.editor_activity_title_new_pet));
    } else {
        setTitle(getString(R.string.editor_activity_title_edit_pet));
        getLoaderManager().initLoader(EXISTING_PET_LOADER, null, this);
    }

`

Therefore, you don't need to use your code in the OnCreateLoader.
It's less expensive.

@linucksrox
Copy link

@linucksrox linucksrox commented on 8d4b875 Aug 21, 2017

Choose a reason for hiding this comment

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

@Wolf2231 Yes, I tested that change and it worked as expected. It makes more sense than what I originally said. Thanks for the update!

@MrEremka
Copy link

@MrEremka MrEremka commented on 8d4b875 Nov 13, 2017

Choose a reason for hiding this comment

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

image

Why does it do this? It stops my app from working and I don't understand why.

And yes I have implemented LoaderManager.LoaderCallbacks in the proper way

public class EditorActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks

@mohammedhemaid
Copy link

Choose a reason for hiding this comment

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

@MrEremka use getSupportLoaderManager(); instead getLoaderManager();

@ShahoodulHassan
Copy link

Choose a reason for hiding this comment

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

Im getting this error whenever i click a pet:

12-14 12:12:37.647 32358-32433/com.example.android.pets E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #2
Process: com.example.android.pets, PID: 32358
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:309)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.NullPointerException: uri
at com.android.internal.util.Preconditions.checkNotNull(Preconditions.java:60)
at android.content.ContentResolver.query(ContentResolver.java:474)
at android.content.CursorLoader.loadInBackground(CursorLoader.java:64)
at android.content.CursorLoader.loadInBackground(CursorLoader.java:56)
at android.content.AsyncTaskLoader.onLoadInBackground(AsyncTaskLoader.java:312)
at android.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:69)
at android.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:66)
at android.os.AsyncTask$2.call(AsyncTask.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) 
at java.lang.Thread.run(Thread.java:818) 

@vedavikas06
Copy link

Choose a reason for hiding this comment

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

I was also getting the same error when i click a pet.
help required!!

@vedavikas06
Copy link

Choose a reason for hiding this comment

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

change this line in the PetProvider Class in the static { ------ } sUriMatcher.addURI(PetContract.CONTENT_AUTHORITY,PetContract.PATH_PETS+"#",PET_ID);

to

sUriMatcher.addURI(PetContract.CONTENT_AUTHORITY,PetContract.PATH_PETS+"/#",PET_ID);

had resolved the issue for me

@ShahoodulHassan may be this is kind of the mistake in your code too.

@parasarorahere
Copy link

Choose a reason for hiding this comment

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

yeah

@Babadzhanov
Copy link

@Babadzhanov Babadzhanov commented on 8d4b875 Jun 5, 2018

Choose a reason for hiding this comment

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

So far so good 👍 Except when we save the edited pet we actually add a new one instead of replacing the existing pet but I'm pretty sure we will fix that soon..

@Nikoloutsos
Copy link

@Nikoloutsos Nikoloutsos commented on 8d4b875 Jun 17, 2018

Choose a reason for hiding this comment

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

I believe that we'd have cleaner code by using anonymous classes for implementing the callbacks instead of doing that..(Keep in mind that if you use this you cant have 2 loaders in the same activity 👎 )
Also, we don't need a projection array in onCreateLoader method because we can pass null(which by default will have the same results 👍 )

@adityalochan
Copy link

Choose a reason for hiding this comment

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

image

Why does it do this? It stops my app from working and I don't understand why.

And yes I have implemented LoaderManager.LoaderCallbacks in the proper way

public class EditorActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks

Update your import:

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.net.Uri;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;

Add all other relevant imports. Its mentioned in tutorial 6 that imports are wrong and need to be updated with right one.

@soumahaka
Copy link

Choose a reason for hiding this comment

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

    getSupportLoaderManager().initLoader(EXISTING_PET_LOADER, null, this);

App still crashes... please help !

@soumahaka
Copy link

Choose a reason for hiding this comment

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

change this line in the PetProvider Class in the static { ------ } sUriMatcher.addURI(PetContract.CONTENT_AUTHORITY,PetContract.PATH_PETS+"#",PET_ID);

to

sUriMatcher.addURI(PetContract.CONTENT_AUTHORITY,PetContract.PATH_PETS+"/#",PET_ID);

had resolved the issue for me

@ShahoodulHassan may be this is kind of the mistake in your code too.

bro, thank you a lot !!!!!!! you eased my life after 3 days debugging this code.... I was giving up the rest of the course

@zxkfall
Copy link

@zxkfall zxkfall commented on 8d4b875 Jun 13, 2020 via email

Choose a reason for hiding this comment

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

@Nusratillo
Copy link

Choose a reason for hiding this comment

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

2020-06-21 22:26:02.726 18477-18477/com.example.android.pets E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.android.pets, PID: 18477
android.database.CursorIndexOutOfBoundsException: Index -1 requested, with a size of 1
at android.database.AbstractCursor.checkPosition(AbstractCursor.java:460)
at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:136)
at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:50)
at android.database.CursorWrapper.getString(CursorWrapper.java:137)
at com.example.android.pets.EditorActivity.onLoadFinished(EditorActivity.java:253)
at com.example.android.pets.EditorActivity.onLoadFinished(EditorActivity.java:57)
at androidx.loader.app.LoaderManagerImpl$LoaderObserver.onChanged(LoaderManagerImpl.java:250)
at androidx.lifecycle.LiveData.considerNotify(LiveData.java:113)
at androidx.lifecycle.LiveData.dispatchingValue(LiveData.java:131)
at androidx.lifecycle.LiveData.setValue(LiveData.java:289)
at androidx.lifecycle.MutableLiveData.setValue(MutableLiveData.java:33)
at androidx.loader.app.LoaderManagerImpl$LoaderInfo.setValue(LoaderManagerImpl.java:189)
at androidx.loader.app.LoaderManagerImpl$LoaderInfo.onLoadComplete(LoaderManagerImpl.java:174)
at androidx.loader.content.Loader.deliverResult(Loader.java:132)

I have been doing all the steps same as tutorial, but I am getting this error, tried to fix but I cant find any solution, if smn knows the solution, help is apreciated)) Thanks

@soumahaka
Copy link

@soumahaka soumahaka commented on 8d4b875 Jun 21, 2020

Choose a reason for hiding this comment

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

2020-06-21 22:26:02.726 18477-18477/com.example.android.pets E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.android.pets, PID: 18477
android.database.CursorIndexOutOfBoundsException: Index -1 requested, with a size of 1
at android.database.AbstractCursor.checkPosition(AbstractCursor.java:460)
at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:136)
at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:50)
at android.database.CursorWrapper.getString(CursorWrapper.java:137)
at com.example.android.pets.EditorActivity.onLoadFinished(EditorActivity.java:253)
at com.example.android.pets.EditorActivity.onLoadFinished(EditorActivity.java:57)
at androidx.loader.app.LoaderManagerImpl$LoaderObserver.onChanged(LoaderManagerImpl.java:250)
at androidx.lifecycle.LiveData.considerNotify(LiveData.java:113)
at androidx.lifecycle.LiveData.dispatchingValue(LiveData.java:131)
at androidx.lifecycle.LiveData.setValue(LiveData.java:289)
at androidx.lifecycle.MutableLiveData.setValue(MutableLiveData.java:33)
at androidx.loader.app.LoaderManagerImpl$LoaderInfo.setValue(LoaderManagerImpl.java:189)
at androidx.loader.app.LoaderManagerImpl$LoaderInfo.onLoadComplete(LoaderManagerImpl.java:174)
at androidx.loader.content.Loader.deliverResult(Loader.java:132)

I have been doing all the steps same as tutorial, but I am getting this error, tried to fix but I cant find any solution, if smn knows the solution, help is apreciated)) Thanks

Please describe properly the problem to help us help you. I've finished this course there is one week now. I got lot of problem too but I solved them all

@antidoid
Copy link

@antidoid antidoid commented on 8d4b875 Jul 19, 2020

Choose a reason for hiding this comment

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

2020-07-19 13:55:39.504 31728-31728/com.example.android.pets E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.android.pets, PID: 31728
java.lang.IllegalStateException: ** ### ### Couldn't read row 0, col -1 from CursorWindow**. Make sure the Cursor is initialized correctly before accessing data from it.
at android.database.CursorWindow.nativeGetLong(Native Method)
at android.database.CursorWindow.getLong(CursorWindow.java:538)
at android.database.CursorWindow.getInt(CursorWindow.java:605)
at android.database.AbstractWindowedCursor.getInt(AbstractWindowedCursor.java:69)
at android.database.CursorWrapper.getInt(CursorWrapper.java:122)
at com.example.android.pets.EditorActivity.onLoadFinished(EditorActivity.java:250)
at com.example.android.pets.EditorActivity.onLoadFinished(EditorActivity.java:43)
at android.app.LoaderManagerImpl$LoaderInfo.callOnLoadFinished(LoaderManager.java:497)
at android.app.LoaderManagerImpl$LoaderInfo.onLoadComplete(LoaderManager.java:465)
at android.content.Loader.deliverResult(Loader.java:157)
at android.content.CursorLoader.deliverResult(CursorLoader.java:113)
at android.content.CursorLoader.deliverResult(CursorLoader.java:45)
at android.content.AsyncTaskLoader.dispatchOnLoadComplete(AsyncTaskLoader.java:272)
at android.content.AsyncTaskLoader$LoadTask.onPostExecute(AsyncTaskLoader.java:96)
at android.os.AsyncTask.finish(AsyncTask.java:695)
at android.os.AsyncTask.access$600(AsyncTask.java:180)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:712)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:227)
at android.app.ActivityThread.main(ActivityThread.java:7212)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:575)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:887)

I don't know why is this happening
In my senses,I've done everything as required


@SabalNiroula
Copy link

Choose a reason for hiding this comment

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

This is my complete state of the code.

`import android.app.LoaderManager;
import android.content.ContentValues;
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.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.NavUtils;

import com.example.petapp.data.PetContract.PetEntry;

import static com.example.petapp.data.PetContract.BASE_CONTENT_URI;
import static com.example.petapp.data.PetContract.PATH_PETS;

public class EditorActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks {

/** Identifier for the pet data loader */
private static final int EXISTING_PET_LOADER = 0;

/** Content URI for the existing pet (null if it's a new pet) */
private Uri mCurrentPetUri;

public static final Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, PATH_PETS);
/**
 * EditText field to enter the pet's name, breed and weight....
 */
private EditText mNameEditText, mBreedEditText,mWeightEditText;

private Spinner mGenderSpinner;
/**
 * Gender of the pet. The possible values are:
 * 0 for unknown gender, 1 for male, 2 for female.
 */
private int mGender = 0;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_editor);

    Intent intent = getIntent();
    mCurrentPetUri = intent.getData();

    if(mCurrentPetUri == null){
        setTitle(getString(R.string.add_pet));
    }else{
        // Otherwise this is an existing pet, so change app bar to say "Edit Pet"
        setTitle(getString(R.string.edit_pet));
        // Initialize a loader to read the pet data from the database
        // and display the current values in the editor
        getLoaderManager().initLoader(EXISTING_PET_LOADER, null, this);
    }

    // Find all relevant views that we will need to read user input from
    mNameEditText = findViewById(R.id.edit_pet_name);
    mBreedEditText = findViewById(R.id.edit_pet_breed);
    mWeightEditText = findViewById(R.id.edit_pet_weight);
    mGenderSpinner = findViewById(R.id.spinner_gender);

    setupSpinner();
}


/**
 * Setup the dropdown spinner that allows the user to select the gender of the pet.
 */
private void setupSpinner() {
    // Create adapter for spinner. The list options are from the String array it will use
    // the spinner will use the default layout
    ArrayAdapter genderSpinnerAdapter = ArrayAdapter.createFromResource(this,
            R.array.array_gender_options, android.R.layout.simple_spinner_item);

    // Specify dropdown layout style - simple list view with 1 item per line
    genderSpinnerAdapter.setDropDownViewResource(android.R.layout.simple_dropdown_item_1line);

    // Apply the adapter to the spinner
    mGenderSpinner.setAdapter(genderSpinnerAdapter);

    // Set the integer mSelected to the constant values
    mGenderSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            String selection = (String) parent.getItemAtPosition(position);
            if (!TextUtils.isEmpty(selection)) {
                if (selection.equals(getString(R.string.gender_male))) {
                    mGender = PetEntry.GENDER_MALE; // Male
                } else if (selection.equals(getString(R.string.gender_female))) {
                    mGender = PetEntry.GENDER_FEMALE; // Female
                } else {
                    mGender = PetEntry.GENDER_UNKNOWN; // Unknown
                }
            }
        }

        // Because AdapterView is an abstract class, onNothingSelected must be defined
        @Override
        public void onNothingSelected(AdapterView<?> parent) {
            mGender = PetEntry.GENDER_UNKNOWN; // Unknown
        }
    });
}

/**
 * Get user input from editor and save new pet into database.
 * Here, the flow of the execution of the insert method is like this
 * EditorActivity-> ContentResolver -> PetProvider(UriMatcher) -> insert a new pet or perform a update on the single pet
 * After that PetProvider(UriMatcher) -> ContentResolver -> EditorActivity (returns a new Uri object )
 */
private void insertPet() {
    // Read from input fields
    // Use trim to eliminate leading or trailing white space
    String nameString = mNameEditText.getText().toString().trim();
    String breedString = mBreedEditText.getText().toString().trim();
    String weightString = mWeightEditText.getText().toString().trim();
    int weight = Integer.parseInt(weightString);

    // Create a ContentValues object where column names are the keys,
    // and pet attributes from the editor are the values.
    ContentValues values = new ContentValues();
    values.put(PetEntry.COLUMN_PET_NAME, nameString);
    values.put(PetEntry.COLUMN_PET_BREED, breedString);
    values.put(PetEntry.COLUMN_PET_GENDER, mGender);
    values.put(PetEntry.COLUMN_PET_WEIGHT, weight);

    // Insert a new pet into the provider, returning the content URI for the new pet.
    Uri newUri = getContentResolver().insert(PetEntry.CONTENT_URI, values);

    // Show a toast message depending on whether or not the insertion was successful
    if (newUri != null) {
        // If the new content URI is null, then there was an error with insertion.
        Toast.makeText(this, getString(R.string.pet_saved),
                Toast.LENGTH_SHORT).show();
    } else {
        // Otherwise, the insertion was successful and we can display a toast.
        Toast.makeText(this, getString(R.string.not_saved),
                Toast.LENGTH_SHORT).show();
    }
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu options from the res/menu/menu_editor.xml file.
    // This adds menu items to the app bar.
    getMenuInflater().inflate(R.menu.menu_editor, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // User clicked on a menu option in the app bar overflow menu
    switch (item.getItemId()) {
        // Respond to a click on the "Save" menu option
        case R.id.action_save:
            // save the data the has entered
            insertPet();
            //after the save has done the finish() method takes us to the CatalogActivity
            finish();
            return true;
        // Respond to a click on the "Delete" menu option
        case R.id.action_delete:
            // Do nothing for now
            return true;
        // Respond to a click on the "Up" arrow button in the app bar
        case android.R.id.home:
            // Navigate back to parent activity (CatalogActivity)
            NavUtils.navigateUpFromSameTask(this);
            return true;
    }
    return super.onOptionsItemSelected(item);
}

@Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
    // Since the editor shows all pet attributes, define a projection that contains
    // all columns from the pet table
    String[] projection = {
            PetEntry._ID,
            PetEntry.COLUMN_PET_NAME,
            PetEntry.COLUMN_PET_BREED,
            PetEntry.COLUMN_PET_GENDER,
            PetEntry.COLUMN_PET_WEIGHT };

    // This loader will execute the ContentProvider's query method on a background thread
    return new CursorLoader(this,   // Parent activity context
            mCurrentPetUri,         // Query the content URI for the current pet
            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 cursor) {

    // Bail early if the cursor is null or there is less than 1 row in the cursor
    if (cursor == null || cursor.getCount() < 1) {
        return;
    }

    if (cursor.moveToFirst()) {
        // Find the columns of pet attributes that we're interested in
        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);

        // Extract out the value from the Cursor for the given column index
        String name = cursor.getString(nameColumnIndex);
        String breed = cursor.getString(breedColumnIndex);
        int gender = cursor.getInt(genderColumnIndex);
        int weight = cursor.getInt(weightColumnIndex);

        // Update the views on the screen with the values from the database
        mNameEditText.setText(name);
        mBreedEditText.setText(breed);
        mWeightEditText.setText(Integer.toString(weight));
        mGenderSpinner.setSelection(gender);

    }
}


@Override
public void onLoaderReset( Loader<Cursor> loader) {

// If the loader is invalidated, clear out all the data from the input fields.
mNameEditText.setText("");
mBreedEditText.setText("");
mWeightEditText.setText("");
mGenderSpinner.setSelection(0); // Select "Unknown" gender
}
}`

Please sign in to comment.