Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
В Java и Kotlin существуют различные типы данных, которые можно разделить на две основные категории:
Примитивные типы данных (primitive types)
Ссылочные типы данных (reference types)
Ссылочные типы данных указывают на объекты. Они хранятся в куче (heap) и содержат ссылку (адрес) на объект.
Примеры ссылочных типов
String str = "Hello";MyClass obj = new MyClass();int[] arr = {1, 2, 3};List<Integer> list = new ArrayList<>();В Kotlin типы данных делятся на nullable и non-nullable (значения, которые могут быть
null, и те, которые не могут). Kotlin избегает примитивных типов напрямую, но на уровне JVM использует их для оптимизации. Kotlin предоставляет высокоуровневые обёртки для примитивных типов. Например:
Int вместо intDouble вместо doubleВ 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!")
}
}
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
👍3
MainActivity — обычно центральная точка входа с навигацией. Специализированные активити, такие как просмотр фото или метрик, имеют ограниченную функциональность и могут иметь другой жизненный цикл или быть настроены как noHistory, чтобы не сохраняться в бэкстеке.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
В Android есть два основных типа потоков:
1. UI Thread (главный поток) → отвечает за интерфейс и обработку событий.
2. Worker Thread (фоновый поток) → используется для долгих операций (запросы в сеть, работа с БД).
- Отвечает за отрисовку интерфейса (Activity, Fragment, View).
- Обрабатывает нажатия, свайпы, анимации.
- Все
setText(), setImageResource() и другие UI-методы работают только здесь. Если делать тяжёлые операции в UI Thread, приложение зависнет (ANR - Application Not Responding)! val url = URL("https://example.com")
val connection = url.openConnection() as HttpURLConnection // ❌ Ошибка!- Выполняет долгие операции, не блокируя UI:
Запросы в сеть (Retrofit, OkHttp)
Чтение/запись в БД (Room, SQLite)
Обработку файлов, JSON, XML
Любые тяжёлые вычисления
CoroutineScope(Dispatchers.IO).launch {
val url = URL("https://example.com")
val connection = url.openConnection() as HttpURLConnection // ✅ Работает!
}Способ 1:
Coroutines (лучший вариант)CoroutineScope(Dispatchers.IO).launch {
val data = fetchData() // Работает в `Worker Thread`
withContext(Dispatchers.Main) {
textView.text = data // Назад в `UI Thread`
}
}Способ 2:
Handler + Thread (старый вариант) val handler = Handler(Looper.getMainLooper())
Thread {
val data = fetchData() // Работает в `Worker Thread`
handler.post {
textView.text = data // Назад в `UI Thread`
}
}.start()
Способ 3:
AsyncTask (УСТАРЕЛ, НЕ ИСПОЛЬЗОВАТЬ!) class MyTask : AsyncTask<Void, Void, String>() {
override fun doInBackground(vararg params: Void?): String {
return fetchData() // `Worker Thread`
}
override fun onPostExecute(result: String) {
textView.text = result // `UI Thread`
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊2👍1
- Для обычного (started) сервиса:
- Внутри самого сервиса:
Для bound service — вызывается unbindService().
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊2🔥1🤔1
Forwarded from easyoffer
Ура, друзья! Изиоффер переходит в публичное бета-тестирование!
🎉 Что нового:
🟢 Анализ IT собеседований на основе 4500+ реальных интервью
🟢 Вопросы из собеседований с вероятностью встречи
🟢 Видео-примеры ответов на вопросы от Senior, Middle, Junior грейдов
🟢 Пример лучшего ответа
🟢 Задачи из собеседований
🟢 Тестовые задания
🟢 Примеры собеседований
🟢 Фильтрация всего контента по грейдам, компаниям
🟢 Тренажер подготовки к собеседованию на основе интервальных повторений и флеш карточек
🟡 Тренажер "Реальное собеседование" с сценарием вопросов из реальных собеседований (скоро)
🟢 Автоотклики на HeadHunter
🟢 Закрытое сообщество easyoffer
💎 Акция в честь открытия для первых 500 покупателей:
🚀 Скидка 50% на PRO тариф на 1 год (15000₽ → 7500₽)
🔥 Акция уже стартовала! 👉 https://easyoffer.ru/pro
🎉 Что нового:
💎 Акция в честь открытия для первых 500 покупателей:
🚀 Скидка 50% на PRO тариф на 1 год (
🔥 Акция уже стартовала! 👉 https://easyoffer.ru/pro
Please open Telegram to view this post
VIEW IN TELEGRAM
Софткод (Softcode, Soft Coding) — это подход к программированию, при котором логика программы хранится в конфигурационных файлах, базе данных или других внешних источниках, а не жёстко (hardcoded) прописана в коде.
Пример Hardcode (жёстко зашито в коде)
val apiUrl = "https://api.example.com" // ❌ Если URL изменится, надо менять код
Пример Softcode (гибко через конфигурацию)
val apiUrl = Config.get("api_url") // ✅ Загружается из настроекКонфигурационные файлы (
config.json, .properties, .xml). База данных (логика, настройки, права пользователей).
API и сервер (получение UI-элементов, бизнес-логики с сервера).
Скриптовые языки (скрипты загружаются динамически).
Softcode через
SharedPreferences (конфигурация в памяти)val sharedPrefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
val theme = sharedPrefs.getString("app_theme", "light") // ✅ Загружаем тему из настроекSoftcode через
remoteConfig (Firebase Remote Config)val minVersion = Firebase.remoteConfig.getInt("min_supported_version")Softcode через JSON-файл (читаем конфиг из assets)
fun getConfigValue(context: Context, key: String): String {
val json = context.assets.open("config.json").bufferedReader().use { it.readText() }
val jsonObject = JSONObject(json)
return jsonObject.getString(key) // ✅ Получаем значение из JSON
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
- git pull = fetch + merge — загружает и сразу применяет изменения к текущей ветке.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2👍1
XML — это eXtensible Markup Language (Расширяемый язык разметки).
eXtensible → Расширяемый (можно создавать свои теги).
Markup → Разметка (использует теги
<tag> для структурирования данных). Language → Язык (формат хранения и передачи данных).
В Android:
Разметка UI (
activity_main.xml). Конфигурация (
AndroidManifest.xml). Ресурсы (
strings.xml, colors.xml). В веб-разработке:
Конфигурации (
.xml файлы в серверных приложениях). Форматы обмена данными (SOAP, RSS, SVG).
Пример XML-кода
<user>
<name>Алиса</name>
<age>25</age>
</user>
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Hilt позволяет внедрять контекст с помощью аннотаций
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Анонимный класс внутри
inline-функции будет инстанцироваться при каждом вызове функции, что ломает цель inline — избавляться от накладных расходов на объекты. Анонимный класс — это класс без имени, который можно создать с помощью
object : Interface {}. interface ClickListener {
fun onClick()
}
fun main() {
val listener = object : ClickListener {
override fun onClick() {
println("Кнопка нажата!")
}
}
listener.onClick()
}Если мы создадим анонимный класс внутри
inline-функции, он будет создаваться каждый раз при вызове функции! inline fun setClickListener(action: () -> Unit) {
val listener = object : ClickListener {
override fun onClick() {
action()
}
}
listener.onClick()
}
fun main() {
setClickListener { println("Нажато!") }
}Ошибка компиляции
Inline function cannot contain object expressions
Если нужно использовать
inline, можно передавать лямбду вместо анонимного класса. Рабочий вариант
inline fun setClickListener(noinline action: () -> Unit): ClickListener {
return object : ClickListener {
override fun onClick() {
action()
}
}
}
fun main() {
val listener = setClickListener { println("Нажато!") }
listener.onClick()
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Это ситуация, когда в куче (heap) оказывается объект неправильного типа из-за неправильного использования дженериков. Это может привести к ClassCastException во время выполнения.
Причины загрязнения:
- Использование необработанных типов (raw types), например List вместо List<String>.
- Нарушение type safety при кастах ((List<Integer>) obj).
- Использование varargs с дженериками (List<T>... args).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4
Переменные по умолчанию не могут быть
null, что предотвращает NullPointerException.var a: String = "abc"
var b: String? = "abc"
b = null // Допустимо
Разделение на изменяемые и неизменяемые коллекции.
val list: List<String> = listOf("a", "b", "c") // Неизменяемый список
val mutableList: MutableList<String> = mutableListOf("a", "b", "c") // Изменяемый список Автоматическое создание методов
equals(), hashCode(), и toString().data class User(val name: String, val age: Int)
Автоматическое приведение типа после проверки с помощью
is.fun demo(x: Any) {
if (x is String) {
println(x.length)
}
} Упрощают обработку ограниченных иерархий классов.
sealed class Expr
data class Const(val number: Double) : Expr()
Kotlin автоматически определяет тип переменной.
val x = 10 // Int
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
1. Контролировать память: избегать лишнего создания объектов.
2. Гарантировать единственный экземпляр: например,
3. Разделять области ответственности: создавать зависимости, привязанные к жизненному циклу Activity, Fragment, ViewModel и т.д.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Бранчинг (ветвление) — это способ управления кодом в Git, когда разработчики работают в отдельных ветках (
branches). Основные стратегии бранчинга
Git Flow
GitHub Flow
GitLab Flow
Trunk-Based Development
Основные ветки:
main (стабильная версия, релизы). develop (основная ветка разработки). Временные ветки:
feature/* (новые фичи, мерджатся в develop). release/* (готовится релиз, тестирование, фикс багов). hotfix/* (критические фиксы в main). Схема Git Flow:
main ──── hotfix ─▶️ merge ────▶️ main
│
├── develop ─▶️ release ─▶️ merge ─▶️ main
│ │
├── feature/1
├── feature/2
Только две основные ветки:
main (всегда стабильная версия). Фичи разрабатываются в
feature/* и сразу мерджатся в main. Деплой возможен сразу после мерджа в
main. Схема GitHub Flow
main ────▶️ feature/1 ─▶️ merge ─▶️ main ─▶️ deploy
└── feature/2 ─▶️ merge ─▶️ main ─▶️ deploy
main – стабильная ветка (готовая к продакшену). develop (опционально) – если нужно тестирование перед main. feature/* – для разработки новых фич. production, staging – если нужно разделение сред. hotfix/* – фиксы продакшена. main ────▶️ production
│
├── staging ───▶️ merge ─▶️ main
│
├── feature/1 ─▶️ merge ─▶️ staging
├── feature/2 ─▶️ merge ─▶️ staging
Разработчики работают прямо в
main, без feature/* веток. - Коммиты в
main маленькие и частые. - Используются Feature Flags (фичи включаются/выключаются динамически).
Схема Trunk-Based
main ────▶️ commit ─▶️ commit ─▶️ commit ─▶️ deploy
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥2
Самый обычный сервис, который наследуется от класса
Service, по умолчанию запускается в главном потоке приложения, который также называется UI-потоком (User Interface Thread). Это означает, что все операции, выполняемые в сервисе, включая методы onStartCommand(), onCreate(), и onBind(), выполняются в главном потоке. Если в сервисе будут выполняться длительные или ресурсоемкие операции, такие как сетевые запросы, обработка больших данных или выполнение сложных вычислений, это может привести к "зависанию" пользовательского интерфейса и появлению сообщений о том, что приложение не отвечает (ANR — Application Not Responding).Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1💊1
- throw используется для генерации исключения в конкретном месте кода.
- throws указывается в сигнатуре метода, и сообщает, что метод может выбросить исключение.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4
Термин "Extensions" (расширения) используется для обозначения функциональности, которая позволяет добавлять новые возможности к существующим классам без изменения их исходного кода. Этот концепт особенно популярен к примеру в Swift и Kotlin, где расширения используются для улучшения читаемости кода, упрощения его структуры и добавления удобных методов для работы с уже существующими типами данных.
Расширения позволяют добавить новую функциональность к классам, даже если исходный код этих классов недоступен для изменений (например, классы из стандартной библиотеки или сторонних библиотек). Это делается путём объявления функций или свойств, которые могут быть вызваны на экземплярах этих классов, как если бы они были частью оригинальных классов.
// Расширение класса String для проверки, пуста ли строка или состоит из пробелов
fun String.isNullOrBlank(): Boolean {
return this == null || this.trim().isEmpty()
}
// Использование расширения
val myString = " "
println(myString.isNullOrBlank()) // Выведет: true
Использует очень похожий подход, позволяя добавлять новые методы и вычисляемые свойства к существующим типам. Расширения могут даже добавлять новые протоколы к типам, что делает их чрезвычайно мощным инструментом в разработке под iOS и macOS.
// Расширение стандартного типа String для добавления метода инвертирования строки
extension String {
func reversedString() -> String {
return String(self.reversed())
}
}
let myString = "Hello"
print(myString.reversedString()) // Выведет: "olleH"
Расширения позволяют держать методы, связанные с определёнными типами данных, ближе к использованию этих типов.
Расширения предоставляют альтернативный способ добавления функциональности к классам без использования наследования, что помогает избежать избыточной иерархии и увеличения сложности системы.
Методы, добавленные через расширения, могут быть легко переиспользованы в различных частях приложения.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
- AAB — содержит все ресурсы и DEX-коды для всех конфигураций, но не устанавливается напрямую.
Google Play генерирует APK под конкретное устройство, уменьшая размер загрузки.
Формат обязателен для публикации в Google Play с 2021 года.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊3🔥2
Передача больших данных (например, изображений, видео, JSON) между
Activity требует оптимального подхода, потому что: Intent.putExtra() имеет ограничение по размеру (~1MB). Передача
Bitmap в Intent может вызвать TransactionTooLargeException. Большие данные лучше передавать через
Uri, БД или FileProvider. Неправильный способ (НЕ ДЕЛАТЬ!) –
Bitmap через Intent val bitmap: Bitmap = getBitmap()
val intent = Intent(this, ImageActivity::class.java)
intent.putExtra("image", bitmap) // ❌ ОПАСНО! Может вызвать Exception
startActivity(intent)
Сохраняем изображение во
File и получаем Uri fun saveBitmapToFile(context: Context, bitmap: Bitmap): Uri {
val file = File(context.cacheDir, "image.png")
file.outputStream().use {
bitmap.compress(Bitmap.CompressFormat.PNG, 100, it)
}
return FileProvider.getUriForFile(context, "${context.packageName}.fileprovider", file)
}Передаём
Uri через Intent val uri = saveBitmapToFile(this, bitmap)
val intent = Intent(this, ImageActivity::class.java).apply {
putExtra("image_uri", uri.toString())
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // Даем доступ другому Activity
}
startActivity(intent)
Получаем
Uri в ImageActivity и загружаем изображение val uriString = intent.getStringExtra("image_uri")
val uri = Uri.parse(uriString)
val bitmap = BitmapFactory.decodeStream(contentResolver.openInputStream(uri))
imageView.setImageBitmap(bitmap)Если изображение уже хранится в базе данных (
Room), передаём ID записи, а не сам файл. val intent = Intent(this, ImageActivity::class.java)
intent.putExtra("image_id", imageId) // Передаём только ID
startActivity(intent)
Сохраняем путь
val filePath = saveBitmapToFile(this, bitmap).toString()
getSharedPreferences("app_prefs", MODE_PRIVATE).edit()
.putString("last_image", filePath)
.apply()
Читаем путь в
Activity val filePath = getSharedPreferences("app_prefs", MODE_PRIVATE)
.getString("last_image", null)
val bitmap = BitmapFactory.decodeFile(filePath)
imageView.setImageBitmap(bitmap)Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3