Skip to content

Commit

Permalink
1.17 Create PetCursorAdapter to display list of pets in ListView
Browse files Browse the repository at this point in the history
  • Loading branch information
Beginning Android committed Aug 23, 2016
1 parent a244b5a commit feca5f2
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 48 deletions.
51 changes: 7 additions & 44 deletions app/src/main/java/com/example/android/pets/CatalogActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.ListView;

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

Expand Down Expand Up @@ -79,51 +79,14 @@ private void displayDatabaseInfo() {
null, // Selection criteria
null); // The sort order for the returned rows

TextView displayView = (TextView) findViewById(R.id.text_view_pet);
// Find the ListView which will be populated with the pet data
ListView petListView = (ListView) findViewById(R.id.list);

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");
// Setup an Adapter to create a list item for each row of pet data in the Cursor.
PetCursorAdapter adapter = new PetCursorAdapter(this, cursor);

This comment has been minimized.

Copy link
@abdullah-shamali

abdullah-shamali Dec 1, 2018

where is "cursor" referring from?

This comment has been minimized.

Copy link
@vinayak0505

vinayak0505 Jun 5, 2020

you have already created above
check line 75


// 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));
}
} finally {
// Always close the cursor when you're done reading from it. This releases all its
// resources and makes it invalid.
cursor.close();

This comment has been minimized.

Copy link
@AhmadTaramsy

AhmadTaramsy Sep 1, 2021

Why didn’t we close the cursor ?
leaving the cursor open is a bad practice and wastes resources, isn’t it?

}
// Attach the adapter to the ListView.
petListView.setAdapter(adapter);
}

/**
Expand Down
88 changes: 88 additions & 0 deletions app/src/main/java/com/example/android/pets/PetCursorAdapter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.pets;

import android.content.Context;
import android.database.Cursor;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.TextView;

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

/**
* {@link PetCursorAdapter} is an adapter for a list or grid view
* that uses a {@link Cursor} of pet data as its data source. This adapter knows
* how to create list items for each row of pet data in the {@link Cursor}.
*/
public class PetCursorAdapter extends CursorAdapter {

/**
* Constructs a new {@link PetCursorAdapter}.
*
* @param context The context
* @param c The cursor from which to get the data.
*/
public PetCursorAdapter(Context context, Cursor c) {
super(context, c, 0 /* flags */);
}

/**
* Makes a new blank list item view. No data is set (or bound) to the views yet.
*
* @param context app context
* @param cursor The cursor from which to get the data. The cursor is already
* moved to the correct position.
* @param parent The parent to which the new view is attached to
* @return the newly created list item view.
*/
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
// Inflate a list item view using the layout specified in list_item.xml
return LayoutInflater.from(context).inflate(R.layout.list_item, parent, false);
}

/**
* This method binds the pet data (in the current row pointed to by cursor) to the given
* list item layout. For example, the name for the current pet can be set on the name TextView
* in the list item layout.
*
* @param view Existing view, returned earlier by newView() method
* @param context app context
* @param cursor The cursor from which to get the data. The cursor is already moved to the
* correct row.
*/
@Override
public void bindView(View view, Context context, Cursor cursor) {
// Find individual views that we want to modify in the list item layout
TextView nameTextView = (TextView) view.findViewById(R.id.name);
TextView summaryTextView = (TextView) view.findViewById(R.id.summary);

// 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);

// Read the pet attributes from the Cursor for the current pet
String petName = cursor.getString(nameColumnIndex);
String petBreed = cursor.getString(breedColumnIndex);

// Update the TextViews with the attributes for the current pet
nameTextView.setText(petName);
summaryTextView.setText(petBreed);
}
}
7 changes: 3 additions & 4 deletions app/src/main/res/layout/activity_catalog.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,10 @@
android:layout_height="match_parent"
tools:context=".CatalogActivity">

<TextView
android:id="@+id/text_view_pet"
<ListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/activity_margin"/>
android:layout_height="match_parent"/>

<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
Expand Down
36 changes: 36 additions & 0 deletions app/src/main/res/layout/list_item.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- Layout for a single list item in the list of pets -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="@dimen/activity_margin">

<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-medium"
android:textAppearance="?android:textAppearanceMedium"
android:textColor="#2B3D4D" />

<TextView
android:id="@+id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="#AEB6BD" />
</LinearLayout>

14 comments on commit feca5f2

@tSquaredd
Copy link

Choose a reason for hiding this comment

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

What about closing the cursor? I see it is removed, and without removing it a crash occurs because it needs the cursor still... So does the CursorAdapter handle the closing or do we need to address this...?

@linucksrox
Copy link

@linucksrox linucksrox commented on feca5f2 Jun 22, 2017

Choose a reason for hiding this comment

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

@tSquaredd
I'm not sure when you would close the cursor, but one of the next few lessons has you use a CursorLoader which handles this automatically.

@tSquaredd
Copy link

Choose a reason for hiding this comment

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

@linucksrox thanks for the quick reply! Had a feeling it would come up later on..

@Pkhotpanya
Copy link

Choose a reason for hiding this comment

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

Somehow I had an error following the pets tutorial project up to this point. If you are trying to do the Android basics nanodegree around this date then be sure to add _id to the projections array in the displayDatabaseInfo() method or it won't compile. It took me a while to pinpoint this problem.

 private void displayDatabaseInfo() {
     // 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 };

@iawale
Copy link

@iawale iawale commented on feca5f2 Jul 1, 2017

Choose a reason for hiding this comment

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

@tSquaredd If you close the adapter on the finally block as we had done in the past lessons. There will be an error when the adapter will try to extract data from it to setup the list view. And it is so because the cursor is already closed.

@Utshaw
Copy link

@Utshaw Utshaw commented on feca5f2 Sep 9, 2017

Choose a reason for hiding this comment

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

Prior to watching the solution of the quiz , I kept the cursor.close() inside finally block & got this exception:

cursor is deactivated prior to calling this method

@patrickmunye
Copy link

@patrickmunye patrickmunye commented on feca5f2 Oct 15, 2017

Choose a reason for hiding this comment

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

i attached the cursor adapter to the ListView after Cursor().close
petListView.setAdapter(adapter);
the display doesn't recognize adapter (error message.......> " Cannot resolve symbol adapter)

@nonevietnam
Copy link

Choose a reason for hiding this comment

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

why we dont need while loop when read the pet attributes from the Cursor for the current pet??

@RuslanPrimak
Copy link

Choose a reason for hiding this comment

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

Recreating adapter on every displayDatabaseInfo's call seems too tough.

@sherifhisham
Copy link

Choose a reason for hiding this comment

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

Great work

@fragargon
Copy link

Choose a reason for hiding this comment

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

CursorAdapter(Context context, Cursor c)
This constructor was deprecated in API level 11. This option is discouraged, as it results in Cursor queries being performed on the application's UI thread and thus can cause poor responsiveness or even Application Not Responding errors. As an alternative, use LoaderManager with a CursorLoader.
see documentation there: https://developer.android.com/reference/android/widget/CursorAdapter
This will not solved the actual problem cursor.closed() but as this is a intermediate lesson, let's do it and implement the LoaderManager and CursorLoader in the next step.

@ahmedSamra88
Copy link

Choose a reason for hiding this comment

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

cursor.close();
using it remove data from cursor and no data apear in list

@DesmondMilesDante
Copy link

Choose a reason for hiding this comment

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

import com.example.android.pets..PetCursorAdapter; in Catalog Activity

@KushanTharaka97
Copy link

@KushanTharaka97 KushanTharaka97 commented on feca5f2 Jul 10, 2020

Choose a reason for hiding this comment

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

I had a huge error that, describing '_id' is not there, I was confused because previous operations worked properly and what would compiler trying to tell.
So after searching the bug, I was able to find PetContract class InsertData method's ID declaration is wrong.
always it should be alike " public static final String _ID = BaseColumns._ID;" in that way.
#HappyCoading
#goodLuck

Please sign in to comment.