Android – Check for Not Null не работает как ожидается

Я столкнулся с нечетной проблемой, когда мой чек для Null не работает. Я пытаюсь проверить, являются ли значения пустыми, и если это всплывает предупреждение о том, что «Ингредиент требует имя», я не знаю, почему, но я не могу понять, что это должно быть довольно просто.

Я все еще новичок в 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 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 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) } } 

Вы можете опустить оператор if и сделать это вместо этого

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

Ваш оператор elvis не работает, потому что оператор if никогда не возвращает нуль, это либо строка, либо NPE.

Вы можете сделать код лучше, используя let block. что-то вроде этого.

 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 } 
Intereting Posts
В Котлине, как сделать свойство доступным только для определенного типа Котлин «Смарт-литье невозможно, потому что к этому моменту собственность могла быть изменена» Можно ли создать приложение для Android, которое использует Kotlin с make или Soong? Вводные общие типы в Котлин с кинжалом 2 Есть ли способ реализовать разбиение на страницы весной? Kotlin – переопределить / реализовать функцию доступа к массиву Kotlin werid компилирует ошибку, связанную с дженериками и автоматическим типом Mockito Mocks ведет себя как шпионы: Котлин Можно ли использовать Allatori в исходном коде Kotlin? TornadoFX – Создание MVP-дизайна Когда я должен использовать let {} и когда просто просто! = Null Я хочу определить, является ли класс JVM классом Котлина или нет Обработчик ответа соответствия с запросом в VertX Настройка Kotlin для Gradle без поддержки IDE – классы Kotlin не попадают в classpath Класс данных Kotlin Jackson @ JsonProperty не отмечен