Я читал кодовую лабораторию 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
?
Это для какой-то "лучшей практики" или я что-то упустил?
Любой совет будет принят с благодарностью!
@Louis Wasserman Я думаю, что это просто ссылка, а не копирование, поэтому измененный imageCapture
будет использоваться в takePhoto
даже в исходном коде лаборатории кода, не так ли?
В середине takePhoto — так что, если takePhoto не сделает снимок, переменная может быть изменена в середине функции, что может вызвать хаос.
@LouisWasserman Вы должны быть правы, но я действительно не понимаю ... Когда вы сказали «моментальный снимок», это означает «копирование» imageCapture
? Если imageCapture
копируется в начале метода takePhoto
, то ваш комментарий имеет смысл. но я думаю, что это не копия, это просто ссылка на объект. Извините, если я что-то не так понял. Не могли бы вы объяснить немного больше?
Это копирование ссылки.
@LouisWasserman О, вы говорите, что делаете снимок (клон) «эталона», а не самого объекта? Хорошо, я понял. Поэтому, когда вы сказали «... если какой-то другой код в другом потоке« модифицирует »imageCapture
...», «модифицирует» означает назначение другого объекта, а не изменение самого исходного объекта. Правильно ли я понял? Таким образом, если сам исходный объект изменен (не переназначен) в другом потоке, это все равно вызовет хаос, если только мы не скопируем сам объект. Пожалуйста, дайте мне знать, если я неправильно понял. Спасибо за ваши комментарии!
@LouisWasserman Я думаю, что ADM прокомментировал то же самое, что я упомянул, в комментарии к ответу ниже: «Даже если переменная изменяется в середине, неглубокая копия также будет изменена. Вот почему они все одинаковы. Только после клонирования мы можем убедитесь, что локальная ссылка не влияет на фактическую».
Да, это правильно. Если вы правильно используете неизменяемые объекты, то эта копия ссылки — это все, что вам нужно.
Это эквивалентно нулевой проверке.
stable reference -> Not null reference
это похоже на
if (imageCapture==null) return;
Также в лаборатории кода они упомянули то же самое.
Во-первых, получите ссылку на вариант использования ImageCapture. Если вариант использования нулевой, выйдите из функции. Это будет пустым, если вы нажмете кнопку фото до настройки захвата изображения. Без оператора return приложение вылетит, если оно будет нулевым.
Таким образом, в основном вы исключаете возможность NPE, который может быть выполнен несколькими способами, и они используют для этого локальную переменную Another. это также можно сделать с помощью let
.
imageCapture?.let{
// code goes here
}
...что можно сделать несколькими способами, и они используют для этого локальную переменную Another..." Так что это всего лишь один из многих способов избежать NPE, верно? Большое спасибо! Теперь я понимаю.
Это не эквивалентно, if (imageCapture==null) return;
все равно не поможет, если переменная изменилась в середине, вы все равно получите странные вещи, и компилятор не допустит ненулевые .
вызовы объекта даже с этой проверкой в том же отношении. ?.let
сделает неглубокую копию, такую же, как фрагмент в вопросе, который будет защищен от изменений извне.
Несмотря на то, что переменная изменяется в середине, неглубокая копия также будет изменена. Вот поэтому они все одинаковые. Только после клонирования мы можем убедиться, что локальная ссылка не влияет на фактическую.
private var imageCapture: ImageCapture? = null
С помощью этой строки вы присваиваете значение null переменной imageCapture. Теперь, когда вы начнете использовать takePhoto(), как компилятор узнает, что imageCapture больше не является нулевым?
Как описывает @ADM, вы можете использовать
imageCapture?.let{
//your code goes here
}
если ты хочешь. В основном это гарантирует, что вы ничего не вызываете для объекта, допускающего значение NULL.
Как вы думаете, что произойдет, если какой-то другой код в другом потоке изменит
imageCapture
в серединеtakePhoto
?