Почему мы должны «получить стабильную ссылку» в Kotlin/Android?

Я читал кодовую лабораторию Android CameraX: https://codelabs.developers.google.com/codelabs/camerax-getting-started#4

Упрощенный фрагмент кода выглядит так:

class MainActivity : AppCompatActivity() {
    private var imageCapture: ImageCapture? = null
    
    //(some other codes here...)

    private fun takePhoto() {
        // Get a stable reference of the modifiable image capture use case
        val imageCapture = imageCapture ?: return
        
        //(some other codes here...)

    }
}

В кодлабе написано:

Во-первых, получите ссылку на вариант использования ImageCapture.

Зачем нам новая ссылка imageCapture в takePhoto()?

Разве мы не можем просто использовать imageCapture в MainActivity?

Это для какой-то "лучшей практики" или я что-то упустил?

Любой совет будет принят с благодарностью!

Как вы думаете, что произойдет, если какой-то другой код в другом потоке изменит imageCapture в середине takePhoto?

Louis Wasserman 25.12.2020 07:16

@Louis Wasserman Я думаю, что это просто ссылка, а не копирование, поэтому измененный imageCapture будет использоваться в takePhoto даже в исходном коде лаборатории кода, не так ли?

starriet 25.12.2020 07:32

В середине takePhoto — так что, если takePhoto не сделает снимок, переменная может быть изменена в середине функции, что может вызвать хаос.

Louis Wasserman 25.12.2020 07:53

@LouisWasserman Вы должны быть правы, но я действительно не понимаю ... Когда вы сказали «моментальный снимок», это означает «копирование» imageCapture? Если imageCapture копируется в начале метода takePhoto, то ваш комментарий имеет смысл. но я думаю, что это не копия, это просто ссылка на объект. Извините, если я что-то не так понял. Не могли бы вы объяснить немного больше?

starriet 25.12.2020 08:53

Это копирование ссылки.

Louis Wasserman 25.12.2020 17:32

@LouisWasserman О, вы говорите, что делаете снимок (клон) «эталона», а не самого объекта? Хорошо, я понял. Поэтому, когда вы сказали «... если какой-то другой код в другом потоке« модифицирует »imageCapture ...», «модифицирует» означает назначение другого объекта, а не изменение самого исходного объекта. Правильно ли я понял? Таким образом, если сам исходный объект изменен (не переназначен) в другом потоке, это все равно вызовет хаос, если только мы не скопируем сам объект. Пожалуйста, дайте мне знать, если я неправильно понял. Спасибо за ваши комментарии!

starriet 26.12.2020 13:03

@LouisWasserman Я думаю, что ADM прокомментировал то же самое, что я упомянул, в комментарии к ответу ниже: «Даже если переменная изменяется в середине, неглубокая копия также будет изменена. Вот почему они все одинаковы. Только после клонирования мы можем убедитесь, что локальная ссылка не влияет на фактическую».

starriet 26.12.2020 13:12

Да, это правильно. Если вы правильно используете неизменяемые объекты, то эта копия ссылки — это все, что вам нужно.

Louis Wasserman 26.12.2020 19:08
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
8
138
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Это эквивалентно нулевой проверке.

stable reference -> Not null reference 

это похоже на

if (imageCapture==null) return;

Также в лаборатории кода они упомянули то же самое.

Во-первых, получите ссылку на вариант использования ImageCapture. Если вариант использования нулевой, выйдите из функции. Это будет пустым, если вы нажмете кнопку фото до настройки захвата изображения. Без оператора return приложение вылетит, если оно будет нулевым.

Таким образом, в основном вы исключаете возможность NPE, который может быть выполнен несколькими способами, и они используют для этого локальную переменную Another. это также можно сделать с помощью let.

imageCapture?.let{
 // code goes here
   }

...что можно сделать несколькими способами, и они используют для этого локальную переменную Another..." Так что это всего лишь один из многих способов избежать NPE, верно? Большое спасибо! Теперь я понимаю.

starriet 25.12.2020 08:59

Это не эквивалентно, if (imageCapture==null) return; все равно не поможет, если переменная изменилась в середине, вы все равно получите странные вещи, и компилятор не допустит ненулевые . вызовы объекта даже с этой проверкой в ​​том же отношении. ?.let сделает неглубокую копию, такую ​​же, как фрагмент в вопросе, который будет защищен от изменений извне.

Animesh Sahu 25.12.2020 14:04

Несмотря на то, что переменная изменяется в середине, неглубокая копия также будет изменена. Вот поэтому они все одинаковые. Только после клонирования мы можем убедиться, что локальная ссылка не влияет на фактическую.

ADM 25.12.2020 14:08
private var imageCapture: ImageCapture? = null

С помощью этой строки вы присваиваете значение null переменной imageCapture. Теперь, когда вы начнете использовать takePhoto(), как компилятор узнает, что imageCapture больше не является нулевым?

Как описывает @ADM, вы можете использовать

imageCapture?.let{
  //your code goes here
}

если ты хочешь. В основном это гарантирует, что вы ничего не вызываете для объекта, допускающего значение NULL.

Другие вопросы по теме