Dalvik Virtual Machine (DVM) и Android Runtime (ART) — это две среды выполнения для запуска Android-приложений. DVM использовалась в ранних версиях Android, в то время как ART пришла на замену DVM, начиная с Android 5.0 (Lollipop). Основное различие между ними заключается в способе выполнения кода и производительности.
Dalvik Virtual Machine (DVM): Just-In-Time (JIT) компиляция
Dalvik использует JIT-компиляцию (Just-In-Time), что означает, что код приложения компилируется в машинный код во время выполнения (runtime).
Когда приложение запускается, DVM интерпретирует байт-код (.dex-файлы), а при необходимости компилирует часть кода "на лету" для повышения производительности.
Этот подход требует дополнительных ресурсов во время работы приложения, что увеличивает задержки (лаг) при запуске и потребляет больше CPU и батареи.
ART использует AOT-компиляцию (Ahead-Of-Time), которая компилирует весь код приложения в машинный код заранее — во время установки приложения.
Это устраняет необходимость интерпретации и JIT-компиляции во время работы приложения, что снижает нагрузку на процессор и улучшает производительность.
Dalvik (DVM):
Поскольку JIT-компиляция происходит во время работы приложения, это создает дополнительную нагрузку на процессор и замедляет выполнение.
Производительность ниже из-за частой интерпретации кода.
ART:
Благодаря AOT-компиляции приложения запускаются быстрее и работают плавнее.
Потребление ресурсов (CPU, батарея) значительно ниже, поскольку интерпретация и компиляция кода уже выполнены на этапе установки.
Dalvik (DVM):
Приложения запускаются медленнее, так как DVM интерпретирует код во время каждого запуска.
ART:
Приложения запускаются быстрее, так как код уже компилирован в машинный код на этапе установки.
Dalvik (DVM):
Потребляет больше батареи из-за того, что JIT-компиляция выполняется постоянно во время работы приложения.
ART:
Более энергоэффективен, так как большая часть работы выполнена заранее, и процессор не нагружается так сильно.
Dalvik (DVM):
Приложения устанавливаются быстрее, так как код не компилируется заранее.
ART:
Приложения устанавливаются медленнее, так как на этапе установки выполняется AOT-компиляция.
Например, установка приложения в ART может занимать больше времени, чем в DVM, из-за компиляции кода.
Dalvik (DVM):
DVM использует меньше памяти на устройстве, так как код компилируется только во время работы приложения, и машинный код не сохраняется.
ART:
AOT-компиляция увеличивает размер приложения, так как компилированный машинный код сохраняется на устройстве. Это требует больше места в памяти.
Dalvik (DVM):
Ограниченные возможности отладки, так как JIT-компиляция не предоставляет доступа к заранее оптимизированному коду.
ART:
ART позволяет разработчикам использовать более продвинутые инструменты отладки (например, профилирование исполнения) и лучше анализировать производительность приложений.
Dalvik (DVM):
Dalvik был изначально разработан для устройств с ограниченными ресурсами (медленные процессоры, малый объем оперативной памяти).
Приложения работали в основном в условиях ограниченного оборудования.
ART:
ART ориентирован на современные устройства с мощными процессорами и большим объемом памяти.
Он лучше справляется с современными требованиями приложений.
- Установка быстрая.
- При запуске приложения DVM интерпретирует и компилирует код. Это требует времени и ресурсов.
- Приложение может работать медленно из-за интерпретации кода в реальном времени.
- Установка занимает больше времени, так как код компилируется сразу.
- Запуск приложения быстрый, потому что код уже готов к исполнению.
- Приложение работает плавно, так как отсутствует необходимость компиляции во время выполнения.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Forwarded from Идущий к IT
🔥 Записал видос "Как за 3 минуты настроить Автоотклики на вакансии HeadHunter" больше не придется заниматься этой унылой рутиной
📺 Видео: https://youtu.be/G_FOwEGPwlw
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔1💊1
suspend — это ключевое слово в Kotlin, обозначающее функцию, которая может быть приостановлена и возобновлена позже.
Такие функции выполняются внутри корутин и позволяют писать асинхронный код в линейной форме, без колбэков. Пример — delay(), networkCall() и т.п.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥2
Передача фото в редактор зависит от типа редактора:
1. Внешний редактор (например, Google Photos, Snapseed).
2. Встроенный редактор внутри приложения.
Если редактор — другое приложение, используем
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, "Выберите редактор"))
}Если редактор — внутри приложения, можно передавать фото через
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[]), можно передать его как 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
👍2
Это механизм синхронизации, который позволяет исключить одновременный доступ нескольких корутин к ресурсу.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊5👍1🔥1
Nothing — это специальный bottom type (нижний тип), который означает: Функция никогда не возвращает результат (
throw, error()). Код после
Nothing недостижим. fun fail(): Nothing {
throw IllegalStateException("Ошибка!") // Никогда не возвращает значение
}Все классы в Kotlin могут иметь инстансы (объекты), кроме
Nothing. Nothing нельзя создать (instantiate), потому что он не имеет конструктора. Любая переменная типа
Nothing просто не существует. val x: Nothing = Nothing() // ❌ Ошибка: у Nothing нет конструктора
Используется в
throwfun fail(): Nothing = throw IllegalArgumentException("Ошибка")Используется в
TODO()fun getData(): String {
TODO("Функция ещё не реализована")
}Используется в
if-else, где один вариант throwfun getValue(x: Int): String {
return if (x > 0) "Позитивное число" else throw IllegalArgumentException("Отрицательное!")
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥2
- Полная поддержка жестов.
- Системная тёмная тема.
- Scoped Storage — изоляция доступа к файлам.
- Smart Reply в уведомлениях.
- Privacy API и запреты на location в фоне.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
В Java все классы неявно наследуются от класса
Object, если явно не указано другое наследование. class MyClass {
// Неявно наследуется от Object
}
class MyClass2 extends Object {
// То же самое, просто указано явно
}Класс
Object содержит основные методы, доступные во всех классах: class Person {
String name;
Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{name='" + name + "'}";
}
}
public class Main {
public static void main(String[] args) {
Person p = new Person("Alice");
System.out.println(p.toString()); // Person{name='Alice'}
System.out.println(p.hashCode()); // Хеш-код объекта
System.out.println(p.getClass()); // class Person
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
С помощью ключевых слов val или var:
- val — неизменяемая (аналог final),
- var — изменяемая (переменная).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1
Лямбда-выражения представляют собой компактный способ представления анонимных функций, который особенно полезен для создания коротких блоков выполнения кода, предназначенных для последующей передачи другим функциям. Лямбды широко используются для упрощения работы с коллекциями, потоками данных, асинхронным кодом и в ситуациях, где требуется функциональный интерфейс.
Были введены в 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
👍1
- android:exported="false" — компонент может вызываться только внутри приложения.
С Android 12 это поле обязательно для всех компонентов с intent-filter.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
В Retrofit можно изменять все запросы глобально с помощью Interceptor (перехватчика) в OkHttp. Это позволяет добавлять или изменять заголовки, параметры запроса, авторизацию, логирование и многое другое.
Перехватчик (
Interceptor) позволяет модифицировать запрос перед его отправкой. class AuthInterceptor(private val tokenProvider: TokenProvider) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request().newBuilder()
.addHeader("Authorization", "Bearer ${tokenProvider.getToken()}")
.addHeader("Accept", "application/json")
.build()
return chain.proceed(request)
}
}Добавляем перехватчик в OkHttpClient:
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(AuthInterceptor(tokenProvider))
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build()
Иногда нужно добавлять общие GET-параметры (например, API-ключ).
class QueryInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request()
val originalUrl = originalRequest.url
val newUrl = originalUrl.newBuilder()
.addQueryParameter("api_key", "YOUR_API_KEY")
.build()
val newRequest = originalRequest.newBuilder()
.url(newUrl)
.build()
return chain.proceed(newRequest)
}
}Добавляем в
OkHttpClient: val okHttpClient = OkHttpClient.Builder()
.addInterceptor(QueryInterceptor())
.build()
Если сервер возвращает
401 Unauthorized, можно обновить токен и повторить запрос. class AuthenticatorInterceptor(private val tokenProvider: TokenProvider) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
var request = chain.request()
var response = chain.proceed(request)
if (response.code == 401) {
// Получаем новый токен
val newToken = tokenProvider.refreshToken()
// Делаем новый запрос с обновлённым токеном
val newRequest = request.newBuilder()
.header("Authorization", "Bearer $newToken")
.build()
response.close() // Закрываем старый ответ
response = chain.proceed(newRequest) // Повторяем запрос
}
return response
}
}Добавляем в
OkHttpClient: val okHttpClient = OkHttpClient.Builder()
.addInterceptor(AuthenticatorInterceptor(tokenProvider))
.build()
Для отладки удобно логировать все запросы и ответы.
val loggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.build()Если в приложении нужно менять
baseUrl, можно изменять его перед каждым запросом. class BaseUrlInterceptor(private val urlProvider: UrlProvider) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request()
val newUrl = urlProvider.getBaseUrl() + originalRequest.url.encodedPath
val newRequest = originalRequest.newBuilder()
.url(newUrl)
.build()
return chain.proceed(newRequest)
}
}Используем в
OkHttpClient: val okHttpClient = OkHttpClient.Builder()
.addInterceptor(BaseUrlInterceptor(urlProvider))
.build()
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Приложение регистрирует Intent-фильтры в манифесте (AndroidManifest.xml) или программно.
Когда система отправляет Intent (например, для открытия ссылки или получения данных), она ищет среди всех зарегистрированных компонентов те, у кого:
- intent-filter совпадает по action, category и data (например, MIME-тип или URI).
- Компонент экспортирован (если это внешний вызов).
Таким образом, Android использует фильтрацию по intent-параметрам и определяет, какие компоненты соответствуют заданному Intent.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
В 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
👍3
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4
В Kotlin оператор
== используется для структурного сравнения объектов. Оператор
== вызывает метод equals(), чтобы проверить содержимое объектов, а не их ссылки. data class User(val name: String)
fun main() {
val user1 = User("Alice")
val user2 = User("Alice")
println(user1 == user2) // true (структурное сравнение)
println(user1 === user2) // false (сравнение ссылок)
}
== проверяет, равны ли данные объектов (equals()). === проверяет, ссылаются ли объекты на один и тот же участок памяти. val str1 = "Hello"
val str2 = "Hello"
println(str1 == str2) // true (содержимое одинаковое)
println(str1 === str2) // true (Kotlin кеширует строки)
val obj1 = String("Hello".toCharArray())
val obj2 = String("Hello".toCharArray())
println(obj1 == obj2) // true (содержимое одинаковое)
println(obj1 === obj2) // false (разные объекты в памяти)
Если
equals() не переопределён, то сравниваются ссылки (как ===). class Person(val name: String)
fun main() {
val p1 = Person("Bob")
val p2 = Person("Bob")
println(p1 == p2) // false (equals() не переопределён, сравниваются ссылки)
}
Чтобы
== работал по содержимому, нужно переопределить equals()class Person(val name: String) {
override fun equals(other: Any?): Boolean {
return other is Person && other.name == this.name
}
}
fun main() {
val p1 = Person("Bob")
val p2 = Person("Bob")
println(p1 == p2) // true (equals() сравнивает содержимое)
}Kotlin предотвращает
NullPointerException при сравнении с null:val a: String? = null
val b: String? = "Hello"
println(a == b) // false (без NPE)
println(a == null) // true
Когда
a == b, на самом деле выполняется:a?.equals(b) ?: (b === null)
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Это архитектура, при которой проект разбивается на отдельные модули с разными задачами: UI, data, domain, features. Это повышает масштабируемость, ускоряет сборку и разделяет ответственность.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
В 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
👍1
- Через интерфейс: фрагмент сообщает активити о событиях.
- Через ViewModel (если используешь MVVM): общий ViewModel между фрагментом и активити.
- Через bundle-данные и методы.
- Через контекст или requireActivity().
Важно избегать прямых зависимостей, чтобы сохранить гибкость и переиспользуемость.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Это ситуация, когда приложение выделяет память для каких-либо объектов, но затем не освобождает её, даже когда эти объекты больше не нужны. Это приводит к тому, что используемая память накапливается, что может со временем замедлить работу приложения и привести к его аварийному завершению (крашу) из-за нехватки доступной памяти.
В Android утечки памяти могут возникнуть из-за особенностей работы виртуальной машины (ART или Dalvik), а также из-за того, что сборщик мусора (Garbage Collector, GC) не может освободить память для объектов, на которые по-прежнему существуют ссылки. Это происходит в следующих случаях:
Если объект ссылается на другой объект, который больше не нужен, последний не может быть освобождён GC. Например:
Статические ссылки, которые продолжают "удерживать" объект.
Замыкания (closures), которые хранят ссылки на контекст активности.
Некоторые объекты системы Android, такие как
Context, View, Handler, хранят ссылки на компоненты приложения (например, Activity), из-за чего их нельзя освободить.Ошибки, такие как регистрация слушателей (listeners) без последующей отписки, использование таймеров, которые продолжают работать даже после уничтожения активности, и так далее.
public class MyActivity extends AppCompatActivity {
private static TextView myTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myTextView = findViewById(R.id.my_text_view);
myTextView.setText("Hello, Memory Leak!");
}
}Исправленный код
public class MyActivity extends AppCompatActivity {
private TextView myTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myTextView = findViewById(R.id.my_text_view);
myTextView.setText("Hello, World!");
}
}Не используйте
static для объектов, ссылающихся на Context или Activity. Используйте WeakReference, если нужно сохранить ссылку, которая не должна блокировать сборщик мусора.Если вы регистрируете слушателей (например, через
setOnClickListener), обязательно удаляйте их в методах жизненного цикла, например, в onDestroy().Анонимные классы (например,
Runnable, Handler) могут неявно хранить ссылки на внешние классы, что может привести к утечке памяти.Android Profiler: встроенный инструмент Android Studio для мониторинга использования памяти. LeakCanary: библиотека, которая автоматически обнаруживает утечки памяти в вашем приложении.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1
– Автобоксинг — автоматическое преобразование примитива в объект (int → Integer).
– Анбоксинг — наоборот (Integer → int).
Происходит автоматически, но можно и вручную (например, Integer.valueOf(5)).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3