Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Да, Android Framework активно использует паттерн Factory в различных API. Один из самых известных примеров —
LayoutInflater. В Android для создания (инстанцирования) UI-компонентов из XML используется
LayoutInflater, который реализует паттерн Factory Method. Вместо того чтобы вручную создавать объекты View, система предоставляет фабричный метод inflate(), который "производит" экземпляры View. В XML описан интерфейс.
LayoutInflater загружает XML и создает соответствующие объекты View.Это абстрагирует создание UI-компонентов от разработчика.
val inflater = LayoutInflater.from(context)
val view = inflater.inflate(R.layout.custom_layout, parent, false)
Вместо
MediaPlayer() напрямую используется MediaPlayer.create(context, R.raw.sound), который автоматически создаёт и настраивает объект.Позволяет получить
SharedPreferences без необходимости вручную создавать экземпляр.Фабричный метод для создания
Fragment без явного вызова конструктора.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
MV* паттерны — это архитектурные подходы, разделяющие логику приложения на слои:
- MVC (Model-View-Controller): Контроллер управляет моделью и обновляет представление.
- MVP (Model-View-Presenter): Презентер принимает действия от view, взаимодействует с моделью и обновляет UI.
- MVVM (Model-View-ViewModel): ViewModel содержит логику и состояние, а view автоматически подписана на изменения через биндинг.
Цель — отделить UI от логики и улучшить масштабируемость, читаемость и тестируемость.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
ViewModel и onSaveInstanceState служат для сохранения данных при изменении конфигурации активности или фрагмента (например, при повороте экрана). Однако они решают эту задачу по-разному и имеют разные области применения. ViewModel используется для хранения и управления данными, связанных с UI, таким образом, чтобы они сохранялись при изменении конфигурации (например, при повороте экрана). Когда система уничтожает и пересоздаёт
Activity или Fragment, ViewModel остаётся в памяти до полного уничтожения владельца (например, выхода из Activity). class MyViewModel : ViewModel() {
var counter: Int = 0 // Переменная, которая сохраняется при повороте экрана
}Использование в
Activityclass 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-данные
улучшая архитектуру.
например, при закрытии приложения
Метод
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
}
}EditText). BundleСтавь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Производительность измеряется в миллисекундах времени отрисовки (measure, layout, draw). Также учитывается количество операций пересчёта и перекомпоновки. В Jetpack Compose оценивается количеством recomposition и snapshot изменений.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4
В Java есть 4 модификатора доступа, которые контролируют видимость полей, методов и классов:
Поля почти всегда должны быть
private, чтобы инкапсулировать данные. Методы тоже лучше делать private, если они не должны использоваться извне. public class User {
private String name; // ✅ Доступен только внутри класса
public User(String name) {
this.name = name;
}
private void logUserAction() { // ✅ Только внутри класса
System.out.println(name + " совершил действие");
}
}Используется, если класс не должен быть доступен за пределами пакета. Полезно для вспомогательных классов.
class FileHelper { // ✅ Доступен только в этом пакете
static void readFile(String path) {
System.out.println("Читаем файл: " + path);
}
}protected лучше использовать только в abstract классах и для методов, которые должны быть переопределены. Не используй protected для полей → нарушает инкапсуляцию! abstract class Animal {
protected void makeSound() { // ✅ Наследники могут переопределять
System.out.println("Какой-то звук");
}
}
class Dog extends Animal {
@Override
protected void makeSound() {
System.out.println("Гав-гав!");
}
}Класс можно делать
public, только если он должен быть доступен во всех пакетах. Не делай поля public → нарушает инкапсуляцию! public class UserManager { // ✅ Доступен везде
public void createUser() { // ✅ Можно вызывать в любом месте
System.out.println("Создание пользователя...");
}
}final class → класс нельзя наследовать. final method → метод нельзя переопределить. final field → переменная неизменяема (константа). public final class MathUtils {
public static final double PI = 3.14159;
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Когда выполнение suspend-функции приостанавливается (например, при delay или await), состояние функции сохраняется в continuation-объекте, а текущий поток освобождается.
Позже выполнение возобновляется с этого же места — как будто ничего не происходило. Это реализовано через стейт-машину и трансформацию кода компилятором Kotlin.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍1
sealed class – это ограниченная иерархия классов, где можно создавать разные подклассы с разными свойствами. enum class – это фиксированный набор однотипных объектов, которые не имеют разной структуры. Когда значения не изменятся (например, дни недели, цвета, статусы).
Когда у всех значений одинаковая структура.
enum class Status {
LOADING, SUCCESS, ERROR
}Можно добавлять свойства и методы
enum class Color(val hex: String) {
RED("#FF0000"),
GREEN("#00FF00"),
BLUE("#0000FF");
fun printHex() = println(hex)
}
fun main() {
val color = Color.RED
println(color.hex) // #FF0000
color.printHex() // #FF0000
}Когда у состояний разные параметры и поведение.
Когда нужен
when, который проверяет все возможные подклассы. sealed class Status {
object Loading : Status()
data class Success(val data: String) : Status()
data class Error(val message: String) : Status()
}Использование с
when (без else) fun handleStatus(status: Status) {
when (status) {
is Status.Loading -> println("Загрузка...")
is Status.Success -> println("Данные: ${status.data}")
is Status.Error -> println("Ошибка: ${status.message}")
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
- let — выполняет блок с результатом и возвращает последний оператор.
- run — используется для вычислений, возвращает результат.
- also — возвращает исходный объект и используется для побочных действий.
- apply — настраивает объект и возвращает его.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2👍1
APK (Android Package) — это архив с кодом приложения, ресурсами и манифестом.
Приложение должно быть подписано, чтобы его можно было установить на устройство.
- Это черновая версия APK, которая не имеет цифровой подписи.
- Такой APK можно запустить только в эмуляторе или при отладке (
debug build). - Google Play не принимает неподписанные APK.
При сборке
debug-версии в Android Studio: gradlew assembleDebug
Попытка установить неподписанный APK
adb install app-unsigned.apk
Ошибка
Failure [INSTALL_PARSE_FAILED_NO_CERTIFICATES]
- Подписанный APK содержит цифровую подпись, которая гарантирует, что код не был изменён.
- Android проверяет ключ подписи перед установкой.
Google Play требует подписанный APK или AAB.
Как подписать APK вручную?
apksigner sign --ks my-release-key.jks --out app-signed.apk app-unsigned.apk
Подпись APK гарантирует*
Целостность → код не был изменён после сборки.
Подлинность → приложение подписано разработчиком, а не злоумышленником.
Обновления → только приложения с тем же ключом могут обновлять старую версию.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Данные передаются с помощью специального контейнера Data, который прикрепляется к задаче при её создании. Внутри Worker эти данные можно получить через inputData, а также можно вернуть результат выполнения обратно, используя outputData, который затем доступен через LiveData или статус задачи.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4
При наследовании
data class от какого-либо суперкласса в Kotlin, важно понимать, как работают свойства (поля) суперкласса и как они влияют на функциональность и структуру data class. Поля (свойства), объявленные в суперклассе, автоматически становятся доступными в классе-наследнике. Вы можете использовать их в наследуемом классе как обычно. Однако свойства суперкласса не участвуют в автоматически сгенерированных функциях
equals(), hashCode(), и toString() для data class.У
data class Kotlin генерирует функции equals(), hashCode(), toString(), copy() и другие. Эти функции работают только с параметрами, объявленными в первичном конструкторе data-класса. Поля, которые находятся в суперклассе, не участвуют в этих функциях.Это связано с тем, что контракт
data class предполагает, что все его ключевые данные (data) определяются только параметрами первичного конструктора. Это позволяет гарантировать, что две одинаковые сущности будут сравниваться и обрабатываться корректно, основываясь только на данных самого data class.// Суперкласс с полем name
open class Person(val name: String)
// Наследуемый data-класс
data class Employee(val id: Int, val position: String) : Person(name = "Default")
val employee1 = Employee(1, "Developer")
val employee2 = Employee(1, "Developer")
println(employee1 == employee2) // true, так как сравнение основано только на id и position
println(employee1.toString()) // Employee(id=1, position=Developer)
Если вы хотите, чтобы поля суперкласса учитывались в логике
equals() или hashCode(), вам нужно переопределить эти функции вручную.data class Employee(val id: Int, val position: String) : Person(name = "Default") {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Employee || !super.equals(other)) return false
return id == other.id && position == other.position && name == other.name
}
override fun hashCode(): Int {
return 31 * super.hashCode() + id.hashCode() + position.hashCode()
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
- Жизненный цикл — особенно при навигации и конфигурации.
- Утечки памяти через context/view.
- Передача аргументов через Bundle, а не напрямую.
- Подписка на данные — отвязка в onDestroyView.
- Навигация — через Navigation Component или FragmentManager.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊1
Forwarded from easyoffer
🎉 easyoffer 2.0 — релиз уже в этом месяце!
Вас ждут новые фичи, о которых мы ранее даже не упоминали. Они сделают путь к офферам ещё быстрее и эффективнее. Расскажу о них чуть позже 👀
В честь запуска мы готовим ограниченную акцию:
Первые 500 покупателей получат:
🚀 PRO тариф на 1 год с 50% скидкой
Что нужно сделать:
🔔 Подпишитесь на этот Telegram-канал, чтобы первыми узнать о старте релиза. Сообщение появится в нем раньше, чем где-либо еще — вы успеете попасть в число первых 500 и получить максимальную выгоду. 🎁 А еще только для подписчиков канала ценный бонус в подарок к PRO тарифу.
📅 Официальный запуск — уже совсем скоро.
Следите за новостями и не пропустите старт!
Вас ждут новые фичи, о которых мы ранее даже не упоминали. Они сделают путь к офферам ещё быстрее и эффективнее. Расскажу о них чуть позже 👀
В честь запуска мы готовим ограниченную акцию:
Первые 500 покупателей получат:
🚀 PRO тариф на 1 год с 50% скидкой
Что нужно сделать:
🔔 Подпишитесь на этот Telegram-канал, чтобы первыми узнать о старте релиза. Сообщение появится в нем раньше, чем где-либо еще — вы успеете попасть в число первых 500 и получить максимальную выгоду. 🎁 А еще только для подписчиков канала ценный бонус в подарок к PRO тарифу.
📅 Официальный запуск — уже совсем скоро.
Следите за новостями и не пропустите старт!
Разделение UI и бизнес-логики делает код понятнее, тестируемее и проще в поддержке.
Это ключевой принцип чистой архитектуры (Clean Architecture) и паттернов MVP, MVVM, MVI.
Плохой код (UI + логика в
Activity) class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val button = findViewById<Button>(R.id.button)
button.setOnClickListener {
val result = fetchData() // ❌ Логика в UI
button.text = result
}
}
fun fetchData(): String {
return "Данные с сервера" // ❌ Тут должна быть ViewModel
}
}Разделим код на
Activity + ViewModel MainActivity (только UI) class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val button = findViewById<Button>(R.id.button)
viewModel.text.observe(this) { text ->
button.text = text // ✅ UI обновляется из ViewModel
}
button.setOnClickListener {
viewModel.loadData() // ✅ Вызываем бизнес-логику
}
}
}MainViewModel (бизнес-логика) class MainViewModel : ViewModel() {
private val _text = MutableLiveData<String>()
val text: LiveData<String> = _text
fun loadData() {
_text.value = "Данные с сервера" // ✅ UI не знает, откуда данные
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
1. Try-catch внутри launch {} или async {} – локальная обработка ошибок.
2. CoroutineExceptionHandler – глобальная обработка в launch, но не работает с async.
3. supervisorScope {} – дочерние корутины не завершают родительский scope при ошибке.
4. try-catch вокруг await() – обработка исключений из async.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥2
Проблемы с элементами списка в Android-приложениях могут быть разнообразными. Давайте рассмотрим некоторые из наиболее распространённых проблем и способы их решения.
// Пример использования Glide для загрузки изображений
Glide.with(context)
.load(imageUrl)
.into(imageView)
class MyAdapter(private val itemList: List<Item>) : RecyclerView.Adapter<MyAdapter.ViewHolder>() {
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val textView: TextView = itemView.findViewById(R.id.textView)
val imageView: ImageView = itemView.findViewById(R.id.imageView)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_layout, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = itemList[position]
holder.textView.text = item.text
Glide.with(holder.itemView.context).load(item.imageUrl).into(holder.imageView)
}
override fun getItemCount() = itemList.size
} class ItemDiffCallback : DiffUtil.ItemCallback<Item>() {
override fun areItemsTheSame(oldItem: Item, newItem: Item): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: Item, newItem: Item): Boolean {
return oldItem == newItem
}
}
// Использование в адаптере
val diffCallback = ItemDiffCallback()
val diffResult = DiffUtil.calculateDiff(diffCallback)
diffResult.dispatchUpdatesTo(myAdapter)val liveData = MutableLiveData<List<Item>>()
liveData.observe(viewLifecycleOwner, Observer { items ->
myAdapter.submitList(items)
})
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Плюсы:
- Повышение производительности на часто вызываемом коде.
- Гибкая оптимизация под конкретное устройство.
Используется в Java, Dalvik и некоторых JavaScript-движках.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3👍1
Переменные по умолчанию не могут быть
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
👍3🤔1
Контекст (Context) предоставляет доступ к системным ресурсам и функциям:
- доступ к Resources, Assets,
- запуск Activity, Service,
- доступ к SharedPreferences,
- получение SystemService.
Это один из ключевых элементов Android, передающий «среду выполнения».
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1