没有DoInBackground时在doInBackground方法中获取错误

时间:2017-10-14 07:21:24

标签: java android sqlite android-loadermanager

我收到了一个DoInBackground错误,因为我添加了游标通知uri但在此之前我收到错误我的数据库被锁定。这是什么意思我似乎无法理解为什么它是这样的,因为没有背景方法,我正在使用Loader。 活动是

ProductProvider.java

package com.example.bahubali.inventoryapp.data;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;



public class ProductProvider extends ContentProvider {

    //Tag for the log messages
    public static final String LOG_TAG = ProductProvider.class.getSimpleName();

    //Database helper that will provide access to the database.
    private ProductDbHelper mDbHelper;
    /** URI matcher code for the content URI for the pets table */
    public static final int PRODUCTS = 100;

    /** URI matcher code for the content URI for a single pet in the pets table */
    public static final int PRODUCT_ID = 101;

    Context context;

    /** URI matcher object to match a context URI to a corresponding code.
     * The input passed into the constructor represents the code to return for the root URI.
     * It's common to use NO_MATCH as the input for this case.
     */
    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

    // Static initializer. This is run the first time anything is called from this class.
    static {
        // The calls to addURI() go here, for all of the content URI patterns that the provider
        // should recognize. All paths added to the UriMatcher have a corresponding code to return
        // when a match is found.

        // The content URI of the form "content://com.example.android.pets/pets" will map to the
        // integer code {@link #PETS}. This URI is used to provide access to MULTIPLE rows
        // of the pets table.
        sUriMatcher.addURI(ProductContract.CONTENT_AUTHORITY, ProductContract.PATH_PRODUCTS, PRODUCTS);

        // The content URI of the form "content://com.example.android.pets/pets/#" will map to the
        // integer code {@link #PETS_ID}. This URI is used to provide access to ONE single row
        // of the pets table.

        // In this case, the "#" wildcard is used where "#" can be substituted for an integer.
        // For example, "content://com.example.android.pets/pets/3" matches, but
        // "content://com.example.android.pets/pets" (without a number at the end) doesn't match.
        sUriMatcher.addURI(ProductContract.CONTENT_AUTHORITY, ProductContract.PATH_PRODUCTS + "/#", PRODUCT_ID);
    }


    /**
     * Initialize the provider and the database helper object.
     */
    @Override
    public boolean onCreate()
    {
        /*
         * Creates a new helper object. This method always returns quickly.
         * until SQLiteOpenHelper.getWritableDatabase is called
         */
        mDbHelper = new ProductDbHelper(getContext());
        context = getContext();

        return true;
    }


    /*
    *Perform the query to the given URI.Use the given projection,selection,selectionArgs, and sort
    * order.
     */

    @Override
    public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs,
                        String sortOrder) {
        // Get readable database
        SQLiteDatabase database = mDbHelper.getReadableDatabase();

        // This cursor will hold the result of the query
        Cursor cursor ;

        // Figure out if the URI matcher can match the URI to a specific code
        int match = sUriMatcher.match(uri);
        switch (match) {
            case PRODUCTS:
                // For the PETS code, query the pets table directly with the given
                // projection, selection, selection arguments, and sort order. The cursor
                // could contain multiple rows of the pets table.
                //  Perform database query on pets
                cursor = database.query(ProductContract.ProductEntry.TABLE_NAME,
                        projection,selection,selectionArgs,null,null,sortOrder);
                break;

            case PRODUCT_ID:
                // For the PET_ID code, extract out the ID from the URI.
                // For an example URI such as "content://com.example.android.pets/pets/3",
                // the selection will be "_id=?" and the selection argument will be a
                // String array containing the actual ID of 3 in this case.
                //
                // For every "?" in the selection, we need to have an element in the selection
                // arguments that will fill in the "?". Since we have 1 question mark in the
                // selection, we have 1 String in the selection arguments' String array.
                selection = PRODUCT_ID + "=?";
                selectionArgs = new String[] { String.valueOf(ContentUris.parseId(uri)) };

                // This will perform a query on the pets table where the _id equals 3 to return a
                // Cursor containing that row of the table.
                cursor = database.query(ProductContract.ProductEntry.TABLE_NAME, 
                                                                    projection,
                                                                        selection,
                                                                    selectionArgs,
                                                                    null,
                                                                    null,   
                                                                    sortOrder);
                break;
            default:
                throw new IllegalArgumentException("Cannot query unknown URI " + uri);
        }
        //Set notification URI to the cursor,
        //So we know what content URI the cursor was created for.
        //If the data at this URI changes, then we need to update the cursor.
        cursor.setNotificationUri(getContext().getContentResolver(),null);
        cursor.close();
        return cursor;
    }


    /*
    *Return the  MIME type of data for the content URI.
     */
    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        final int match = sUriMatcher.match(uri);
        switch (match){
            case PRODUCTS:
                return ProductContract.ProductEntry.CONTENT_LIST_TYPE;
            case PRODUCT_ID:
                return ProductContract.ProductEntry.CONTENT_ITEM_TYPE;
            default:
                throw new IllegalStateException("UNKNOWN URI" + uri + " with match" + match);
        }


    }
    //Added a commit  here

    /*
    *Insert a new data into the provider with the given Constructor.
     */
    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri,
                      @Nullable ContentValues contentValues) {
        final int match = sUriMatcher.match(uri);
        switch (match){
            case PRODUCTS:
                return insertProduct(uri,contentValues);

                default:
                    throw new IllegalArgumentException("Insertion is not supported for " +uri);


        }

    }

    /*
    Insert a product in the database with the given content values.Return the new content URI
    for that specific row in the database.
     */
    private Uri insertProduct(Uri uri, ContentValues contentValues){

        //Get writeable database
        SQLiteDatabase  database = mDbHelper.getWritableDatabase();

        //Insert the new product with the given values
        long id = database.insert(ProductContract.ProductEntry.TABLE_NAME,null,contentValues);

        //If the Id is -1, then the insertion failed.Log on an error to return null
        if (id == -1){
            Log.e(LOG_TAG,"Failed to insert a row" + uri);
            return null;
        }

        //Check that the name is not null
        String name = contentValues.getAsString(ProductContract.ProductEntry.COLUMN_PRODUCT_NAME);
        if (name == null){
            throw new IllegalArgumentException("Product requires a name");
        }

        //Check that the price is not null
        Integer price = contentValues.getAsInteger(ProductContract.ProductEntry.COLUMN_PRODUCT_PRICE);
        if (price != null && price < 0 ){
            throw new IllegalArgumentException("Product requires  valid price");
        }
        //Notify all listeners that the data has changed for the product content URI
        getContext().getContentResolver().notifyChange(uri,null);


        return ContentUris.withAppendedId(uri,id);
    }

    /*
    *Delete the data at the given selection and selection arguements.
     */
    @Override
    public int delete(@NonNull Uri uri,
                      @Nullable String selection,
                      @Nullable String[] selectionArgs) {
        // Get writeable database
        SQLiteDatabase database = mDbHelper.getWritableDatabase();

        //Track the no. of rows  that were deleted
        int rowsDeleted;

        final int match = sUriMatcher.match(uri);
        switch (match) {
            case PRODUCTS:
                // Delete all rows that match the selection and selection args
              rowsDeleted = database.delete(ProductContract.ProductEntry.TABLE_NAME,selection,selectionArgs);
                break;
            case PRODUCT_ID:
                // Delete a single row given by the ID in the URI
                selection = ProductContract.ProductEntry._ID + "=?";
                selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
                rowsDeleted = database.delete(ProductContract.ProductEntry.TABLE_NAME,selection,selectionArgs);
                break;
            default:
                throw new IllegalArgumentException("Deletion is not supported for " + uri);
        }
        //If 1 or more rows were  deleted, then notify all listeners that the data at the given
        //given uri has changed
        if (rowsDeleted != 0){
            getContext().getContentResolver().notifyChange(uri,null);
        }
        return rowsDeleted;
    }

    /*
    *Updates the data at the given selection and the selection arguements, with the new content
    * values.
     */
    @Override
    public int update(@NonNull Uri uri,
                      @Nullable ContentValues contentValues,
                      @Nullable String selection,
                      @Nullable String[] selectionArgs) {

        final int match = sUriMatcher.match(uri);
        switch (match) {
            case PRODUCTS:
                return updateProduct(uri, contentValues, selection, selectionArgs);
            case PRODUCT_ID:
                // For the PRODUCT_D 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 = ProductContract.ProductEntry._ID + "=?";
                selectionArgs = new String[] { String.valueOf(ContentUris.parseId(uri)) };
                return updateProduct(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 updateProduct(Uri uri,ContentValues contentValues,String selection,String[] selectionArgs){

        // If the {@link ProductEntry#COLUMN_PRODUCT_NAME} key is present,
        // check that the name value is not null.
        if (contentValues.containsKey(ProductContract.ProductEntry.COLUMN_PRODUCT_NAME)) {
            String name = contentValues.getAsString(ProductContract.ProductEntry.COLUMN_PRODUCT_NAME);
            if (name == null) {
                throw new IllegalArgumentException("Product requires a name");
            }
        }

        // If the {@link ProductEntry#COLUMN_PRODUCT_PRICE} key is present,
        // check that the price value is valid.
        if (contentValues.containsKey(ProductContract.ProductEntry.COLUMN_PRODUCT_PRICE)) {
            // Check that the weight is greater than or equal to 0 kg
            Integer price = contentValues.getAsInteger(ProductContract.ProductEntry.COLUMN_PRODUCT_PRICE);
            if (price!= null && price < 0) {
                throw new IllegalArgumentException("Product requires valid weight");
            }
        }

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

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

        //perform the update on the database and the get the number of rows affected
        int rowsUpdated = database.update(ProductContract.ProductEntry.TABLE_NAME,contentValues,selection
                                        ,selectionArgs);

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


    }

CatalogActivity.java

package com.example.bahubali.inventoryapp;

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.database.sqlite.SQLiteDatabase;
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.ListView;

import com.example.bahubali.inventoryapp.data.ProductContract;
import com.example.bahubali.inventoryapp.data.ProductDbHelper;

public class CatalogActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor> {

    /** Database helper that will provide us access to the database */
    private ProductDbHelper mDbHelper;

    //Define an PetCursor adapter
    private ProductCursorAdapter mCursorAdapter;

    //The integer loader constant for Product loader
    private static final int PRODUCT_LOADER = 0;

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

      //Setup fab to open editor activity
        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(CatalogActivity.this,EditorActivity.class);
                startActivity(intent);
            }
        });
        // To access our database, we instantiate our subclass of SQLiteOpenHelper
        // and pass the context, which is the current activity.

         mDbHelper = new ProductDbHelper(this);

         //Find the listView which will be with the product data
        ListView productListView = (ListView) findViewById(R.id.list);

        //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);
        productListView.setEmptyView(emptyView);

        //Setup an Adapter to create a list item for each row of product data in the Cursor.
        //There is no product data yet(until the loader finishes) so pass in the null Cursor.
        mCursorAdapter = new ProductCursorAdapter(this,null);
        productListView.setAdapter(mCursorAdapter);

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



    }

    @Override
    protected void onStart() {
        super.onStart();

    }



    /*helper method to insert hardcoded data in the database*/
    private void insertProduct(){
        //Get the database in the write mode
        SQLiteDatabase db = mDbHelper.getWritableDatabase();
        //Create a contentValues where  column names are the keys,
        //and the boat attributes are values
        ContentValues values = new ContentValues();
        values.put(ProductContract.ProductEntry.COLUMN_PRODUCT_NAME,"Boat");
        values.put(ProductContract.ProductEntry.COLUMN_PRODUCT_PRICE,600);
        values.put(ProductContract.ProductEntry.COLUMN_PRODUCT_QUANTITY,4);
        values.put(ProductContract.ProductEntry.COLUMN_PRODUCT_SUPPLIER,"Amazon");

        /*
        Insert a new row in the database ,returning the id of that new row
        The first argument for the db.insert() is the products table name
        The second arguments provides the name of the column in which the framework
        can insert Null if the event that the content values is empty(if this is set to "null",then
        the framework will not insert a row when there is no values.
         */
        long newRowId = db.insert(ProductContract.ProductEntry.TABLE_NAME,null,values);
    }




    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu options from the res/menu/menu_catalog.xml file.
        // This adds menu items to the app bar.
        getMenuInflater().inflate(R.menu.menu_catalog,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 "Insert dummy data" menu option
            case R.id.action_insert_new_data:
                insertProduct();
                return true;
            // Respond to a click on the "Delete all entries" menu option
            case R.id.action_delete_all_entries:
                //Do nothing for now;
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
    //Define a projection that specifies the column from the table we care about
        String projection[] = {
                ProductContract.ProductEntry._ID,
                ProductContract.ProductEntry.COLUMN_PRODUCT_NAME,
                ProductContract.ProductEntry.COLUMN_PRODUCT_SUPPLIER
        };
    //This loader will implement the ContentProvider's method in background thread
        return new CursorLoader(this,
                ProductContract.ProductEntry.CONTENT_URI,
                projection,
                null,
                null,
                null);
    }

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

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

    }
}

    }


}

LogCat:

10-14 12:20:31.131 2900-3121/com.example.bahubali.inventoryapp E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
                                                                                 Process: com.example.bahubali.inventoryapp, PID: 2900
                                                                                 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.IllegalArgumentException: You must pass a valid uri and observer
                                                                                     at android.os.Parcel.readException(Parcel.java:1624)
                                                                                     at android.os.Parcel.readException(Parcel.java:1573)
                                                                                     at android.content.IContentService$Stub$Proxy.registerContentObserver(IContentService.java:713)
                                                                                     at android.content.ContentResolver.registerContentObserver(ContentResolver.java:1605)
                                                                                     at android.database.AbstractCursor.setNotificationUri(AbstractCursor.java:402)
                                                                                     at android.database.AbstractCursor.setNotificationUri(AbstractCursor.java:390)
                                                                                     at com.example.bahubali.inventoryapp.data.ProductProvider.query(ProductProvider.java:131)
                                                                                     at android.content.ContentProvider.query(ContentProvider.java:1017)
                                                                                     at android.content.ContentProvider$Transport.query(ContentProvider.java:238)
                                                                                     at android.content.ContentResolver.query(ContentResolver.java:491)
                                                                                     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) 

0 个答案:

没有答案
相关问题