2017-08-30 37 views
1

我遇到了一个奇怪的问题,其中检查不Null不工作。我试图检查值是否为空,如果是这样,弹出一个警告,说“成分需要一个名字”我不知道为什么,但我似乎无法弄清楚这应该是相当简单的。Android - 检查是否为空无法正常工作

我还是Kotlin的新手,所以我怀疑我的Java对Kotlin的思考过程在这里是有缺陷的。

任何帮助和建议将不胜感激!

的部分,我遇到的麻烦:

// Check that the name is not null 
    (if (values != null) values else throw KotlinNullPointerException()).getAsString(IngredientEntry.COLUMN_INGREDIENT_NAME) ?: throw IllegalArgumentException("Ingredient requires a name") 

完整的类。我倾向于评论废话的一切,所以希望它是有道理的:

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.util.Log 
import 
import kotlin.properties.Delegates 

class DbContentProvider : ContentProvider() { 

// Database helper object 
private var mDbHelper: DbHelper by Delegates.notNull() 


// Order the of ingredients in the list view 
private val ingredientSortBy = IngredientEntry.COLUMN_INGREDIENT_NAME 

override fun onCreate(): Boolean { 
    mDbHelper = DbHelper(context) 
    return true 
} 

override fun query(uri: Uri, projection: Array<String>?, selection: String?, selectionArgs: Array<String>?, 
        sortOrder: String?): Cursor? { 

    // Get readable database 
    val database: SQLiteDatabase = mDbHelper.readableDatabase 

    // This cursor will hold the result of the query 
    val cursor: Cursor 

    // Figure out if the URI matcher can match the URI to a specific code 
    val match = sUriMatcher.match(uri) 
    when (match) { 
     INGREDIENTS -> 
      // For the INGREDIENTS code, query the ingredients table directly with the given 
      // projection, selection, selection arguments, and sort order. The cursor 
      // could contain multiple rows of the ingredients table. 
      // Query is uri, projection, selection, selectionArgs, sortOrder and orderBy 
      cursor = database.query(IngredientEntry.TABLE_NAME, projection, selection, selectionArgs, null, null, ingredientSortBy) 
     INGREDIENTS_ID -> { 
      // For the INGREDIENTS_ID code, extract out the ID from the URI. 
      // For an example URI such as "content://com.example.android.ingredients/ingredients/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. 
      val mSelection = IngredientEntry._ID + "=?" 
      val mSelectionArgs = arrayOf(ContentUris.parseId(uri).toString()) 

      // This will perform a query on the ingredients table where the _id equals 3 to return a 
      // Cursor containing that row of the table. 
      // Query is uri, projection, selection, selectionArgs, sortOrder and orderBy 
      cursor = database.query(IngredientEntry.TABLE_NAME, projection, mSelection, mSelectionArgs, null, null, ingredientSortBy) 
     } 
     else -> throw IllegalArgumentException("Cannot query unknown URI " + uri) 
    } 

    // Set notification URI on the Cursor, 
    // so we know what content URI the Cursor was created for. 
    // If the data at this URI changes, then we know we need to update the Cursor. 
    cursor.setNotificationUri(context.contentResolver, uri) 

    // Return the cursor 
    return cursor 
} 

override fun insert(uri: Uri, contentValues: ContentValues?): Uri? { 
    val match = sUriMatcher.match(uri) 
    when (match) { 
     INGREDIENTS -> return insertIngredient(uri, contentValues) 
     else -> throw IllegalArgumentException("Insertion is not supported for " + uri) 
    } 
} 

/** 
* Insert an ingredient into the database with the given content values. Return the new content URI 
* for that specific row in the database. 
*/ 
private fun insertIngredient(uri: Uri, contentValues: ContentValues?): Uri? { 
    // Check that the name is not null or empty 
    val ingredientName = contentValues?.getAsString(IngredientEntry.COLUMN_INGREDIENT_NAME) 
    if (ingredientName == null || ingredientName.isEmpty()) { 
     throw IllegalArgumentException("Ingredient requires valid category") 
    } 

    // Check that the category is valid 
    val category = contentValues.getAsInteger(IngredientEntry.COLUMN_INGREDIENT_CATEGORY) 
    if (category == null || !IngredientEntry.isValidCategory(category)) { 
     throw IllegalArgumentException("Ingredient requires valid category") 
    } 

    // Check that the measurement is valid 
    val measurement = contentValues.getAsInteger(IngredientEntry.COLUMN_INGREDIENT_MEASUREMENT) 
    if (measurement == null || !IngredientEntry.isValidMeasurement(measurement)) { 
     throw IllegalArgumentException("Ingredient requires valid measurement") 
    } 

    // No need to check the description, any value is valid (including null). 

    // Get writable database 
    val database = mDbHelper.writableDatabase 

    // Insert the new ingredient with the given values 
    val id = database.insert(IngredientEntry.TABLE_NAME, null, contentValues) 
    // If the ID is -1, then the insertion failed. Log an error and return null. 
    if (id == (-1).toLong()) { 
     Log.e(LOG_TAG, "Failed to insert row for " + uri) 
     return null 
    } 

    // Notify all listeners that the data has changed for the ingredient content URI 
    context.contentResolver.notifyChange(uri, null) 

    // Return the new URI with the ID (of the newly inserted row) appended at the end 
    return ContentUris.withAppendedId(uri, id) 
} 

override fun update(uri: Uri, contentValues: ContentValues?, selection: String?, 
        selectionArgs: Array<String>?): Int { 

    val match = sUriMatcher.match(uri) 
    return when (match) { 
     INGREDIENTS -> updateIngredient(uri, contentValues, selection, selectionArgs) 
     INGREDIENTS_ID -> { 
      // For the INGREDIENTS_ID 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. 
      val mSelection = IngredientEntry._ID + "=?" 
      val mSelectionArgs = arrayOf(ContentUris.parseId(uri).toString()) 
      updateIngredient(uri, contentValues, mSelection, mSelectionArgs) 
     } 
     else -> throw IllegalArgumentException("Update is not supported for " + uri) 
    } 
} 

/** 
* Update ingredients in the database with the given content contentValues. Apply the changes to the rows 
* specified in the selection and selection arguments (which could be 0 or 1 or more ingredients). 
* Return the number of rows that were successfully updated. 
*/ 
private fun updateIngredient(uri: Uri, contentValues: ContentValues?, selection: String?, selectionArgs: Array<String>?): Int { 
    // If the {@link IngredientEntry#COLUMN_INGREDIENT_NAME} key is present, 
    // check that the name value is not null. 
    if ((if (contentValues != null) contentValues else throw KotlinNullPointerException()).containsKey(IngredientEntry.COLUMN_INGREDIENT_NAME)) { 
     contentValues.getAsString(IngredientEntry.COLUMN_INGREDIENT_NAME) ?: throw IllegalArgumentException("Ingredient requires a name") 
    } 

    // If the {@link IngredientEntry#COLUMN_INGREDIENT_CATEGORY} key is present, 
    // check that the category value is valid. 
    if (contentValues.containsKey(IngredientEntry.COLUMN_INGREDIENT_CATEGORY)) { 
     val category = contentValues.getAsInteger(IngredientEntry.COLUMN_INGREDIENT_CATEGORY) 
     if (category == null || !IngredientEntry.isValidCategory(category)) { 
      throw IllegalArgumentException("Ingredient requires valid category") 
     } 
    } 

    // If the {@link IngredientEntry#COLUMN_INGREDIENT_MEASUREMENT} key is present, 
    // check that the measurement value is valid. 
    if (contentValues.containsKey(IngredientEntry.COLUMN_INGREDIENT_MEASUREMENT)) { 
     val measurement = contentValues.getAsInteger(IngredientEntry.COLUMN_INGREDIENT_MEASUREMENT) 
     if (measurement == null || !IngredientEntry.isValidMeasurement(measurement)) { 
      throw IllegalArgumentException("Ingredient requires valid measurement") 
     } 
    } 

    // No need to check the description, any value is valid (including null). 

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

    // Otherwise, get writable database to update the data 
    val database = mDbHelper.writableDatabase 

    // Perform the update on the database and get the number of rows affected 
    val rowsUpdated = database.update(IngredientEntry.TABLE_NAME, contentValues, 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) { 
     context.contentResolver.notifyChange(uri, null) 
    } 

    // Return the number of rows updated 
    return rowsUpdated 
} 

override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int { 

    // Get writable database 
    val database = mDbHelper.writableDatabase 

    // Track the number of rows that were deleted 
    val rowsDeleted: Int 

    val match = sUriMatcher.match(uri) 
    rowsDeleted = when (match) { 
     INGREDIENTS -> 
      // Delete all rows that match the selection and selection args 
      database.delete(IngredientEntry.TABLE_NAME, selection, selectionArgs) 
     INGREDIENTS_ID -> { 
      // Delete a single row given by the ID in the URI 
      val mSelection = IngredientEntry._ID + "=?" 
      val mSelectionArgs = arrayOf(ContentUris.parseId(uri).toString()) 
      database.delete(IngredientEntry.TABLE_NAME, mSelection, mSelectionArgs) 
     } 
     else -> throw IllegalArgumentException("Deletion is not supported for " + uri) 
    } 

    // If 1 or more rows were deleted, then notify all listeners that the data at the 
    // given URI has changed 
    if (rowsDeleted != 0) { 
     context.contentResolver.notifyChange(uri, null) 
    } 

    // Return the number of rows deleted 
    return rowsDeleted 
} 

override fun getType(uri: Uri): String? { 
    val match = sUriMatcher.match(uri) 
    return when (match) { 
     INGREDIENTS -> IngredientEntry.CONTENT_LIST_TYPE 
     INGREDIENTS_ID -> IngredientEntry.CONTENT_ITEM_TYPE 
     else -> throw IllegalStateException("Unknown URI $uri with match $match") 
    } 
} 

companion object { 

    /** Tag for the log messages */ 
    val LOG_TAG: String? = ContentProvider::class.java.simpleName 

    /** URI matcher code for the content URI for the ingredients table */ 
    private val INGREDIENTS = 100 

    /** URI matcher code for the content URI for a single ingredient in the ingredients table */ 
    private val INGREDIENTS_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 val sUriMatcher = UriMatcher(UriMatcher.NO_MATCH) 

    // Static initializer. This is run the first time anything is called from this class. 
    init { 
     // 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.ingredients/ingredients" will map to the 
     // integer code {@link #INGREDIENTS}. This URI is used to provide access to MULTIPLE rows 
     // of the ingredients table. 
     sUriMatcher.addURI(DbContract.CONTENT_AUTHORITY, DbContract.PATH_INGREDIENTS, INGREDIENTS) 

     // The content URI of the form "content://com.example.android.ingredients/ingredients/#" will map to the 
     // integer code {@link #INGREDIENTS_ID}. This URI is used to provide access to ONE single row 
     // of the ingredients table. 
     // 
     // In this case, the "#" wildcard is used where "#" can be substituted for an integer. 
     // For example, "content://com.example.android.ingredients/ingredients/3" matches, but 
     // "content://com.example.android.ingredients/ingredients" (without a number at the end) doesn't match. 
     sUriMatcher.addURI(DbContract.CONTENT_AUTHORITY, DbContract.PATH_INGREDIENTS + "/#", INGREDIENTS_ID) 
    } 
} 
} 

我更新了我的方法,现在它捕获空或空。但是,如果有人将姓名字段留空,它显然会使我的应用程序崩溃。关于如何让用户知道名称字段必须填充的任何想法,而不是使应用程序崩溃并停止创建原料?谢谢!

另一个版本我做了捕捉异常和犯规崩溃的应用程序,但仍允许用户创建没有名字的成分。呸!

// Check that the name EditText field is not null or empty 
    val ingredientName = contentValues?.getAsString(IngredientEntry.COLUMN_INGREDIENT_NAME) 
    if (ingredientName == null || ingredientName.isEmpty()) { 
     try { 
      throw Exception ("Ingredient requires a name") 
     } catch (exception: Exception) { 
      System.out.println(exception) 
     } 
    } 
+0

你能告诉你如何调用'乐趣插入(URI:URI,contentValues:ContentValues?):乌里'方法? – Hohenhiem

+0

该方法是一个必需的重写,它在我的应用程序的其他任何地方都没有使用。 – Dallas

回答

0

可以if语句和省略,因为这样做反而

values?.getAsString(IngredientEntry.COLUMN_INGREDIENT_NAME) ?: throw IllegalArgumentException("Ingredient requires a name") 

你Elvis操作符不工作的if语句永远不会返回空值,其无论是字符串或NPE。

你实际上可以通过使用let块来使你的代码更好。像这样的东西。

values?.let{ 
    //logic here that uses value, refer to value as it 
} ?: IllegalArgumentException() 

编辑

values?.let{ 
    if(it.getAsString(IngredientEntry.COLUMN_INGREDIENT_NAME).isEmpty()) throw IllegalArgumentException() 
    else // do your logic 
} 
+0

谢谢。我尝试了你的建议,但没有任何效果。仍然允许我添加一个没有名字的原料。 – Dallas

+0

它可能是值根本不为空。你可以用'.isEmpty()'检查是否为空。 请检查编辑 – Hohenhiem

+0

你可能是对的。我会尽力并稍后再回来查看。 – Dallas

相关问题