Sqlite Content Provider:已插入行,但应用崩溃导致无法插入行

时间:2019-01-23 05:49:45

标签: android sqlite android-contentprovider sql-insert

我的应用程序中的内容提供程序有几个问题。我在提供程序中存储了一项(文本字符串)。它有一个对应的ID。 id是一个String而不是一个int。最初,项目已保存,但在刷卡时并未删除。此后已解决。我之前的主题:

Deleting a single SQlite row RecyclerView onSwiped

现在,当我按下按钮将项目添加到数据库时,应用程序崩溃。重新启动应用程序后,当我选择数据库时,该项目已存在。此外,logcat和debug均显示该项目已保存。 Stacktrace错误:

 E/AndroidRuntime: FATAL EXCEPTION: main
    Process: capstone.my.annin.londontubeschedule, PID: 4325
    android.database.SQLException: Failed to insert row into content://capstone.my.annin.londontubeschedule/lines
        at capstone.my.annin.londontubeschedule.data.TubeLineContentProvider.insert(TubeLineContentProvider.java:89)
        at android.content.ContentProvider$Transport.insert(ContentProvider.java:267)
        at android.content.ContentResolver.insert(ContentResolver.java:1545)
        at capstone.my.annin.londontubeschedule.ui.StationListActivity$1.onClick(StationListActivity.java:91)

错误可能是因为这是一个长字符串而不是字符串吗?

long id = db.insert(TubeLineContract.TubeLineEntry.TABLE_NAME, null, values);

不允许我将其更改为字符串。

主持人:到目前为止,我在这里还没有找到类似的话题。谢谢。

ContentProvider类:

public class TubeLineContentProvider extends ContentProvider
{
    //Tag for the log messages
    public static final String LOG_TAG = TubeLineContentProvider.class.getSimpleName();

    /**
     * URI matcher code for the content URI for the lines table
     */
    public static final int LINES = 100;

    /**
     * URI matcher code for the content URI for one line in the lines table
     */
    public static final int LINE_WITH_ID = 101;

    /**
     * UriMatcher object to match a content 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 = buildUriMatcher();

    // Static initializer. This is run the first time anything is called from this class.
    public static UriMatcher buildUriMatcher()
    {
        // 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.
        UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI(TubeLineContract.CONTENT_AUTHORITY, TubeLineContract.PATH_LINES, LINES);
        uriMatcher.addURI(TubeLineContract.CONTENT_AUTHORITY, TubeLineContract.PATH_LINES + "/*", LINE_WITH_ID);

        return uriMatcher;
    }

    /**
     * Database helper object
     */
    private TubeLineDbHelper mTubeLineDbHelper;

    @Override
    public boolean onCreate()
    {
        // Complete onCreate() and initialize a TubeLineDbhelper on startup
        // [Hint] Declare the DbHelper as a global variable
        Context context = getContext();
        mTubeLineDbHelper = new TubeLineDbHelper(context);
        return true;
    }

    // Implement insert to handle requests to insert a single new row of data
    @Override
    public Uri insert(@NonNull Uri uri, ContentValues values)
    {
        // Get access to the line database (to write new data to)
        final SQLiteDatabase db = mTubeLineDbHelper.getWritableDatabase();

        // Write URI matching code to identify the match for the lines directory
        int match = sUriMatcher.match(uri);
        Uri returnUri; // URI to be returned

        switch (match)
        {
            case LINES:
                // Insert new values into the database
                // Inserting values into lines table
                long id = db.insert(TubeLineContract.TubeLineEntry.TABLE_NAME, null, values);
                if (id == 0)
               {
                    returnUri = ContentUris.withAppendedId(TubeLineContract.TubeLineEntry.CONTENT_URI, id);
              }
                else
                {
                    throw new android.database.SQLException("Failed to insert row into " + uri);
                }
                break;
            // Set the value for the returnedUri and write the default case for unknown URI's
            // Default case throws an UnsupportedOperationException
            default:
                throw new UnsupportedOperationException("Unknown uri: " + uri);
        }

        // Notify the resolver if the uri has been changed, and return the newly inserted URI
        getContext().getContentResolver().notifyChange(uri, null);

        // Return constructed uri (this points to the newly inserted row of data)
        return returnUri;
    }

    // Implement query to handle requests for data by URI
    @Override
    public Cursor query(@NonNull Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder)
    {
        // Get access to underlying database (read-only for query)
        final SQLiteDatabase db = mTubeLineDbHelper.getReadableDatabase();

        // Write URI match code and set a variable to return a Cursor
        int match = sUriMatcher.match(uri);
        Cursor retCursor;

        // Query for the lines directory and write a default case
        switch (match)
        {
            // Query for the lines directory
            case LINES:
                retCursor = db.query(TubeLineContract.TubeLineEntry.TABLE_NAME,
                        projection,
                        selection,
                        selectionArgs,
                        null,
                        null,
                        sortOrder);
                break;
            // Default exception
            default:
                throw new UnsupportedOperationException("Unknown uri: " + uri);
        }

        // Set a notification URI on the Cursor and return that Cursor
        retCursor.setNotificationUri(getContext().getContentResolver(), uri);

        // Return the desired Cursor
        return retCursor;
    }

    /**
     * Update inventory 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.
     */
    @Override
    public int update(@NonNull Uri uri, ContentValues values, String selection,
                      String[] selectionArgs)
    {
        //Keep track of if an update occurs
        int rowsUpdated;
        final int match = sUriMatcher.match(uri);
        switch (match) {
            case LINE_WITH_ID:
                String id = uri.getPathSegments().get(1);
                rowsUpdated = mTubeLineDbHelper.getWritableDatabase().update(TubeLineContract.TubeLineEntry.TABLE_NAME, values, "_id=?", new String[]{id});
                break;
            default:
                throw new UnsupportedOperationException("Not yet implemented");
        }
        if (rowsUpdated != 0)
        {
            //set notifications if a row was updated
            getContext().getContentResolver().notifyChange(uri, null);
        }

        // return number of rows updated
        return rowsUpdated;
    }

    // Implement delete to delete a single row of data
    @Override
    public int delete(@NonNull Uri uri, String selection, String[] selectionArgs)
    {
        // Get access to the database and write URI matching code to recognize a single item
        final SQLiteDatabase db = mTubeLineDbHelper.getWritableDatabase();

        int match = sUriMatcher.match(uri);
        // Keep track of the number of deleted rows
        int rowsDeleted; // starts as 0

        //if (null == selection) selection = "1";
        // Write the code to delete a single row of data
        // [Hint] Use selections to delete an item by its row ID
        switch (match)
        {
            // Handle the single item case, recognized by the ID included in the URI path
            case LINE_WITH_ID:
                // Get the line ID from the URI path
               String id = uri.getPathSegments().get(1);
                // Use selections/selectionArgs to filter for this ID

                rowsDeleted = db.delete(TubeLineContract.TubeLineEntry.TABLE_NAME, "id=?",
                        new String[]{id});

                break;
            default:
                throw new UnsupportedOperationException("Unknown uri: " + uri);
        }

        // Notify the resolver of a change and return the number of items deleted
        if (rowsDeleted != 0)
        {
            // A line was deleted, set notification
            getContext().getContentResolver().notifyChange(uri, null);
        }

        // Return the number of rows deleted
        return rowsDeleted;
    }

    @Override
    public String getType(@NonNull Uri uri)
    {
        final int match = sUriMatcher.match(uri);
        switch (match) {
            case LINES:
                return TubeLineContract.TubeLineEntry.CONTENT_LIST_TYPE;
            case LINE_WITH_ID:
                return "vnd.android.cursor.item" + "/" + TubeLineContract.CONTENT_AUTHORITY + "/" + TubeLineContract.PATH_LINES;
            default:
                throw new UnsupportedOperationException("Not yet implemented");
        }
    }
}

活动:

 //add to favorites
    favoritesButton.setOnClickListener(new View.OnClickListener()
    {
        @Override
        public void onClick(View view)
        {
            ContentValues values = new ContentValues();
            values.put(TubeLineContract.TubeLineEntry.COLUMN_LINES_ID, lines.getLineId());
            values.put(TubeLineContract.TubeLineEntry.COLUMN_LINES_NAME, lines.getLineName());

//Line 91 error
            Uri uri = getContentResolver().insert(TubeLineContract.TubeLineEntry.CONTENT_URI, values);

            if (uri != null)
            {
                Toast.makeText(getBaseContext(), uri.toString(), Toast.LENGTH_LONG).show();
                Toast.makeText(StationListActivity.this, R.string.favorites_added, Toast.LENGTH_SHORT).show();
                favoritesButton.setVisibility(View.GONE);
            }
        }
    });
// Kick off the loader
       getLoaderManager().initLoader(FAVORITES_LOADER, null, this);
        }

1 个答案:

答案 0 :(得分:2)

尝试将client1.myproject.com client2.myproject.com client3.myproject.com 更改为if (id == 0)

从insert返回的值将是插入行的ID。 id将为1或更大(如果未插入,则为-1,但不会插入0)。

因此,看起来好像您实际上正在插入,但是插入后只是走错了路径。

  • 请注意,这确实是假设您未使用 WITHOUT ROWID 表,并且您之前未插入负ID值以及最高的 id 没有达到9223372036854754775807(两种情况都不太可能)。
  • 如果您当时的行为可能会有所不同。
  • 如果表是WITHOUT ROWID表,将返回 0