0

I am trying to build a simple stock application, I have a list view on my main activity which has a "Sell" button on every list item I have. The functionality of the Sell button should decrease the quantity of that particular item by updating the row for that item and setting the quantity to quantity-1.

To achieve this, I have found that setting up an on click listener in my custom cursor adapter class was the way to do it. I am using a content provider class for my Database operations. So what I tried to do is, trigger a function which is in my main activity, within the OnClickListener which is in my cursor adapter. Here is some code that would explain more. (please forgive my terrible programming skills, I am fairly new )

My approach does not seem to work for some reason, first click on Sell button does not do anything, and the second one crashes the application with the reason:

  android.database.StaleDataException: Attempting to access a closed CursorWindow.Most probable cause: cursor is deactivated prior to calling this method.

p.s. I did not send the context from the adapter to decrease count method, and it was crashing of a null pointer on the getContentResolver().

Update function in my content provider:

private int updateItem (Uri uri, ContentValues values, String selection, String[] selectionArgs){

    if (values.containsKey(InventoryContract.ItemEntry.COLUMN_NAME)){
        String name = values.getAsString(InventoryContract.ItemEntry.COLUMN_NAME);
        if (name == null){
            throw new IllegalArgumentException("Item requires a name");
        }
    }

    // If values size is zero, do not try to update the database.
    if (values.size() == 0){
        return 0;
    }

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

    // Perform the update on the database and get the number of rows affected
    int rowsUpdated = database.update(InventoryContract.ItemEntry.TABLE_NAME, values, selection, selectionArgs);

    // If 1 or more rows were updated, then notify all listeners that the data at the
    // given URI has changed
    if (rowsUpdated != 0) {
        getContext().getContentResolver().notifyChange(uri, null);
    }

    // Return number of rows updated
    return rowsUpdated;
}

The function I have written ( or tried to write ) in my main activity

    public void decreaseCount(Context context, int columnId, int quantity){

    quantity = quantity -1;

    ContentValues values = new ContentValues();
    values.put(InventoryContract.ItemEntry.COLUMN_QUANTITY, quantity);

    Uri updateUri = ContentUris.withAppendedId(InventoryContract.ItemEntry.CONTENT_URI, columnId);

    int rowsAffected = context.getContentResolver().update(updateUri, values,null, null);

}

and lastly, the custom OnClickListener I have added to the button (p.s. the listener is inside the overriden bindView method of the cursor adapter )

sellButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            int columnIdIndex = mCursor.getColumnIndex(InventoryContract.ItemEntry._ID);
            int quantityIndex = mCursor.getColumnIndex(InventoryContract.ItemEntry.COLUMN_QUANTITY);

            CatalogActivity catalogActivity = new CatalogActivity();
            catalogActivity.decreaseCount(context2, Integer.valueOf(mCursor.getString(columnIdIndex)), Integer.valueOf(mCursor.getString(quantityIndex)));
        }
    });

Thank you in advance !

5
  • sorry, added more details, i accidentally saved. Commented Jan 19, 2018 at 22:30
  • github.com/tipialican/InventoryApp heres the repo if anyone would like to check it out Commented Jan 19, 2018 at 22:32
  • Show the full stack trace from the log not just one line. Show code that manages mCursor as StaleDataException - This exception is thrown when a Cursor contains stale data and must be requeried before being used again. Commented Jan 19, 2018 at 22:43
  • hey mike, it turns out my code actually is reducing the quantity of the item, but for some reason it is doing it regardless to item which has the sale button clicked Commented Jan 19, 2018 at 22:47
  • Exactly why the full stack trace is important, it says what is what and especially where the issue occurred. Commented Jan 19, 2018 at 22:51

1 Answer 1

1

The problem is very trivial. I fixed your codes. First don't create objects out of activities. Try to use boxing and unboxing technic to retrieve your context back. In your InsertCursorAdapter constructor should be like this

public ItemCursorAdapter(Context context, Cursor c) { super(context, c); this.context = context; }

Then you need to save your cursor from bindView method.

Then you need to bind the context object to get your activity object back. All in all, you would have something like this:

 @Override
public void bindView(View view, final Context context, Cursor cursor) {
    this.mCursor = cursor;
    TextView nameTextView = view.findViewById(R.id.name);
    TextView quantityTextView = view.findViewById(R.id.quantity);
     sellButton = view.findViewById(R.id.sell_button);
    ImageView imageView = view.findViewById(R.id.item_image);

    sellButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            int columnIdIndex = mCursor.getColumnIndex(InventoryContract.ItemEntry._ID);
            int quantityIndex = mCursor.getColumnIndex(InventoryContract.ItemEntry.COLUMN_QUANTITY);
            String col= mCursor.getString(columnIdIndex);
            String quan= mCursor.getString(quantityIndex);
            CatalogActivity catalogActivity = (CatalogActivity) context;
            catalogActivity.decreaseCount( Integer.valueOf(col), Integer.valueOf(quan));
        }
    });

Also I changed your decreaseCount arguments. Because this method is in activity class you don't need to pass it anytime you need to decrease the value. getContentResolver() method is a method in super class AppCompatActivity and because it is public, your activity have implemented it already.

 //TODO: Decrease count by one
public void decreaseCount(int columnId, int quantity){

    quantity = quantity -1;

    ContentValues values = new ContentValues();
    values.put(InventoryContract.ItemEntry.COLUMN_QUANTITY, quantity);

    Uri updateUri = ContentUris.withAppendedId(InventoryContract.ItemEntry.CONTENT_URI, columnId);

    int rowsAffected = getContentResolver().update(updateUri, values,null, null);

}
Sign up to request clarification or add additional context in comments.

2 Comments

thank you so much for all the explanation, fixed my code. I now have a problem where, when there are multiple items in my list, clicking sell on one of them is decreasing the count of another item on the list. but I can create an other question for that. again thank you for the time you spared.
aaand solved that by storing the cursor position in my bindView. thank you again.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.