完整项目here 当我调用getContentResolver()。insert()并且我不明白为什么时,我的程序崩溃了。我正在学习android中的sqlite数据库,所以我的任务是为商店制作一个库存应用程序,我记录项目,价格,数量,供应商和描述。主要活动包含所有项目的列表视图,按钮包含对编辑器活动的更改,其中我将项目添加到数据库,这是EditorActivity。我认为它不是在向Uri添加_id:
package com.example.android.inventory;
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;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import com.example.android.inventory.data.InventoryContract.InventoryEntry;
public class EditorActivity extends AppCompatActivity implements
LoaderManager.LoaderCallbacks<Cursor> {
private static final int EXISTING_INVENTORY_LOADER = 0;
private Uri mCurrentItemUri;
private EditText mItemName;
private EditText mItemPrice;
private EditText mItemQuantity;
private EditText mItemSupplier;
private EditText mItemDescription;
private boolean mItemHasChanged = false;
private View.OnTouchListener mTouchListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
mItemHasChanged = true;
return false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_editor);
Intent intent = getIntent();
mCurrentItemUri = intent.getData();
if (mCurrentItemUri == null) {
setTitle(getString(R.string.add_item));
invalidateOptionsMenu();
} else {
setTitle(getString(R.string.update_item));
getLoaderManager().initLoader(EXISTING_INVENTORY_LOADER, null, this);
}
mItemName = (EditText) findViewById(R.id.name_edit_view);
mItemPrice = (EditText) findViewById(R.id.price_edit_view);
mItemQuantity = (EditText) findViewById(R.id.quantity_edit_view);
mItemSupplier = (EditText) findViewById(R.id.supplier_edit_view);
mItemDescription = (EditText) findViewById(R.id.description_edit_view);
mItemName.setOnTouchListener(mTouchListener);
mItemPrice.setOnTouchListener(mTouchListener);
mItemQuantity.setOnTouchListener(mTouchListener);
mItemSupplier.setOnTouchListener(mTouchListener);
mItemDescription.setOnTouchListener(mTouchListener);
}
private void saveItem() {
String nameStr = mItemName.getText().toString().trim();
String priceStr = mItemPrice.getText().toString().trim();
String quantityStr = mItemQuantity.getText().toString().trim();
String supplierStr = mItemSupplier.getText().toString().trim();
String descriptionStr = mItemDescription.getText().toString().trim();
if (mCurrentItemUri == null && TextUtils.isEmpty(nameStr) && TextUtils.isEmpty(priceStr) && TextUtils.isEmpty(quantityStr)
&& TextUtils.isEmpty(supplierStr) && TextUtils.isEmpty(descriptionStr)) {
return;
}
ContentValues values = new ContentValues();
values.put(InventoryEntry.COLUMN_ITEM_NAME, nameStr);
int price = 0;
int quantity = 0;
if (!TextUtils.isEmpty(priceStr))
price = Integer.parseInt(priceStr);
if (!TextUtils.isEmpty(quantityStr))
quantity = Integer.parseInt(quantityStr);
values.put(InventoryEntry.COLUMN_ITEM_PRICE, price);
values.put(InventoryEntry.COLUMN_ITEM_QUANTITY, quantity);
values.put(InventoryEntry.COLUMN_ITEM_SUPPLIER, supplierStr);
values.put(InventoryEntry.COLUMN_ITEM_DESCRIPTION, descriptionStr);
if (mCurrentItemUri == null) {
Uri newUri = getContentResolver().insert(InventoryEntry.CONTENT_URI, values);
if (newUri == null) {
Toast.makeText(this, getString(R.string.error_insert_item),
Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, R.string.new_item_add,
Toast.LENGTH_SHORT).show();
}
} else {
int rowsAffected = getContentResolver().update(mCurrentItemUri, values, null, null);
if (rowsAffected == 0) {
Toast.makeText(this, R.string.error_update_item,
Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, R.string.update_item_success,
Toast.LENGTH_SHORT).show();
}
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.editor_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_save:
saveItem();
finish();
return true;
case android.R.id.home:
NavUtils.navigateUpFromSameTask(EditorActivity.this);
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onBackPressed() {
finish();
super.onBackPressed();
}
@Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
String[] projection = {
InventoryEntry._ID,
InventoryEntry.COLUMN_ITEM_NAME,
InventoryEntry.COLUMN_ITEM_PRICE,
InventoryEntry.COLUMN_ITEM_QUANTITY,
InventoryEntry.COLUMN_ITEM_SUPPLIER,
InventoryEntry.COLUMN_ITEM_DESCRIPTION};
return new CursorLoader(this, mCurrentItemUri, projection, null, null, null);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
if (cursor == null || cursor.getCount() < 1) {
return;
}
if (cursor.moveToFirst()) {
int nameColumnIndex = cursor.getColumnIndex(InventoryEntry.COLUMN_ITEM_NAME);
int priceColumnIndex = cursor.getColumnIndex(InventoryEntry.COLUMN_ITEM_PRICE);
int quantityColumnIndex = cursor.getColumnIndex(InventoryEntry.COLUMN_ITEM_QUANTITY);
int supplierColumnIndex = cursor.getColumnIndex(InventoryEntry.COLUMN_ITEM_SUPPLIER);
int descriptionColumnIndex = cursor.getColumnIndex(InventoryEntry.COLUMN_ITEM_DESCRIPTION);
String name = cursor.getString(nameColumnIndex);
String price = cursor.getString(priceColumnIndex) + getString(R.string.currency_symbol);
String quantity = cursor.getString(quantityColumnIndex);
String supplier = cursor.getString(supplierColumnIndex);
String description = cursor.getString(descriptionColumnIndex);
mItemName.setText(name);
mItemPrice.setText(price);
mItemQuantity.setText(quantity);
mItemSupplier.setText(supplier);
mItemDescription.setText(description);
}
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
mItemName.setText("");
mItemPrice.setText("");
mItemQuantity.setText("");
mItemSupplier.setText("");
mItemDescription.setText("");
}
}
这是InventoryProvider:
package com.example.android.inventory.data;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
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;
import com.example.android.inventory.data.InventoryContract.InventoryEntry;
import static com.example.android.inventory.data.InventoryDbHelper.LOG_TAG;
public class InventoryProvider extends ContentProvider {
private static final int INVENTORY = 100;
private static final int INVENTORY_ID = 101;
private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
sUriMatcher.addURI(InventoryContract.CONTENT_AUTHORITY, InventoryContract.PATH_INVENTORY, INVENTORY);
sUriMatcher.addURI(InventoryContract.CONTENT_AUTHORITY, InventoryContract.PATH_INVENTORY + "/#", INVENTORY_ID);
}
private InventoryDbHelper mDbHelper;
@Override
public boolean onCreate() {
mDbHelper = new InventoryDbHelper(getContext());
return true;
}
@Nullable
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteDatabase database = mDbHelper.getReadableDatabase();
Cursor cursor;
int match = sUriMatcher.match(uri);
switch (match) {
case INVENTORY:
cursor = database.query(InventoryEntry.TABLE_NAME, projection, selection, selectionArgs,
null, null, sortOrder);
break;
case INVENTORY_ID:
selection = InventoryEntry._ID + "=?";
selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
cursor = database.query(InventoryEntry.TABLE_NAME, projection, selection, selectionArgs,
null, null, sortOrder);
break;
default:
throw new IllegalArgumentException("Cannot query unknown URI " + uri);
}
cursor.setNotificationUri(getContext().getContentResolver(), uri);
// Return the cursor
return cursor;
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
final int match = sUriMatcher.match(uri);
switch (match) {
case INVENTORY:
return InventoryEntry.CONTENT_LIST_TYPE;
case INVENTORY_ID:
return InventoryEntry.CONTENT_ITEM_TYPE;
default:
throw new IllegalStateException("Unknown URI " + uri + " with match " + match);
}
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
final int match = sUriMatcher.match(uri);
switch (match) {
case INVENTORY:
return insertItem(uri, contentValues);
default:
throw new IllegalArgumentException("Insertion is not supported for " + uri);
}
}
private Uri insertItem(Uri uri, ContentValues values){
/** TODO: verificar se os inputs são validos **/
SQLiteDatabase database = mDbHelper.getWritableDatabase();
// Insert the new pet with the given values
long id = database.insert(InventoryEntry.TABLE_NAME, null, values);
// If the ID is -1, then the insertion failed. Log an error and return null.
if (id == -1) {
Log.e(LOG_TAG, "Failed to insert row for " + uri);
return null;
}
getContext().getContentResolver().notifyChange(uri, null);
return ContentUris.withAppendedId(uri, id);
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase database = mDbHelper.getWritableDatabase();
// Track the number of rows that were deleted
int rowsDeleted;
final int match = sUriMatcher.match(uri);
switch (match) {
case INVENTORY:
// Delete all rows that match the selection and selection args
rowsDeleted = database.delete(InventoryEntry.TABLE_NAME, selection, selectionArgs);
break;
case INVENTORY_ID:
// Delete a single row given by the ID in the URI
selection = InventoryEntry._ID + "=?";
selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
rowsDeleted = database.delete(InventoryEntry.TABLE_NAME, selection, selectionArgs);
break;
default:
throw new IllegalArgumentException("Deletion is not supported for " + uri);
}
if (rowsDeleted != 0) {
getContext().getContentResolver().notifyChange(uri, null);
}
// Return the number of rows deleted
return rowsDeleted;
}
@Override
public int update(Uri uri, ContentValues contentValues, String selection,
String[] selectionArgs) {
final int match = sUriMatcher.match(uri);
switch (match) {
case INVENTORY:
return updateInventory(uri, contentValues, selection, selectionArgs);
case INVENTORY_ID:
selection = InventoryEntry._ID + "=?";
selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
return updateInventory(uri, contentValues, selection, selectionArgs);
default:
throw new IllegalArgumentException("Update is not supported for " + uri);
}
}
private int updateInventory(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
SQLiteDatabase db = mDbHelper.getWritableDatabase();
int rowsUpdated = db.update(InventoryEntry.TABLE_NAME, values, selection, selectionArgs);
if (rowsUpdated != 0) {
getContext().getContentResolver().notifyChange(uri, null);
}
// Return the number of rows updated
return rowsUpdated;
}
}
InventoryContract:
package com.example.android.inventory.data;
import android.content.ContentResolver;
import android.net.Uri;
import android.provider.BaseColumns;
/**
* Created by Rodrigo on 23/07/2017.
*/
public class InventoryContract {
private InventoryContract() {
}
public static final String CONTENT_AUTHORITY = "com.example.android.inventory";
public static final String PATH_INVENTORY = "items";
public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY);
public static final class InventoryEntry implements BaseColumns {
public static final Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, PATH_INVENTORY);
public static final String CONTENT_LIST_TYPE =
ContentResolver.CURSOR_DIR_BASE_TYPE + "/" + CONTENT_AUTHORITY + "/" + PATH_INVENTORY;
public static final String CONTENT_ITEM_TYPE =
ContentResolver.CURSOR_ITEM_BASE_TYPE + "/" + CONTENT_AUTHORITY + "/" + PATH_INVENTORY;
public static String TABLE_NAME = "items";
public final static String _ID = BaseColumns._ID;
public static String COLUMN_ITEM_NAME = "item";
public static String COLUMN_ITEM_PRICE = "price";
public static String COLUMN_ITEM_QUANTITY = "quantity";
public static String COLUMN_ITEM_SUPPLIER = "supplier";
public static String COLUMN_ITEM_DESCRIPTION = "description";
public static String COLUMN_ITEM_IMAGE = "image";
}
}
和InventoryDbHelper:
package com.example.android.inventory.data;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import com.example.android.inventory.data.InventoryContract.InventoryEntry;
public class InventoryDbHelper extends SQLiteOpenHelper {
public static final String LOG_TAG = InventoryDbHelper.class.getSimpleName();
private static final String DATABASE_NAME = "inventory.db";
private static final int DATABASE_VERSION = 1;
public InventoryDbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
String SQL_CREATE_INVENTORY_TABLE = "CREATE TABLE " + InventoryEntry.TABLE_NAME + " ("
+ InventoryEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ InventoryEntry.COLUMN_ITEM_NAME + " TEXT NOT NULL, "
+ InventoryEntry.COLUMN_ITEM_PRICE + " INTEGER NOT NULL DEFAULT 0,"
+ InventoryEntry.COLUMN_ITEM_QUANTITY + " INTEGER NOT NULL DEFAULT 0, "
+ InventoryEntry.COLUMN_ITEM_SUPPLIER + " TEXT NOT NULL,"
+ InventoryEntry.COLUMN_ITEM_DESCRIPTION + "TEXT);";
// Execute the SQL statement
db.execSQL(SQL_CREATE_INVENTORY_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
错误:
07-26 01:54:11.067 15263-15263/com.example.android.inventory E/ActivityThread: Failed to find provider info for com.example.android.inventory
07-26 01:54:11.068 15263-15263/com.example.android.inventory D/AndroidRuntime: Shutting down VM
07-26 01:54:11.068 15263-15263/com.example.android.inventory E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.android.inventory, PID: 15263
java.lang.IllegalArgumentException: Unknown URL content://com.example.android.inventory/items
at android.content.ContentResolver.insert(ContentResolver.java:1270)
at com.example.android.inventory.EditorActivity.saveItem(EditorActivity.java:114)
at com.example.android.inventory.EditorActivity.onOptionsItemSelected(EditorActivity.java:149)
at android.app.Activity.onMenuItemSelected(Activity.java:3204)
at android.support.v4.app.FragmentActivity.onMenuItemSelected(FragmentActivity.java:360)
at android.support.v7.app.AppCompatActivity.onMenuItemSelected(AppCompatActivity.java:194)
at android.support.v7.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:110)
at android.support.v7.app.AppCompatDelegateImplV9.onMenuItemSelected(AppCompatDelegateImplV9.java:676)
at android.support.v7.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:821)
at android.support.v7.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:158)
at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:968)
at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:958)
at android.support.v7.widget.ActionMenuView.invokeItem(ActionMenuView.java:623)
at android.support.v7.view.menu.ActionMenuItemView.onClick(ActionMenuItemView.java:147)
at android.view.View.performClick(View.java:5610)
at android.view.View$PerformClick.run(View.java:22265)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)
清单:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.inventory">
<provider
android:name=".data.InventoryProvider"
android:authorities="com.example.android.inventory"
android:exported="false" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".InventoryActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".EditorActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".InventoryActivity" />
</activity>
</application>
</manifest>