Kotlin | Вопросы собесов
2.56K subscribers
30 photos
972 links
Download Telegram
🤔 Что делает функция коллекций partition()?

Эта функция делит коллекцию на два списка: один содержит элементы, соответствующие условию, другой — не соответствующие. Это удобно для фильтрации без потери невалидных элементов.


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

Лямбда-выражения представляют собой компактный способ представления анонимных функций, который особенно полезен для создания коротких блоков выполнения кода, предназначенных для последующей передачи другим функциям. Лямбды широко используются для упрощения работы с коллекциями, потоками данных, асинхронным кодом и в ситуациях, где требуется функциональный интерфейс.

🚩Лямбда-выражения

Были введены в Java 8 и являются частью усилий по добавлению функциональных возможностей в язык. Лямбды в Java чаще всего используются с функциональными интерфейсами, которые являются интерфейсами с одним абстрактным методом.
(parameters) -> expression


или
(parameters) -> { statements; }


🚩Лямбда-выражения

Поддерживает более гибкие и выразительные лямбды по сравнению с Java. Лямбды могут использоваться как с функциональными интерфейсами, так и в качестве части синтаксиса языка, благодаря чему Kotlin особенно удобен для функционального программирования.
{ parameters -> code body }


🚩Примеры

Лямбда без параметров
{ println("Hello, World!") }  


Лямбда с одним параметром
{ a: Int -> a * a }   


Лямбда с несколькими параметрами
{ a: Int, b: Int -> a + b }   


Лямбда с телом, содержащим несколько выражений
      { s: String ->
println(s)
s.length
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Как работают SAM (Single Abstract Method)?

1. SAM-конверсии позволяют использовать лямбда-функции вместо объектов классов с одним абстрактным методом.
2. Это делает код более кратким и читабельным при работе с Java API или интерфейсами в Kotlin.
3. Пример: интерфейс с одним методом автоматически превращается в функциональный тип.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
🤔 Что делает библиотека LifeCycle ?

Библиотека Lifecycle в Android Jetpack помогает управлять и контролировать жизненный цикл компонентов Android, таких как Activities и Fragments. Она упрощает создание компонентов, которые осведомлены о своем жизненном цикле и могут корректно реагировать на изменения в нем. Это позволяет избегать утечек памяти и некорректной работы компонентов при изменении конфигураций или переходах между состояниями.

🚩Основные компоненты библиотеки Lifecycle

🟠LifecycleOwner
Это интерфейс, который определяет класс как владеющий жизненным циклом. Activity и Fragment уже реализуют этот интерфейс.
class MyActivity : AppCompatActivity(), LifecycleOwner {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}


🟠LifecycleObserver
Это интерфейс, который позволяет классу наблюдать за изменениями в жизненном цикле компонента. Методы, аннотированные @OnLifecycleEvent, будут вызываться при соответствующих событиях жизненного цикла.
class MyObserver : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onStart() {
// Код, который выполняется при старте жизненного цикла
Log.d("MyObserver", "onStart called")
}

@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onStop() {
// Код, который выполняется при остановке жизненного цикла
Log.d("MyObserver", "onStop called")
}
}


🟠Lifecycle
Это класс, который содержит информацию о текущем состоянии и позволяет другим объектам наблюдать за изменениями в жизненном цикле.
class MyActivity : AppCompatActivity() {
private lateinit var myObserver: MyObserver

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

myObserver = MyObserver()
lifecycle.addObserver(myObserver)
}
}


🚩Применение библиотеки Lifecycle

1⃣ Добавьте зависимости в ваш build.gradle
dependencies {
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
}


2⃣Создайте класс, реализующий LifecycleObserver
class MyObserver : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun onResume() {
Log.d("MyObserver", "Activity resumed")
}

@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun onPause() {
Log.d("MyObserver", "Activity paused")
}
}


3⃣Добавьте LifecycleObserver в LifecycleOwner (например, Activity)
class MyActivity : AppCompatActivity() {
private lateinit var myObserver: MyObserver

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

myObserver = MyObserver()
lifecycle.addObserver(myObserver)
}
}


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

1. Сохранить текущую позицию скролла в onSaveInstanceState.
2. При восстановлении (в onRestoreInstanceState) установить сохранённую позицию через RecyclerView.scrollToPosition или ScrollView.scrollTo.


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

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

🟠Сохранение Markdown в виде строки (Plain Text)
Самый простой способ — хранить Markdown как обычный текст в базе данных или файле.
База данных (SQLite, Room):
@Entity
data class Note(
@PrimaryKey(autoGenerate = true) val id: Long = 0,
val title: String,
val content: String // Здесь хранится Markdown-текст
)


@Dao
interface NoteDao {
@Insert
suspend fun insert(note: Note)

@Query("SELECT * FROM Note WHERE id = :id")
suspend fun getNote(id: Long): Note?
}


Файл на диске
fun saveMarkdownToFile(context: Context, filename: String, content: String) {
val file = File(context.filesDir, filename)
file.writeText(content, Charsets.UTF_8)
}

fun readMarkdownFromFile(context: Context, filename: String): String {
val file = File(context.filesDir, filename)
return if (file.exists()) file.readText(Charsets.UTF_8) else ""
}


🟠Хранение Markdown в виде JSON (Парсинг в структуру)
Если нужно анализировать структуру Markdown (например, извлекать заголовки, ссылки, списки), можно парсить Markdown в JSON и сохранять в базу данных.
{
"title": "Android Markdown Guide",
"content": [
{
"type": "header",
"level": 1,
"text": "Введение"
},
{
"type": "paragraph",
"text": "Markdown — это простой язык разметки..."
},
{
"type": "list",
"items": [
"Простота",
"Гибкость",
"Совместимость"
]
}
]
}


Сохранение в базу данных (Room + TypeConverter):
@Entity
data class MarkdownNote(
@PrimaryKey(autoGenerate = true) val id: Long = 0,
val title: String,
val jsonContent: String // Храним JSON-структуру
)

class MarkdownConverter {
@TypeConverter
fun fromJson(value: String): List<MarkdownBlock> {
return Gson().fromJson(value, object : TypeToken<List<MarkdownBlock>>() {}.type)
}

@TypeConverter
fun toJson(content: List<MarkdownBlock>): String {
return Gson().toJson(content)
}
}


Парсинг Markdown в JSON с помощью библиотеки (например, flexmark-java)
fun parseMarkdownToJson(markdown: String): String {
val document = Parser.builder().build().parse(markdown)
val blocks = mutableListOf<MarkdownBlock>()

document.children.forEach { node ->
when (node) {
is Heading -> blocks.add(MarkdownBlock("header", node.level, node.text.toString()))
is Paragraph -> blocks.add(MarkdownBlock("paragraph", text = node.text.toString()))
is BulletList -> {
val items = node.children.map { it.text.toString() }
blocks.add(MarkdownBlock("list", items = items))
}
}
}
return Gson().toJson(blocks)
}


🟠Сохранение Markdown в виде HTML
Если Markdown в основном нужен для отображения, можно сразу конвертировать его в HTML и хранить в базе/файлах.
Конвертация Markdown → HTML с помощью flexmark-java:
fun convertMarkdownToHtml(markdown: String): String {
val renderer = HtmlRenderer.builder().build()
val document = Parser.builder().build().parse(markdown)
return renderer.render(document)
}


Сохранение в базу:
@Entity
data class HtmlNote(
@PrimaryKey(autoGenerate = true) val id: Long = 0,
val title: String,
val htmlContent: String
)


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

Многопоточность позволяет выполнять тяжёлые задачи без блокировки UI. В Android используют ExecutorService, Thread, Handler, Coroutines, WorkManager, RxJava, LiveData и другие средства в зависимости от задач.


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

Переход от списка (например, списка элементов в RecyclerView) к экрану деталей элемента в Android является очень распространённой задачей. Для реализации таких переходов используются Intent, Bundle, ViewModel, а также инструменты навигации, такие как Navigation Component.

🟠Переход с использованием Intent и Bundle
Это базовый способ передачи данных от одного экрана (активности) к другому.
1. При нажатии на элемент списка (RecyclerView) создается Intent.
2. В Intent передаются данные (например, ID элемента или вся информация в виде Parcelable или Serializable объекта).
3. Новый экран (деталка) запускается с помощью метода startActivity(intent).
4. На экране детализации данные извлекаются из Intent.
// Предположим, что в адаптере RecyclerView вы обрабатываете клик на элементе
val intent = Intent(this, DetailActivity::class.java)
// Передаем ID элемента через Intent
intent.putExtra("ITEM_ID", item.id)
startActivity(intent)


Деталка (DetailActivity)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_detail)

// Получаем данные из Intent
val itemId = intent.getIntExtra("ITEM_ID", -1)

// Используем itemId, чтобы загрузить данные о выбранном элементе
loadItemDetails(itemId)
}

fun loadItemDetails(id: Int) {
// Например, загрузка из базы данных или сети
}


🟠Переход с использованием Navigation Component
Navigation Component — это современный способ управления переходами между экранами в Android. Он значительно упрощает реализацию навигации и передачи данных.
1. Вы создаете граф навигации (nav_graph), где определяете все экраны (фрагменты) и связи между ними.
2. Переходы между экранами задаются как действия (actions) внутри графа.
3. Данные передаются через аргументы (arguments), которые указываются в nav_graph.

1⃣Настройка nav_graph (res/navigation/nav_graph.xml)
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="https://schemas.android.com/apk/res/android"
app:startDestination="@id/listFragment">

<fragment
android:id="@+id/listFragment"
android:name="com.example.ListFragment"
android:label="Список" >
<action
android:id="@+id/action_listFragment_to_detailFragment"
app:destination="@id/detailFragment" />
</fragment>

<fragment
android:id="@+id/detailFragment"
android:name="com.example.DetailFragment"
android:label="Детали" >
<argument
android:name="itemId"
app:argType="integer" />
</fragment>

</navigation>


2⃣Переход из списка (ListFragment)
val action = ListFragmentDirections.actionListFragmentToDetailFragment(itemId = 123)
findNavController().navigate(action)


3⃣Получение аргумента в деталке (DetailFragment)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

// Получаем аргумент, переданный через Navigation Component
val itemId = arguments?.getInt("itemId") ?: -1

// Используем itemId для загрузки деталей
loadItemDetails(itemId)
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Почему многие отказываются от MVP?

– Требует много шаблонного кода,
– Сложно масштабировать,
– Не очень гибко при асинхронных данных,
– Современные альтернативы (MVVM, MVI) лучше сочетаются с LiveData, Flow, State и coroutines.


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

Передача фото в редактор зависит от типа редактора:
1. Внешний редактор (например, Google Photos, Snapseed).
2. Встроенный редактор внутри приложения.

🚩Передача фото во внешний редактор (Intent)

Если редактор — другое приложение, используем Intent.ACTION_EDIT.
Как передать фото в редактор?
fun openPhotoEditor(context: Context, uri: Uri) {
val intent = Intent(Intent.ACTION_EDIT).apply {
setDataAndType(uri, "image/*")
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // Разрешение на чтение
}
context.startActivity(Intent.createChooser(intent, "Выберите редактор"))
}


🚩Передача в `Activity` своего приложения (FileProvider)

Если редактор — внутри приложения, можно передавать фото через Intent с Uri.
Отправка фото в редактор
fun openEditor(context: Context, photoFile: File) {
val uri = FileProvider.getUriForFile(context, "${context.packageName}.fileprovider", photoFile)

val intent = Intent(context, PhotoEditorActivity::class.java).apply {
putExtra("PHOTO_URI", uri.toString())
}

context.startActivity(intent)
}


Получение фото в редакторе (PhotoEditorActivity)
class PhotoEditorActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

val uriString = intent.getStringExtra("PHOTO_URI")
val uri = uriString?.let { Uri.parse(it) }

uri?.let {
imageView.setImageURI(it) // Показываем фото
}
}
}


🚩Если фото приходит в `byte[]` (с сервера)

Если фото уже в памяти (byte[]), можно передать его как Parcelable.
Отправка
val bitmap = ... // Получили Bitmap
val byteArray = ByteArrayOutputStream().apply {
bitmap.compress(Bitmap.CompressFormat.PNG, 100, this)
}.toByteArray()

val intent = Intent(context, PhotoEditorActivity::class.java).apply {
putExtra("PHOTO_BYTES", byteArray)
}

context.startActivity(intent)


Получение
val byteArray = intent.getByteArrayExtra("PHOTO_BYTES")
byteArray?.let {
val bitmap = BitmapFactory.decodeByteArray(it, 0, it.size)
imageView.setImageBitmap(bitmap)
}


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

В data class можно использовать только свойства, объявленные в первичном конструкторе (val или var). Эти свойства автоматически участвуют в:
- equals, hashCode;
- toString;
- copy и componentN.
Остальные свойства не считаются частью "данных" класса.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
🤔 Что нужно сделать в 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
🤔 Из каких частей состоит проект и какая часть за что отвечает?

– src/ — исходный код,
– res/ — ресурсы (строки, изображения, макеты),
– manifest — описание компонентов, разрешений, запуска,
– build.gradle — настройки сборки, зависимости,
– libs/ — внешние библиотеки,
– assets/ — файлы, доступные в рантайме.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4
🤔 Зачем нужны Data Class и Sealed Classes?

Data Class и Sealed Class решают разные задачи и обеспечивают улучшения в организации кода, управлении состоянием и безопасности типов. Они вносят значительные упрощения и повышают читаемость кода в Kotlin-проектах.

🚩Зачем они нужны

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

🟠Сокращение кода
Автоматически генерирует методы equals(), hashCode(), и toString(), а также copy() и компонентные функции для объектов данных. Это избавляет от необходимости ручной реализации этих методов, что уменьшает количество кода и возможность ошибок.

🟠Упрощение передачи данных
Идеально подходят для передачи данных между различными частями приложения, например, между слоями в архитектуре MVVM или при передаче данных между активностями и фрагментами.

🟠Поддержка неизменяемости
С помощью них легко создавать неизменяемые объекты, что способствует безопасной работе с данными, особенно в многопоточной среде.

🚩Зачем они нужны

Sealed Class используются для определения закрытых иерархий классов, где все потомки известны и ограничены. Они полезны по следующим причинам:

🟠Полное покрытие случаев в `when`
Гарантируют, что все возможные подтипы обработаны в выражениях when, что предотвращает ошибки во время выполнения из-за пропущенных случаев. Это упрощает управление состояниями и делает код более безопасным и предсказуемым.

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

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

data class User(val name: String, val age: Int)


Пример Sealed Class
sealed class Result {
data class Success(val data: String) : Result()
data class Failure(val error: Throwable) : Result()
}

fun handleResult(result: Result) {
when (result) {
is Result.Success -> println("Success with data: ${result.data}")
is Result.Failure -> println("Failure with error: ${result.error.message}")
}
}


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

В RxJava управление потоками осуществляется через subscribeOn и observeOn. Первый определяет поток, в котором будет происходить генерация данных (источник), второй — поток, в котором обрабатываются все дальнейшие операторы и подписка.


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

В Android при нажатии пользователя на экран вызывается событие ACTION_DOWN.

🚩Разбор работы событий касания

Android использует систему обработки касаний через MotionEvent. Когда пользователь касается экрана, система генерирует разные типы событий:
ACTION_DOWN – вызывается в момент первого касания.
ACTION_MOVE – вызывается, когда пользователь двигает палец по экрану.
ACTION_UP – вызывается, когда пользователь убирает палец с экрана.
ACTION_CANCEL – вызывается, если система прерывает касание (например, из-за входящего звонка).

🚩Как обрабатывать нажатие

Для обработки событий касания нужно переопределить метод onTouchEvent() в View или использовать setOnTouchListener().
override fun onTouchEvent(event: MotionEvent): Boolean {
when (event.action) {
MotionEvent.ACTION_DOWN -> {
Log.d("TouchEvent", "Палец коснулся экрана")
return true
}
MotionEvent.ACTION_UP -> {
Log.d("TouchEvent", "Палец отпущен")
}
}
return super.onTouchEvent(event)
}


Можно также назначить слушатель
view.setOnTouchListener { _, event ->
if (event.action == MotionEvent.ACTION_DOWN) {
Log.d("TouchEvent", "Нажатие зафиксировано")
true
} else {
false
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🤔 Как будут вести себя LinkedList и ArrayList, если вставить в них элемент?

В LinkedList вставка в начало или середину имеет сложность O(1), так как требуется только обновление ссылок, но доступ к элементу занимает O(n). В ArrayList вставка занимает O(n) из-за необходимости сдвига элементов, но доступ по индексу — O(1).

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

Чтобы обрабатывать жесты в 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
👍1
🤔 Как получить результат от следующей Activity?

1. Используйте метод startActivityForResult:
- Передайте Intent, а затем обработайте результат в методе onActivityResult.
2. В современных API используйте ActivityResultLauncher для управления результатами.


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

RxJava может вызывать утечки памяти, если подписки (Disposable) не очищаются правильно.
Утечки памяти происходят, когда RxJava-события продолжают выполняться после уничтожения Activity/Fragment, удерживая ссылки на View или Context.

🚩Используем `CompositeDisposable`

CompositeDisposable собирает все подписки и очищает их при onDestroy().
class MainActivity : AppCompatActivity() {
private val disposables = CompositeDisposable() // Собираем подписки

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

val disposable = Observable.interval(1, TimeUnit.SECONDS)
.subscribe { println("Tick: $it") }

disposables.add(disposable) // Добавляем подписку
}

override fun onDestroy() {
super.onDestroy()
disposables.clear() // Очищаем подписки, предотвращая утечку памяти
}
}


🚩Используем `autoDispose` (для Jetpack Lifecycle)

Если используем Jetpack ViewModel или LifecycleOwner, можно автоматически отвязывать подписки.
class MyFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
Observable.interval(1, TimeUnit.SECONDS)
.autoDispose(viewLifecycleOwner) // Автоочистка при `onDestroyView()`
.subscribe { println("Tick: $it") }
}
}


🚩Используем `Disposable.dispose()` вручную

Если подписка не в CompositeDisposable, её можно очистить вручную.
private var disposable: Disposable? = null

fun startObserving() {
disposable = Observable.interval(1, TimeUnit.SECONDS)
.subscribe { println("Tick: $it") }
}

fun stopObserving() {
disposable?.dispose() // Очищаем подписку
}


🚩Используем `ViewModel` + `LiveData` вместо RxJava

RxJava может удерживать Activity/Fragment, вызывая утечки памяти.
Лучше использовать ViewModel + LiveData!
class MyViewModel : ViewModel() {
private val _timer = MutableLiveData<Long>()
val timer: LiveData<Long> = _timer

init {
Observable.interval(1, TimeUnit.SECONDS)
.subscribe { _timer.postValue(it) }
}
}


Подписка в Activity (без утечек!)
viewModel.timer.observe(this) { println("Tick: $it") }


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🤔 Можно ли отправить своё broadcast-сообщение?

Да. Можно использовать:
- sendBroadcast(Intent) — для обычной широковещательной рассылки.
- sendOrderedBroadcast() — для последовательной доставки.
- LocalBroadcastManager (устарел, но можно использовать аналоги).
Это позволяет передавать события между компонентами приложения или уведомлять другие приложения (если экспортировано).


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