Kotlin | Вопросы собесов
2.57K subscribers
28 photos
964 links
Download Telegram
🤔 Можно ли создать анонимный класс внутри inline функции?

Да, можно создать анонимный класс внутри inline функции.
1. Однако, если этот класс захватывает переменные, они не будут инлайновыми и могут повлиять на производительность.
2. Inline функции лучше использовать для лямбда-функций, не создающих дополнительных объектов.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3👍2
🤔 Расскажи про ключевое слово Object в Kotlin?

Ключевое слово object в Kotlin имеет несколько важных применений, и оно является одной из наиболее мощных и уникальных возможностей языка.

🟠Объявление объекта-одиночки (Singleton)
Kotlin предоставляет встроенную поддержку для создания singleton-объектов. Это объект, который имеет единственный экземпляр в приложении.
object Database {
val name = "MainDatabase"
fun connect() {
println("Подключение к базе данных $name")
}
}

fun main() {
Database.connect() // Подключение к базе данных MainDatabase
}


🟠Анонимные объекты
Ключевое слово object может использоваться для создания анонимных объектов (объектов без имени). Это полезно, если нужно создать временный объект или реализовать интерфейс/абстрактный класс.
fun main() {
val listener = object : ClickListener {
override fun onClick() {
println("Кнопка нажата")
}
}
listener.onClick()
}

interface ClickListener {
fun onClick()
}


🟠Компаньон-объекты (Companion Object)
Ключевое слово object можно использовать внутри класса для объявления компаньон-объекта. Это позволяет создавать статические методы и переменные в классе.
class User(val name: String) {
companion object {
fun createGuest() = User("Guest")
}
}

fun main() {
val guest = User.createGuest()
println(guest.name) // Guest
}


🟠Объект-выражение
Ключевое слово object может использоваться для объявления объектов в коде прямо "на месте".
val myObject = object {
val x = 10
fun printX() {
println(x)
}
}

fun main() {
myObject.printX() // 10
}


🚩Почему `object` так полезен?

🟠Лаконичность
Вместо написания множества шаблонного кода для Singleton, анонимных объектов или статических методов, вы получаете готовую реализацию из коробки.

🟠Потокобезопасность
В случае object, компилятор Kotlin автоматически гарантирует, что объект создаётся в потокобезопасном режиме.

🟠Гибкость
object можно использовать практически везде: глобально, локально, внутри классов и функций.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
🤔 Какие архитектурные паттерны используются в Android фреймворке?

1. MVC (Model-View-Controller): часто используется в старых приложениях.
2. MVP (Model-View-Presenter): разделяет бизнес-логику и представление.
3. MVVM (Model-View-ViewModel): основа Jetpack-компонентов, поддерживает двустороннюю привязку данных.
4. Clean Architecture: упрощает тестирование и масштабируемость через слои данных, домена и представления.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍21🤯1
🤔 В чем разница между linked list и array list?

Являются двумя различными типами коллекций, которые используются для хранения наборов данных. Основные различия между этими двумя структурами данных касаются их внутренней реализации, что влияет на производительность операций добавления, удаления и доступа к элементам.

🚩Внутренняя реализация

🟠ArrayList
основан на динамическом массиве. Это позволяет обеспечить быстрый доступ к элементам по индексу, поскольку адрес каждого элемента в памяти может быть вычислен напрямую. Однако, поскольку внутренний массив имеет фиксированный размер, при его переполнении необходимо выделить массив большего размера и скопировать в него все элементы из старого массива, что делает операции добавления и удаления более затратными по времени, особенно для больших объемов данных.

🟠LinkedList
основан на двусвязном списке элементов, где каждый элемент (узел) содержит данные и ссылки на предыдущий и следующий элементы в списке. Это обеспечивает высокую производительность операций вставки и удаления, поскольку требуется лишь изменить ссылки у соседних элементов, но доступ к элементам по индексу занимает больше времени, так как для этого нужно последовательно пройти от начала или конца списка до нужного элемента.

🚩Производительность:

🟠ArrayList
Быстрый доступ к элементам по индексу. Медленные операции добавления и удаления элементов (особенно в начале и середине списка), так как может потребоваться сдвиг оставшейся части массива.

🟠LinkedList
Быстрые операции вставки и удаления элементов, поскольку они требуют только изменения ссылок. Медленный доступ к элементам по индексу, так как для доступа к элементу необходимо пройти по списку.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥21
🤔 Какие есть ограничения у sealed классов?

1. Все подклассы должны находиться в том же файле или быть вложенными.
2. Нельзя создавать экземпляры базового sealed класса напрямую.
3. Поддерживает ограниченное количество наследников, обеспечивая контроль над иерархией.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥41👍1
🤔 Через какой класс вызываются методы get, replace?

Методы get и replace в Kotlin относятся к работе с коллекциями, карты (Map) или к строкам. В зависимости от контекста, они вызываются через разные классы. Давайте разберем каждый случай отдельно.

🟠Методы `get` и `replace` для коллекций (`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 и 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` через пользовательские классы
Если вы пишете свои классы, вы можете переопределить оператор 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
}


Пример с replace
class 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
👍51🔥1
🤔 Где можно оптимизировать парсинг?

1. Использовать потоковую обработку (например, XmlPullParser вместо DOM).
2. Уменьшить количество преобразований строк.
3. Кешировать результаты парсинга для повторного использования.
4. Использовать специализированные библиотеки, такие как Moshi или Gson.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
2🔥2👍1
🤔 Что нужно сделать в Android-проекте чтобы начать рисовать UI на экране?

Чтобы начать рисовать пользовательский интерфейс (UI) на экране в Android-проекте, необходимо выполнить несколько шагов, которые включают настройку проекта, создание макета и взаимодействие с основными компонентами Android.

1⃣Создание Android-проекта
Первый шаг — создание Android-проекта в Android Studio. Это можно сделать, выбрав шаблон «Empty Activity», который предоставляет минимальный набор для разработки приложения.
Укажите имя проекта.
Выберите язык программирования (Java или Kotlin).
Убедитесь, что минимальная версия SDK подходит для вашей целевой аудитории.

2⃣Настройка макета (XML-файл)
Android UI в основном создаётся с использованием XML-файлов, которые определяют структуру интерфейса.
По умолчанию файл макета находится в каталоге:
res/layout/activity_main.xml


#### Пример простого макета:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">

<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Привет, мир!"
android:textSize="24sp"
android:padding="16dp"/>

<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Нажми меня"/>
</LinearLayout>


🟠Подключение макета к активности
Макет нужно связать с логикой приложения в Java или Kotlin. Это делается с помощью метода setContentView() в Activity.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

// Указываем, какой XML-файл использовать для интерфейса
setContentView(R.layout.activity_main)

// Найдём элементы интерфейса и добавим логику
val textView = findViewById<TextView>(R.id.textView)
val button = findViewById<Button>(R.id.button)

button.setOnClickListener {
textView.text = "Кнопка нажата!"
}
}
}


🟠Добавление кастомного рисования (по необходимости)
Если нужно нарисовать что-то вручную (например, графику, линии, или кастомные фигуры), можно создать свой собственный класс, унаследованный от View, и переопределить метод onDraw().
class CustomView(context: Context) : View(context) {
private val paint = Paint().apply {
color = Color.RED
strokeWidth = 10f
}

override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)

// Рисуем линию
canvas?.drawLine(100f, 100f, 400f, 400f, paint)
}
}


Чтобы использовать этот класс, можно добавить его в макет или программно
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

// Устанавливаем кастомный View вместо макета
setContentView(CustomView(this))
}
}


🟠Запуск приложения
Теперь можно запустить приложение на эмуляторе или реальном устройстве:
Нажмите Run в Android Studio.
Убедитесь, что устройство подключено или выбран эмулятор.
После запуска вы увидите созданный интерфейс.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3👍2🤯2
🤔 Как разбить текст, зная, сколько символов помещается на экране?

Используйте класс Paint и метод breakText, чтобы определить, сколько символов помещается в строку. Это позволит разбивать текст в зависимости от ширины экрана и используемого шрифта.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11👀4👍1
🤔 Расскажи все типы данных в Java/Kotlin?

В Java и Kotlin существуют различные типы данных, которые можно разделить на две основные категории:
Примитивные типы данных (primitive types)
Ссылочные типы данных (reference types)

🚩Типы данных в Java

🟠Ссылочные типы данных (Reference Types)
Ссылочные типы данных указывают на объекты. Они хранятся в куче (heap) и содержат ссылку (адрес) на объект.
Примеры ссылочных типов

🟠Строки (`String`)
String str = "Hello";

🟠Классы и объекты
MyClass obj = new MyClass();

🟠Массивы
int[] arr = {1, 2, 3};

🟠Интерфейсы
List<Integer> list = new ArrayList<>();

🚩Типы данных в Kotlin

В Kotlin типы данных делятся на nullable и non-nullable (значения, которые могут быть null, и те, которые не могут). Kotlin избегает примитивных типов напрямую, но на уровне JVM использует их для оптимизации.

🟠Примитивные типы данных (на уровне JVM)
Kotlin предоставляет высокоуровневые обёртки для примитивных типов. Например:
Int вместо int
Double вместо double

🟠Ссылочные типы данных (Reference Types)
В Kotlin все данные — объекты.
Сюда входят:
Строки (String): val str: String = "Hello"
Коллекции: val list: List<Int> = listOf(1, 2, 3)
Классы: val obj = MyClass()
Nullable-типизация: В Kotlin можно указать, что переменная может быть null. Для этого используется ?.
  val nullableString: String? = null
val nonNullableString: String = "Hello"


Интерфейсы и абстракции: Kotlin поддерживает классы, интерфейсы и их реализации, например
  interface Animal {
fun makeSound()
}

class Dog : Animal {
override fun makeSound() {
println("Woof!")
}
}


🟠Тип Unit и Nothing
Kotlin добавляет уникальные типы, которые отсутствуют в Java:
Unit
Эквивалент void в Java, но является объектом.
Используется, когда функция ничего не возвращает:
  fun printMessage(message: String): Unit {
println(message)
}


Nothing
Представляет значение, которое никогда не будет существовать (например, функция всегда бросает исключение):
  fun fail(message: String): Nothing {
throw IllegalArgumentException(message)
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍82🔥2
🤔 Как сохранить структуру Markdown в базу данных/на диск?

Сохраняйте текст Markdown в исходном виде как строку в базе данных или файле. Для сохранения структуры можно использовать JSON или специализированные библиотеки, такие как FlexMark.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍21
🤔 Может ли потеря state быть связанной с фрагментом?

Да, потеря состояния (state) может быть связана с фрагментами (Fragments) в Android. Это довольно распространённая проблема, особенно при работе с динамическими интерфейсами. Давайте разберёмся, почему она возникает, как её предотвратить и какие решения существуют.

🚩Почему происходит потеря состояния во фрагментах?

🟠Жизненный цикл фрагмента
Фрагменты имеют сложный жизненный цикл, который тесно связан с активностью. Основные этапы:
onCreate() — создаётся фрагмент, инициализируются объекты.
onViewCreated() — создаётся View (UI компоненты).
onStart() / onResume() — фрагмент становится видимым и активным.
onPause() / onStop() — фрагмент приостанавливается.
onDestroyView() — уничтожается только View (UI), но сам фрагмент всё ещё существует.
onDestroy() — полностью уничтожается фрагмент.
Фрагменты могут пересоздаваться системой, например, при смене ориентации экрана или нехватке памяти. Если разработчик неправильно сохраняет состояние фрагмента, оно может быть утеряно.

🟠Удаление View фрагмента системой
Когда фрагмент переходит в состояние onDestroyView(), его View уничтожается, но сам объект фрагмента сохраняется. Если пользователь вернётся к этому фрагменту, View будет пересоздана, и вы потеряете все изменения, сделанные ранее, если они не сохранены явно.

🟠Проблемы с менеджером фрагментов
Использование FragmentManager или FragmentTransaction с неправильными методами, такими как replace() или add(), без должного управления стэком (back stack), может привести к пересозданию или дублированию фрагментов, что вызывает потерю состояния.

🟠Проблемы с `savedInstanceState`
Фрагменты, как и активности, используют механизм сохранения состояния через BundleonSaveInstanceState). Если состояние не сохранено правильно, данные могут быть потеряны.

🚩Как предотвратить потерю состояния во фрагментах?

🟠Сохранение данных в `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`
Для хранения состояния, которое переживает уничтожение и пересоздание фрагмента, лучше использовать архитектурный компонент ViewModel.
1⃣Создайте ViewModel
class MyViewModel : ViewModel() {
val textData = MutableLiveData<String>()
}


2⃣Используйте его во фрагменте
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()
}
}
}


🟠Использование `FragmentManager` правильно
При работе с фрагментами всегда добавляйте их в 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
👍5
🤔 Как можно указать ссылку на картинку из галереи?

Используйте Uri, полученный через Intent с ACTION_GET_CONTENT или ACTION_PICK. Пример: пользователь выбирает изображение, и возвращается Uri, который безопасно обрабатывается через ContentResolver.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍2
🤔 Какой класс можно использовать что бы ловить разные жесты?

Чтобы обрабатывать жесты в Android, используйте класс GestureDetector. Он помогает отслеживать стандартные жесты: одиночные нажатия, свайпы, долгие нажатия, двойные касания и т.д.

🚩Как использовать GestureDetector?

Создайте экземпляр GestureDetector, передав Context и слушателя (GestureDetector.OnGestureListener).
Передавайте события касания в gestureDetector.onTouchEvent(event) из метода onTouchEvent().
class GestureActivity : AppCompatActivity(), GestureDetector.OnGestureListener {
private lateinit var gestureDetector: GestureDetector

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
gestureDetector = GestureDetector(this, this)
}

override fun onTouchEvent(event: MotionEvent): Boolean {
return gestureDetector.onTouchEvent(event) || super.onTouchEvent(event)
}

override fun onFling(e1: MotionEvent?, e2: MotionEvent?, velocityX: Float, velocityY: Float): Boolean {
val deltaX = e2!!.x - e1!!.x
if (deltaX > 0) Log.d("Gesture", "Swipe Right") else Log.d("Gesture", "Swipe Left")
return true
}

override fun onDown(e: MotionEvent?) = true
override fun onShowPress(e: MotionEvent?) {}
override fun onSingleTapUp(e: MotionEvent?) = false
override fun onScroll(e1: MotionEvent?, e2: MotionEvent?, distanceX: Float, distanceY: Float) = false
override fun onLongPress(e: MotionEvent?) {}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
🤔 Почему нельзя использовать ссылку на файл, как в Unix-системах, а нужно делать Uri через контент-провайдер?

Использует контент-провайдеры для обеспечения безопасности и контроля доступа к файлам. Прямые ссылки на файлы небезопасны, так как разные приложения имеют изолированные файловые системы.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👍2
🤔 Как выглядит алгоритм запроса данных из двух таблиц и какая у него сложность?

Запрос данных из двух таблиц обычно выполняется с помощью операции объединения (JOIN) в SQL. Алгоритм и его сложность зависят от типа объединения, структуры данных и используемой базы данных.

🚩Пример запроса

Предположим, у нас есть две таблицы: employees и departments. Мы хотим получить список сотрудников вместе с их отделами.
SELECT employees.name, departments.name
FROM employees
INNER JOIN departments ON employees.department_id = departments.id;


🚩Алгоритмы выполнения JOIN

1⃣Nested Loop Join (Вложенные циклы)
Для каждой строки из первой таблицы выполняется поиск соответствующих строк во второй таблице.
for each row in employees:
for each row in departments:
if row.employees.department_id == row.departments.id:
yield (row.employees.name, row.departments.name)


2⃣Hash Join (Хеш-объединение)
Создается хеш-таблица для одной из таблиц на основе ключа соединения. Для каждой строки из другой таблицы проверяется наличие соответствующего ключа в хеш-таблице.
hash_table = {}
for each row in departments:
hash_table[row.id] = row.name
for each row in employees:
if row.department_id in hash_table:
yield (row.name, hash_table[row.department_id])


3⃣Sort-Merge Join (Сортировка и слияние)
Обе таблицы сортируются по ключу соединения, затем выполняется слияние отсортированных списков.
sorted_employees = sort(employees, key=lambda x: x.department_id)
sorted_departments = sort(departments, key=lambda x: x.id)
i, j = 0, 0
while i < len(sorted_employees) and j < len(sorted_departments):
if sorted_employees[i].department_id == sorted_departments[j].id:
yield (sorted_employees[i].name, sorted_departments[j].name)
i += 1
j += 1
elif sorted_employees[i].department_id < sorted_departments[j].id:
i += 1
else:
j += 1


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍21
🤔 Когда стоит делать свой контент-провайдер?

1. Для совместного использования данных между приложениями.
2. Когда нужно предоставить безопасный доступ к данным.
3. Для унифицированного интерфейса работы с базами данных, файлами или сетевыми данными.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1
🤔 View Model vs OnSavedInstanceState?

ViewModel и onSaveInstanceState служат для сохранения данных при изменении конфигурации активности или фрагмента (например, при повороте экрана). Однако они решают эту задачу по-разному и имеют разные области применения.

🟠ViewModel
ViewModel используется для хранения и управления данными, связанных с UI, таким образом, чтобы они сохранялись при изменении конфигурации (например, при повороте экрана).

🚩Как это работает?

Когда система уничтожает и пересоздаёт Activity или Fragment, ViewModel остаётся в памяти до полного уничтожения владельца (например, выхода из Activity).
class MyViewModel : ViewModel() {
var counter: Int = 0 // Переменная, которая сохраняется при повороте экрана
}


Использование в Activity
class MainActivity : AppCompatActivity() {
private lateinit var viewModel: MyViewModel

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

viewModel = ViewModelProvider(this).get(MyViewModel::class.java)

// Теперь viewModel.counter сохранится при повороте экрана
}
}



🚩Плюсы

Хранит данные в памяти
до полного уничтожения Activity или Fragment.
Удобно для хранения сложных объектов
списки, модели, API-данные
Позволяет разделять логику и UI
улучшая архитектуру.

🚩Минусы

Данные исчезают при уничтожении Activity
например, при закрытии приложения
Не сохраняет данные при завершении процесса например, при нехватке памяти

🚩onSaveInstanceState()

Метод onSaveInstanceState() используется для сохранения данных в Bundle, который система автоматически передаёт при пересоздании Activity или Fragment.

🚩Как это работает?

Когда Activity уничтожается (например, при повороте экрана), система вызывает onSaveInstanceState(), в котором можно сохранить небольшие данные (строки, числа и т. д.). После пересоздания Activity эти данные можно восстановить из savedInstanceState.
class MainActivity : AppCompatActivity() {
private var counter: Int = 0 // Значение, которое мы хотим сохранить

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

// Восстанавливаем данные, если они есть
counter = savedInstanceState?.getInt("counter_key") ?: 0
}

override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putInt("counter_key", counter) // Сохраняем значение перед уничтожением Activity
}
}


🚩Плюсы

Сохраняет данные даже при завершении процесса (например, при нехватке памяти).
Позволяет быстро восстановить состояние UI (например, текст в EditText).

🚩Минусы

Подходит только для небольших данных (числа, строки).
Не подходит для хранения сложных объектов (списки, большие модели, API-данные).
Требует кодирования и декодирования данных в Bundle

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
🤔 Как оптимизировать Markdown для быстрой отрисовки?

1. Предварительно парсить Markdown в HTML или промежуточную структуру.
2. Кешировать результаты парсинга.
3. Разделять обработку сложных блоков (например, таблиц) от простых (текста).
4. Использовать библиотеки, оптимизированные для Android, такие как Markwon.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
🤔 Если профайлер показывает тебе что какой-нибудь фрейм занял 120 миллисекунд, что это значит?

Если профайлер показывает, что рендеринг какого-либо фрейма занял 120 миллисекунд, это означает, что этот фрейм выполнялся слишком долго, что приводит к фризам и лагам в пользовательском интерфейсе.

🚩Разбор проблемы

🟠Что значит "фрейм" в этом контексте?
В Android интерфейс обновляется 60 раз в секунду (частота 60 FPS). Это значит, что каждый кадр (фрейм) должен рендериться не дольше 16,67 мс (1000 мс / 60 FPS).

🟠Почему 120 мс — это плохо?
Если рендеринг кадра занимает 120 мс, то за это время устройство должно было бы нарисовать 7 кадров (120 / 16,67 ≈ 7). Однако оно успело обработать только один, что приводит к заметному подтормаживанию.

🟠Что может вызывать такие задержки?
Тяжёлые вычисления в основном потоке (UI Thread) – например, сложные математические операции, работа с JSON, парсинг файлов.
Долгие операции с рендерингом – сложные векторные изображения, перегруженные Canvas.draw() или анимации.
Синхронные вызовы I/O (чтение файлов, базы данных, сети) – если, например, в onDraw() идёт обращение к диску или базе данных.
Неоптимальный layout – глубокая иерархия ViewGroup, частые перерасчёты макетов (measure/layout).

🚩Как исправить?

🟠Перенести тяжёлые вычисления в фоновый поток
Coroutines, Executors, WorkManager
🟠Использовать профайлер Android Studio
для поиска "узких мест".
🟠Оптимизировать рендеринг
избегать сложных onDraw(), использовать ViewStub, RecyclerView.
🟠Пересмотреть макет
убрать ненужные ViewGroup, использовать ConstraintLayout.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5