Через open и :. Родительский класс должен быть open, а дочерний объявляется с class B : A().
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Являются двумя различными типами коллекций, которые используются для хранения наборов данных. Основные различия между этими двумя структурами данных касаются их внутренней реализации, что влияет на производительность операций добавления, удаления и доступа к элементам.
основан на динамическом массиве. Это позволяет обеспечить быстрый доступ к элементам по индексу, поскольку адрес каждого элемента в памяти может быть вычислен напрямую. Однако, поскольку внутренний массив имеет фиксированный размер, при его переполнении необходимо выделить массив большего размера и скопировать в него все элементы из старого массива, что делает операции добавления и удаления более затратными по времени, особенно для больших объемов данных.
основан на двусвязном списке элементов, где каждый элемент (узел) содержит данные и ссылки на предыдущий и следующий элементы в списке. Это обеспечивает высокую производительность операций вставки и удаления, поскольку требуется лишь изменить ссылки у соседних элементов, но доступ к элементам по индексу занимает больше времени, так как для этого нужно последовательно пройти от начала или конца списка до нужного элемента.
Быстрый доступ к элементам по индексу. Медленные операции добавления и удаления элементов (особенно в начале и середине списка), так как может потребоваться сдвиг оставшейся части массива.
Быстрые операции вставки и удаления элементов, поскольку они требуют только изменения ссылок. Медленный доступ к элементам по индексу, так как для доступа к элементу необходимо пройти по списку.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
- Использовать overridePendingTransition() для задания анимации входа и выхода.
2. Fragment переходы:
- Установить FragmentTransaction.setCustomAnimations() или использовать shared element transitions.
3. Navigation Component:
- Указать анимации в nav_graph.xml или через NavOptions.
4. Compose Navigation:
- Использовать AnimatedVisibility, AnimatedContent или другие transition-компоненты.
Анимации переходов делают интерфейс плавным и улучшают UX.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Да, потеря состояния (state) может быть связана с фрагментами (Fragments) в Android. Это довольно распространённая проблема, особенно при работе с динамическими интерфейсами. Давайте разберёмся, почему она возникает, как её предотвратить и какие решения существуют.
Фрагменты имеют сложный жизненный цикл, который тесно связан с активностью. Основные этапы:
onCreate() — создаётся фрагмент, инициализируются объекты.onViewCreated() — создаётся View (UI компоненты).onStart() / onResume() — фрагмент становится видимым и активным.onPause() / onStop() — фрагмент приостанавливается.onDestroyView() — уничтожается только View (UI), но сам фрагмент всё ещё существует.onDestroy() — полностью уничтожается фрагмент.Фрагменты могут пересоздаваться системой, например, при смене ориентации экрана или нехватке памяти. Если разработчик неправильно сохраняет состояние фрагмента, оно может быть утеряно.
Когда фрагмент переходит в состояние
onDestroyView(), его View уничтожается, но сам объект фрагмента сохраняется. Если пользователь вернётся к этому фрагменту, View будет пересоздана, и вы потеряете все изменения, сделанные ранее, если они не сохранены явно.Использование
FragmentManager или FragmentTransaction с неправильными методами, такими как replace() или add(), без должного управления стэком (back stack), может привести к пересозданию или дублированию фрагментов, что вызывает потерю состояния.Фрагменты, как и активности, используют механизм сохранения состояния через
Bundle (в onSaveInstanceState). Если состояние не сохранено правильно, данные могут быть потеряны.При уничтожении фрагмента система вызывает метод
onSaveInstanceState(). Здесь вы можете сохранить важные данные в Bundle.override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putString("key_text", editText.text.toString())
}При пересоздании фрагмента данные можно восстановить в
onViewCreated()override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val restoredText = savedInstanceState?.getString("key_text")
editText.setText(restoredText)
}Для хранения состояния, которое переживает уничтожение и пересоздание фрагмента, лучше использовать архитектурный компонент
ViewModel.ViewModelclass MyViewModel : ViewModel() {
val textData = MutableLiveData<String>()
}class MyFragment : Fragment() {
private lateinit var viewModel: MyViewModel
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel = ViewModelProvider(this).get(MyViewModel::class.java)
// Восстановление данных
viewModel.textData.observe(viewLifecycleOwner) { text ->
editText.setText(text)
}
// Сохранение данных при изменении
editText.addTextChangedListener {
viewModel.textData.value = it.toString()
}
}
}При работе с фрагментами всегда добавляйте их в back stack, если вы хотите сохранить состояние.
val fragment = MyFragment()
parentFragmentManager.beginTransaction()
.replace(R.id.fragment_container, fragment)
.addToBackStack(null)
.commit()
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Android оценивает приоритет процесса:
1. Foreground (не трогается),
2. Visible,
3. Service,
4. Cached (в фоне),
5. Empty (не содержит компонентов).
Убиваются сначала самые низкоприоритетные, при нехватке памяти.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Методы
get и replace в Kotlin относятся к работе с коллекциями, карты (Map) или к строкам. В зависимости от контекста, они вызываются через разные классы. Давайте разберем каждый случай отдельно.В контексте работы с картами (
Map), методы get и replace относятся к получению значений по ключу и замене существующих значений.Метод
getМетод
get используется для извлечения значения из карты по указанному ключу.val map = mapOf("key1" to "value1", "key2" to "value2")
println(map.get("key1")) // value1
println(map["key2"]) // value2 (альтернатива `get`)Метод
replace используется для обновления значения, связанного с определённым ключом, если он существует. Этот метод доступен только для изменяемых карт (MutableMap).val mutableMap = mutableMapOf("key1" to "value1", "key2" to "value2")
mutableMap.replace("key1", "newValue1")
println(mutableMap) // {key1=newValue1, key2=value2}В контексте строк, методы
get и replace работают с символами и подстроками.Метод
get используется для доступа к символу строки по индексу. Это альтернатива квадратным скобкам.val text = "Kotlin"
println(text.get(0)) // K
println(text[1]) // o (альтернатива `get`)
Метод
replace заменяет символы или подстроки в строке на заданные.val text = "Kotlin is awesome"
val newText = text.replace("awesome", "powerful")
println(newText) // Kotlin is powerful
Если вы пишете свои классы, вы можете переопределить оператор
get и метод replace, чтобы использовать их для своих нужд.class CustomList<T>(private val items: List<T>) {
operator fun get(index: Int): T {
return items[index]
}
}
fun main() {
val customList = CustomList(listOf(1, 2, 3))
println(customList[0]) // 1
}Пример с
replaceclass CustomMap<K, V>(private val map: MutableMap<K, V>) {
fun replace(key: K, value: V) {
if (map.containsKey(key)) {
map[key] = value
}
}
}
fun main() {
val customMap = CustomMap(mutableMapOf("key1" to "value1"))
customMap.replace("key1", "newValue1")
println(customMap) // {key1=newValue1}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
ArrayList реализован на основе массива. Амортизированное O(1). Если массив не заполнен, элемент добавляется в конец списка. В случае, если массив заполнен, требуется выделение нового массива и копирование элементов, что занимает O(n) времени.
val arrayList = ArrayList<Int>()
arrayList.add(1) // Быстрая вставка в конец
O(n). Необходимо сдвинуть все элементы, начиная с позиции вставки, чтобы освободить место для нового элемента. Это требует времени, пропорционального количеству элементов после позиции вставки.
arrayList.add(0, 2) // Медленная вставка в начало
arrayList.add(1, 3) // Медленная вставка в середину
LinkedList реализован на основе узлов, где каждый узел содержит ссылку на следующий и/или предыдущий узел (в случае двусвязного списка).val linkedList = LinkedList<Int>()
linkedList.addFirst(1) // Быстрая вставка в начало
O(1) (если есть ссылка на последний узел) или O(n) (если необходимо пройти весь список). Если список двусвязный и хранится ссылка на последний элемент, вставка в конец осуществляется за O(1). В противном случае, требуется пройти весь список до конца.
linkedList.addLast(2) // Быстрая вставка в конец, если есть ссылка на последний узел
O(n). Необходимо пройти список до нужной позиции и изменить ссылки узлов.
linkedList.add(1, 3) // Медленная вставка в середину
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Файл classes.dex содержит весь скомпилированный Kotlin/Java код.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2👍1
Модификаторы доступа (Access Modifiers) — это ключевые слова, которые определяют, кто может видеть и использовать класс, переменную или метод.
Они помогают инкапсулировать данные и защищать код от неправильного использования.
Пример Java
public class Example {
private int a = 10; // ❌ Только внутри класса
int b = 20; // ✅ Видно внутри пакета (package-private)
protected int c = 30; // ✅ Видно в пакете и наследниках
public int d = 40; // ✅ Доступно везде
}В Kotlin есть почти такие же модификаторы, но
package-private заменён на internal.Пример Kotlin
class Example {
private val a = 10 // ❌ Только в этом классе
internal val b = 20 // ✅ Видно в модуле
protected val c = 30 // ✅ Видно в наследниках
public val d = 40 // ✅ Видно везде (по умолчанию)
}Для полей (переменных класса)
public class User {
private String name; // ❌ Скрыто от других классов
public User(String name) {
this.name = name;
}
public String getName() { // ✅ Доступ через метод
return name;
}
}Для методов
class Animal {
protected void makeSound() { // ✅ Доступен только в наследниках
System.out.println("Животное издаёт звук");
}
}
class Dog extends Animal {
public void bark() {
makeSound(); // ✅ Разрешено, потому что `protected`
System.out.println("Гав-гав!");
}
}Для классов
public class Car { } // ✅ Доступен везде
class Engine { } // ❌ Только в этом пакетеВ Kotlin можно делать
private class, но только внутри другого класса. class Car {
private class Engine // ❌ Только в этом классе
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Executor — это абстракция для управления потоками. Он позволяет отправлять задачи на выполнение, не заботясь напрямую о создании и управлении потоками.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Если профайлер показывает, что рендеринг какого-либо фрейма занял 120 миллисекунд, это означает, что этот фрейм выполнялся слишком долго, что приводит к фризам и лагам в пользовательском интерфейсе.
В Android интерфейс обновляется 60 раз в секунду (частота 60 FPS). Это значит, что каждый кадр (фрейм) должен рендериться не дольше 16,67 мс (1000 мс / 60 FPS).
Если рендеринг кадра занимает 120 мс, то за это время устройство должно было бы нарисовать 7 кадров (120 / 16,67 ≈ 7). Однако оно успело обработать только один, что приводит к заметному подтормаживанию.
Тяжёлые вычисления в основном потоке (UI Thread) – например, сложные математические операции, работа с JSON, парсинг файлов.
Долгие операции с рендерингом – сложные векторные изображения, перегруженные
Canvas.draw() или анимации. Синхронные вызовы I/O (чтение файлов, базы данных, сети) – если, например, в
onDraw() идёт обращение к диску или базе данных. Неоптимальный layout – глубокая иерархия
ViewGroup, частые перерасчёты макетов (measure/layout). Coroutines, Executors, WorkManagerдля поиска "узких мест".
избегать сложных
onDraw(), использовать ViewStub, RecyclerView. убрать ненужные
ViewGroup, использовать ConstraintLayout.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
- HashSet — не гарантирует порядок элементов, основан на хеш-таблице.
- LinkedHashSet — сохраняет порядок добавления элементов.
- TreeSet — отсортированное множество (по натуральному порядку или Comparator), основано на красно-чёрном дереве.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
В Kotlin можно добавлять свойства-расширения (
extension properties), но только с кастомным get (геттером). Расширяемые свойства могут быть только вычисляемыми (
val), потому что нельзя создать field внутри расширения. val String.firstChar: Char
get() = this[0]
fun main() {
println("Kotlin".firstChar) // K
}
Для
var нужно и get(), и set(), но всё равно нельзя использовать field. var StringBuilder.lastChar: Char
get() = this[length - 1]
set(value) {
this.setCharAt(length - 1, value)
}
fun main() {
val sb = StringBuilder("Hello")
println(sb.lastChar) // o
sb.lastChar = '!'
println(sb) // Hell!
}
Такой код НЕ скомпилируется!
var String.someProperty: String = "Default" // Ошибка!
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
– Data push — содержит полезную нагрузку (данные), которые обрабатываются приложением (например, текст сообщения, обновления).
– Identification push — содержит только метаинформацию, которая говорит приложению, что нужно самостоятельно запросить данные с сервера.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
В Kotlin все классы неявно наследуются от
Any (аналог Object в Java). Это значит, что любой класс в Kotlin имеет 3 базовых метода:
По умолчанию сравнивает ссылки (как
===) class Person(val name: String)
fun main() {
val p1 = Person("Alice")
val p2 = Person("Alice")
println(p1 == p2) // false (разные объекты)
}
Как переопределить
equals() для сравнения по значениям? class Person(val name: String) {
override fun equals(other: Any?): Boolean {
return other is Person && this.name == other.name
}
}
fun main() {
val p1 = Person("Alice")
val p2 = Person("Alice")
println(p1 == p2) // true (теперь сравниваются значения)
}По умолчанию генерируется на основе ссылки
val p = Person("Alice")
println(p.hashCode()) // Разный для каждого объектаКак переопределить
hashCode()? class Person(val name: String) {
override fun hashCode(): Int {
return name.hashCode() // Генерируем хеш-код на основе имени
}
}По умолчанию печатает
ClassName@hashCodeval p = Person("Alice")
println(p.toString()) // Person@4e25154f (неудобный вывод)Как сделать красивый вывод?
class Person(val name: String) {
override fun toString(): String {
return "Person(name=$name)"
}
}
val p = Person("Alice")
println(p.toString()) // Person(name=Alice)data class User(val name: String)
fun main() {
val u1 = User("Alice")
val u2 = User("Alice")
println(u1 == u2) // ✅ true (по значениям)
println(u1.hashCode()) // ✅ Одинаковый для объектов с одинаковыми данными
println(u1.toString()) // ✅ User(name=Alice)
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🤔1
- px (pixels) — абсолютные пиксели экрана.
- dp (density-independent pixels) — масштабируемые пиксели, зависят от плотности экрана.
- sp (scale-independent pixels) — как dp, но учитывают пользовательские настройки размера шрифта.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
В Java класс
Object является корневым классом для всех остальных классов. Это значит, что все классы в Java неявно наследуются от Object, если явно не указано другое. Определяет, равны ли два объекта. По умолчанию использует сравнение по ссылке (
==), но может быть переопределён для логического сравнения. class Person {
String name;
Person(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return name.equals(person.name);
}
}
public class Main {
public static void main(String[] args) {
Person p1 = new Person("Alice");
Person p2 = new Person("Alice");
System.out.println(p1.equals(p2)); // true
}
}
Возвращает числовой хеш-код объекта, используемый, например, в
HashMap. Если переопределяем equals(), нужно переопределить и hashCode(). @Override
public int hashCode() {
return Objects.hash(name);
}
Возвращает строковое представление объекта. По умолчанию – имя класса + хеш-код, но лучше переопределять.
@Override
public String toString() {
return "Person{name='" + name + "'}";
}
Возвращает объект
Class, описывающий класс объекта. System.out.println(p1.getClass().getName()); // Person
Создаёт копию объекта (поверхностное клонирование). Объект должен реализовать
Cloneable, иначе будет CloneNotSupportedException. class Person implements Cloneable {
String name;
Person(String name) {
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
Вызывается перед удалением объекта сборщиком мусора. Лучше использовать
try-with-resources и close(). @Override
protected void finalize() throws Throwable {
System.out.println("Object is being garbage collected");
}
Методы для работы с многопоточностью.
wait() – приостанавливает поток до вызова notify(). notify() – пробуждает один поток. notifyAll() – пробуждает все потоки. class SharedResource {
synchronized void doWait() throws InterruptedException {
wait();
}
synchronized void doNotify() {
notify();
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Во фрагменте можно получить доступ к активности через requireActivity() или activity, и вызвать у неё метод, предварительно приведя к нужному типу (например, activity as MyActivity). Лучше всего — через интерфейс, реализуемый активностью, для слабой связанности.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
По умолчанию нельзя, потому что дженерики стираются (
Type Erasure) во время компиляции. fun <T> printType(value: T) {
println(T::class.simpleName) // ❌ Ошибка! Нельзя использовать `T::class`
}Если используем
inline fun, можно сделать дженерик "реальным" (reified). inline fun <reified T> printType(value: T) {
println(T::class.simpleName) // ✅ Работает!
}
fun main() {
printType(123) // Int
printType("Hello") // String
printType(3.14) // Double
}Если дженерик используется в классе, то
reified не поможет. class MyGenericClass<T>(private val type: KClass<T>) {
fun printType() {
println(type.simpleName) // ✅ Работает
}
}
fun main() {
val obj = MyGenericClass(String::class)
obj.printType() // String
}Для сложных дженериков (
List<T>, Map<K, V>) используем typeOf<T>() (только с reified). import kotlin.reflect.typeOf
inline fun <reified T> printGenericType() {
val type = typeOf<T>()
println(type) // ✅ List<Int>, Map<String, Boolean> и т. д.
}
fun main() {
printGenericType<List<Int>>() // kotlin.collections.List<kotlin.Int>
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1