Kotlin | Вопросы собесов
2.56K subscribers
27 photos
957 links
Download Telegram
🤔 Какое значение будет у переменной val x = listOf(1, 2, 3).lastOrNull { it < 3 } ?: 0?
Anonymous Quiz
5%
1
58%
2
9%
3
29%
0
📌 Что такое scope, как они работают?

💬 Спрашивают в 7% собеседований

В контексте Dagger, scope (область видимости) используется для управления временем жизни объектов и их зависимостей. Скоупы позволяют создавать объекты, которые могут быть переиспользованы в рамках определенного жизненного цикла, предотвращая ненужное создание новых экземпляров объектов. Это особенно полезно для управления зависимостями в Android-приложениях, где важна эффективная работа с памятью и производительность.

🤔 Основные концепции и работа с scope

1️⃣ Аннотации Scope:
Dagger использует аннотации для определения скоупов. Например, для создания синглтона (единственного экземпляра) на уровне приложения используется аннотация @Singleton.
Вы также можете создавать свои собственные скоупы с помощью аннотации @Scope.

   @Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScope {}


2️⃣ Использование скоупов с компонентами:
Скоупы связываются с компонентами Dagger. Когда вы аннотируете компонент и предоставляемые зависимости скоупом, Dagger гарантирует, что каждый раз, когда компонент предоставляет зависимость, он использует один и тот же экземпляр.
   @Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {
void inject(MyApplication application);
}

@Module
public class AppModule {
@Singleton
@Provides
public ApiService provideApiService() {
return new ApiServiceImpl();
}
}


3️⃣ Пример использования пользовательского скоупа:
Допустим, у нас есть скоуп для активности. Мы определяем его как @ActivityScope и используем в соответствующих компонентах и модулях.
   @ActivityScope
@Component(dependencies = AppComponent.class, modules = {ActivityModule.class})
public interface ActivityComponent {
void inject(MyActivity activity);
}

@Module
public class ActivityModule {
@ActivityScope
@Provides
public UserRepository provideUserRepository(ApiService apiService) {
return new UserRepository(apiService);
}
}


4️⃣ Работа с подкомпонентами:
Dagger поддерживает иерархию компонентов, где один компонент может включать подкомпоненты. Подкомпоненты могут наследовать зависимости из родительского компонента и определять свои собственные зависимости с отдельными скоупами.
   @Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {
ActivityComponent newActivityComponent(ActivityModule module);
}

@ActivityScope
@Subcomponent(modules = {ActivityModule.class})
public interface ActivityComponent {
void inject(MyActivity activity);
}


🤔 Преимущества использования scope

1️⃣ Оптимизация памяти и производительности:
Скоупы позволяют избежать многократного создания одинаковых объектов, что экономит память и улучшает производительность.
2️⃣ Управление жизненным циклом объектов:
Скоупы помогают управлять временем жизни объектов, что особенно важно в Android для управления ресурсами и предотвращения утечек памяти.

3️⃣ Упрощение тестирования:
Четкое определение скоупов упрощает написание тестов, так как вы можете легко подменять зависимости и контролировать их время жизни.

🤔 Краткий вывод

Scope в Dagger управляет временем жизни объектов и их зависимостей. Он предотвращает многократное создание одних и тех же объектов, оптимизируя использование памяти и улучшая производительность приложения.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍31
🤔 Какой результат выполнения выражения val result = (1..3).flatMap { listOf(it, it * 2) }?
Anonymous Quiz
10%
[1, 2, 3, 4, 6]
77%
[1, 2, 2, 4, 3, 6]
10%
[1, 2, 2, 3, 4, 6]
3%
[1, 3, 2, 4, 6]
📌 Как правильно организовать работу с UI?

💬 Спрашивают в 7% собеседований

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

🤔 Основные принципы

1️⃣ Разделение ответственности:
Используйте архитектурные паттерны, такие как MVP (Model-View-Presenter), MVVM (Model-View-ViewModel) или MVI (Model-View-Intent), чтобы разделить логику представления (UI) и бизнес-логику. Это делает код более управляемым и тестируемым.

2️⃣ Использование ViewModel:
ViewModel из Android Architecture Components помогает сохранять данные при изменениях конфигурации (например, при повороте экрана) и управлять состоянием UI.

3️⃣ Жизненный цикл:
Учитывайте жизненный цикл Activity и Fragment. Используйте LiveData для автоматического обновления UI при изменении данных.

4️⃣ Асинхронность:
Выполняйте длительные операции (например, сетевые запросы или операции с базой данных) в фоновом потоке, используя такие инструменты, как Coroutines, RxJava или ExecutorService.

🤔 Практики

1️⃣ Использование архитектурных компонентов:
Android предоставляет архитектурные компоненты, такие как ViewModel, LiveData, Room и DataBinding, которые упрощают управление UI и данными.

2️⃣ Data Binding:
Data Binding Library позволяет связывать элементы интерфейса с источниками данных, что сокращает количество шаблонного кода и упрощает обновление UI.

3️⃣ Dependency Injection:
Использование DI (например, с Dagger или Hilt) упрощает управление зависимостями и улучшает тестируемость кода.

🤔 Краткий вывод

Чтобы правильно организовать работу с UI в Android, используйте архитектурные паттерны, такие как MVVM, внедрение зависимостей, асинхронные операции, ViewModel и LiveData. Это помогает разделить ответственность, улучшить управляемость кода и обеспечить отзывчивость интерфейса.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1
🤔 Какое ключевое слово используется для объявления параметров функции по умолчанию в Kotlin?
Anonymous Quiz
14%
default
6%
const
15%
var
65%
=
👀12
📌 Как организовать работу с текстом и картинками в делегате?

💬 Спрашивают в 7% собеседований

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

🤔 Основные шаги

1️⃣Определение моделей данных
2️⃣ Создание интерфейса делегата
3️⃣ Реализация делегатов для текста и картинок

🤔 Пример

Предположим, у нас есть два типа элементов: текстовые сообщения и изображения. Мы будем использовать подход делегатов для управления этими элементами.

1️⃣ Определение моделей данных

sealed class ListItem {
data class TextItem(val text: String) : ListItem()
data class ImageItem(val imageUrl: String) : ListItem()
}


2️⃣ Создание интерфейса делегата

interface AdapterDelegate {
fun isForViewType(items: List<ListItem>, position: Int): Boolean
fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder
fun onBindViewHolder(items: List<ListItem>, position: Int, holder: RecyclerView.ViewHolder)
}


3️⃣ Реализация делегатов для текста и картинок

Делегат для текста

class TextDelegate : AdapterDelegate {
override fun isForViewType(items: List<ListItem>, position: Int): Boolean {
return items[position] is ListItem.TextItem
}

override fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_text, parent, false)
return TextViewHolder(view)
}

override fun onBindViewHolder(items: List<ListItem>, position: Int, holder: RecyclerView.ViewHolder) {
val textItem = items[position] as ListItem.TextItem
(holder as TextViewHolder).bind(textItem)
}

class TextViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val textView: TextView = itemView.findViewById(R.id.text_view)
fun bind(item: ListItem.TextItem) {
textView.text = item.text
}
}
}


Делегат для картинок

class ImageDelegate : AdapterDelegate {
override fun isForViewType(items: List<ListItem>, position: Int): Boolean {
return items[position] is ListItem.ImageItem
}

override fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_image, parent, false)
return ImageViewHolder(view)
}

override fun onBindViewHolder(items: List<ListItem>, position: Int, holder: RecyclerView.ViewHolder) {
val imageItem = items[position] as ListItem.ImageItem
(holder as ImageViewHolder).bind(imageItem)
}

class ImageViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val imageView: ImageView = itemView.findViewById(R.id.image_view)
fun bind(item: ListItem.ImageItem) {
// Используйте библиотеку загрузки изображений, например, Glide
Glide.with(itemView.context).load(item.imageUrl).into(imageView)
}
}
}



🤔 Краткий вывод

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

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍52🤔1
🤔 Какой результат выполнения выражения val result = listOf(1, 2, 3).reduce { acc, i -> acc - i }?
Anonymous Quiz
32%
-6
42%
-4
8%
-2
18%
0
📌 Как делать списки чатов с точки зрения UI?

💬 Спрашивают в 7% собеседований

Создание списков чатов с точки зрения UI требует учёта множества аспектов, чтобы обеспечить удобство использования, хорошую производительность и красивый внешний вид. В этой задаче важно учесть, как будет отображаться каждая чат-комната, отдельные сообщения и различные состояния (например, новые сообщения, непрочитанные сообщения, онлайн-статус пользователя и т.д.).

🤔 Основные шаги

1️⃣ Определение данных
2️⃣ Создание макетов для элементов списка
3️⃣Создание адаптера для RecyclerView
4️⃣Настройка RecyclerView и управление данными
5️⃣Оптимизация производительности

Пример реализации

1️⃣ Определение данных

Для чата мы можем определить два типа элементов: чат-комнаты и сообщения.

data class ChatRoom(
val id: String,
val name: String,
val lastMessage: String,
val timestamp: Long,
val unreadCount: Int,
val imageUrl: String
)

data class Message(
val id: String,
val chatRoomId: String,
val senderId: String,
val text: String,
val timestamp: Long,
val isRead: Boolean
)


2️⃣ Создание макетов для элементов списка

Макет для элемента чат-комнаты (item_chat_room.xml)


3️⃣ Создание адаптера для RecyclerView

Адаптер для списка чат-комнат


4️⃣ Настройка RecyclerView и управление данными

Настройка RecyclerView в Activity или Fragment


5️⃣ Оптимизация производительности

ViewHolder Pattern: Уже используется, так как RecyclerView автоматически использует паттерн ViewHolder.
DiffUtil: Для оптимального обновления данных в RecyclerView, используйте DiffUtil для вычисления различий между старым и новым списком.
Пагинация: Если у вас много данных, рассмотрите возможность использования Paging Library для подгрузки данных по мере прокрутки.

// Пример использования DiffUtil
class ChatRoomsAdapter : RecyclerView.Adapter<ChatRoomsAdapter.ChatRoomViewHolder>() {

private val chatRooms = mutableListOf<ChatRoom>()

fun setChatRooms(newChatRooms: List<ChatRoom>) {
val diffCallback = ChatRoomDiffCallback(chatRooms, newChatRooms)
val diffResult = DiffUtil.calculateDiff(diffCallback)

chatRooms.clear()
chatRooms.addAll(newChatRooms)
diffResult.dispatchUpdatesTo(this)
}

// Остальной код адаптера...

class ChatRoomDiffCallback(
private val oldList: List<ChatRoom>,
private val newList: List<ChatRoom>
) : DiffUtil.Callback() {

override fun getOldListSize() = oldList.size

override fun getNewListSize() = newList.size

override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition].id == newList[newItemPosition].id
}

override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition] == newList[newItemPosition]
}
}
}


🤔 Краткий вывод

Для создания списка чатов в Android используйте RecyclerView с делегатами для управления различными типами данных, такими как текстовые сообщения и изображения. Это включает в себя определение моделей данных, создание макетов для элементов списка, настройку адаптера и оптимизацию производительности с помощью таких инструментов, как DiffUtil и пагинация.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍41
🤔 Какое значение примет переменная val y = "kotlin".capitalize()?
Anonymous Quiz
5%
kotlin
41%
Kotlin
52%
KOTLIN
1%
kOTLIN
🤔 В каких случаях расчет diff в background потоке работает плохо?

Расчет DiffUtil в фоновом потоке является полезной практикой для повышения производительности и обеспечения плавного пользовательского интерфейса. Однако в некоторых случаях он может работать плохо или даже вызывать проблемы. Вот несколько таких случаев:

🟠Модификация данных во время расчета DiffUtil: Если данные изменяются в процессе вычисления DiffUtil, это может привести к некорректным результатам. Например, если данные в списке обновляются из другого потока, пока выполняется расчет диффа, результаты могут быть несогласованными или некорректными.

🟠Сложные и длительные вычисления в DiffUtil.Callback: Если методы areItemsTheSame или areContentsTheSame выполняют сложные или длительные вычисления, это может негативно сказаться на производительности, даже если расчет выполняется в фоновом потоке. Это может также вызвать блокировки или задержки в главном потоке, если результат используется для обновления UI.

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

🟠Многопоточность и состояние гонки: Работа с DiffUtil в фоновом потоке может вызвать проблемы многопоточности, если не обеспечить должную синхронизацию. Это может привести к состоянию гонки, когда разные потоки пытаются одновременно обновить данные или интерфейс.

🟠Изменение данных во время обновления интерфейса: Если данные изменяются в процессе обновления интерфейса на основе результатов DiffUtil, это может привести к несогласованности интерфейса. Например, если пользовательский интерфейс обновляется в главном потоке, а данные изменяются в фоновом потоке, результаты могут быть непредсказуемыми.

Пример проблемы с многопоточностью
// Определение diffCallback
val diffCallback = object : DiffUtil.Callback() {
override fun getOldListSize() = oldList.size
override fun getNewListSize() = newList.size

override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
// Сложные вычисления или доступ к данным, которые могут измениться
return oldList[oldItemPosition].id == newList[newItemPosition].id
}

override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
// Сложные вычисления или доступ к данным, которые могут измениться
return oldList[oldItemPosition] == newList[newItemPosition]
}
}

// Выполнение diff в фоновом потоке
Thread {
val diffResult = DiffUtil.calculateDiff(diffCallback)

// Обновление UI в главном потоке
runOnUiThread {
adapter.submitList(newList)
diffResult.dispatchUpdatesTo(adapter)
}
}.start()


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
🤔 Какой результат выполнения выражения val x = "Hello".drop(3)?
Anonymous Quiz
23%
He
28%
Hel
44%
lo
5%
llo
🤔 Когда лучше использовать png и webp, а когда svg?

Использование различных форматов изображений в Android приложениях зависит от контекста и требований к качеству изображения, его размеру и поддержке различных экранов. Вот рекомендации по выбору между PNG, WebP и SVG:

🚩Когда использовать PNG:

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

Преимущества:
🟠Поддержка прозрачности (альфа-канала).
🟠Без потерь качества (lossless compression).

Недостатки: Большой размер файлов по сравнению с другими форматами, такими как WebP.

🚩WebP:

🟠Фотографии и сложные изображения: WebP хорошо подходит для фотографий и изображений с множеством цветов и градиентов, так как он поддерживает как сжатие без потерь (lossless), так и сжатие с потерями (lossy).
🟠Сжатие и экономия пространства: Если необходимо уменьшить размер файлов без значительной потери качества, WebP может сжать изображения до 34% меньше, чем аналогичные изображения в формате PNG.

Преимущества:
🟠Поддержка сжатия как с потерями, так и без потерь.
🟠Поддержка прозрачности.
🟠Меньший размер файлов по сравнению с PNG и JPEG.

Недостатки: Поддержка WebP появилась в Android 4.0 (API Level 14). В старых версиях Android этот формат не поддерживается.

🚩SVG

🟠Векторные изображения: SVG идеально подходит для векторных изображений, таких как иконки, логотипы и другие графические элементы, которые могут масштабироваться без потери качества.
🟠Изображения, требующие масштабирования: Когда изображение должно корректно отображаться на экранах с различным разрешением и плотностью пикселей (DPI), SVG гарантирует четкость и качество на любом экране.

Преимущества:
🟠Масштабируемость без потери качества.
🟠Малый размер файла для векторных изображений.
🟠Возможность изменения и стилизации с помощью CSS и JavaScript (для веб-приложений).

Недостатки:
🟠Ограниченная поддержка сложных изображений и фотографий.
🟠SVG не всегда поддерживается в старых версиях Android без дополнительных библиотек (например, до Android 5.0, API Level 21).

🚩Практические примеры

Использования PNG:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/logo.png" />


Использования WebP:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/photo.webp" />


Использования SVG: SVG в Android используется через VectorDrawable. Пример vector drawable (res/drawable/ic_logo.xml):
<vector xmlns:android="https://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM17,12l-5,5 -5,-5 1.41,-1.41L11,13.17V7h2v6.17l3.59,-3.58L17,12z"/>
</vector>


Использование VectorDrawable в ImageView:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_logo" />


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
🤔 В Kotlin, какой ключевой элемент позволяет функции возвращать множество значений, используя один возвращаемый объект?
Anonymous Quiz
12%
Array
23%
Data class
38%
Pair/Triple
27%
List
🤔33🤯7
🤔 Что лучше, png или webp?

Выбор между PNG и WebP зависит от конкретных требований вашего проекта, таких как качество изображения, размер файла, поддержка прозрачности и совместимость с различными версиями Android. Вот сравнительный анализ этих форматов:

🚩PNG

Преимущества:
🟠Без потерь (lossless): PNG сохраняет качество изображения без потерь, что делает его идеальным для изображений с высокой детализацией и текстом.
🟠Прозрачность: PNG поддерживает прозрачность (альфа-канал), что полезно для иконок и графических элементов, которые требуют прозрачного фона.
🟠Широкая поддержка: PNG поддерживается всеми версиями Android и всеми браузерами.

Недостатки: Размер файла: PNG файлы могут быть значительно большими по сравнению с WebP, особенно для фотографий и изображений с множеством цветов и градиентов.

🚩WebP

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

Недостатки:
🟠Совместимость: WebP поддерживается начиная с Android 4.0 (API Level 14). В старых версиях Android этот формат не поддерживается.
🟠Качество: Хотя WebP предлагает хорошее качество изображения при меньшем размере файла, в некоторых случаях сжатие с потерями может привести к видимым артефактам.

🚩Когда использовать PNG

🟠Изображения с высокой детализацией: Когда нужно сохранить все детали без компромиссов.
🟠Прозрачность: Для иконок и логотипов, которые требуют прозрачного фона.
🟠Широкая поддержка: Если нужно поддерживать очень старые версии Android или другие платформы, которые не поддерживают WebP.

🚩Когда использовать WebP

🟠Фотографии и сложные изображения: Когда важен меньший размер файла и допустимо некоторое сжатие с потерями.
🟠Оптимизация производительности: Для ускорения загрузки изображений в приложении за счет меньшего размера файлов.
🟠Прозрачность: Когда требуется прозрачность, но при этом нужен меньший размер файла по сравнению с PNG.

Пример использования PNG:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/logo.png" />


Использования WebP:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/photo.webp" />


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14🤔2
🤔 Какой оператор в Kotlin исполняет блок кода и возвращает его значение?
Anonymous Quiz
41%
apply
15%
also
39%
run
5%
repeat
🤔11👍1
🤔 Как сделать polling?

Polling — это техника, при которой приложение периодически отправляет запросы на сервер, чтобы получить обновленные данные. В Android для реализации polling можно использовать различные подходы, такие как использование Handler и Runnable, ScheduledExecutorService, или RxJava. Выбор зависит от требований приложения и предпочтений разработчика.

🚩Подходы для реализации polling

Использование `Handler` и `Runnable`: Этот подход прост в реализации и хорошо подходит для простых задач.
class MainActivity : AppCompatActivity() {

private val pollingHandler = Handler(Looper.getMainLooper())
private val pollingInterval = 5000L // Интервал в миллисекундах (5 секунд)

private val pollingRunnable = object : Runnable {
override fun run() {
// Ваша логика запроса
fetchDataFromServer()

// Запуск polling через указанный интервал
pollingHandler.postDelayed(this, pollingInterval)
}
}

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

// Запуск polling при старте Activity
startPolling()
}

private fun startPolling() {
pollingHandler.post(pollingRunnable)
}

private fun stopPolling() {
pollingHandler.removeCallbacks(pollingRunnable)
}

private fun fetchDataFromServer() {
// Ваша логика запроса на сервер
// Например, использование Retrofit для выполнения сетевого запроса
// и обновление UI с помощью данных из ответа
}

override fun onDestroy() {
super.onDestroy()
// Остановка polling при уничтожении Activity
stopPolling()
}
}


Использование `ScheduledExecutorService`: Этот подход более гибкий и позволяет выполнять задачи в фоновом потоке.
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.TimeUnit

class MainActivity : AppCompatActivity() {

private val scheduler: ScheduledExecutorService = Executors.newScheduledThreadPool(1)
private val pollingInterval = 5L // Интервал в секундах

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

// Запуск polling при старте Activity
startPolling()
}

private fun startPolling() {
scheduler.scheduleAtFixedRate({
// Ваша логика запроса
fetchDataFromServer()
}, 0, pollingInterval, TimeUnit.SECONDS)
}

private fun stopPolling() {
scheduler.shutdown()
}

private fun fetchDataFromServer() {
// Ваша логика запроса на сервер
// Например, использование Retrofit для выполнения сетевого запроса
// и обновление UI с помощью данных из ответа
}

override fun onDestroy() {
super.onDestroy()
// Остановка polling при уничтожении Activity
stopPolling()
}
}


Использование RxJava: RxJava предоставляет мощные операторы для управления асинхронными операциями, что делает его отличным выбором для реализации polling.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17🔥21
🤔 Какой ключевой элемент в Kotlin позволяет выполнить блок кода только для ненулевых значений?
Anonymous Quiz
10%
checkNotNull
24%
requireNotNull
55%
let
10%
notNull
🤯10👍1🤔1
🤔 Как сделать кэш?

Создание кэша в Android приложении помогает улучшить производительность и уменьшить количество сетевых запросов, сохраняя данные локально для быстрого доступа. В зависимости от типа данных и потребностей приложения, вы можете использовать различные методы для кэширования, такие как SharedPreferences, SQLite, Room, файлы, и библиотеки кэширования (например, Glide для изображений).

SharedPreferences подходит для сохранения небольших объемов данных, таких как настройки или кэшированные ответы от API.
// Сохранение данных в SharedPreferences
fun saveDataToCache(context: Context, key: String, value: String) {
val sharedPreferences = context.getSharedPreferences("app_cache", Context.MODE_PRIVATE)
val editor = sharedPreferences.edit()
editor.putString(key, value)
editor.apply()
}

// Получение данных из SharedPreferences
fun getDataFromCache(context: Context, key: String): String? {
val sharedPreferences = context.getSharedPreferences("app_cache", Context.MODE_PRIVATE)
return sharedPreferences.getString(key, null)
}


Room — это библиотека для работы с базой данных SQLite, которая упрощает создание и использование базы данных в Android приложениях.

Создание Entity:
@Entity(tableName = "users")
data class User(
@PrimaryKey val id: Int,
val name: String,
val email: String
)


Создание DAO:
@Dao
interface UserDao {
@Query("SELECT * FROM users WHERE id = :userId")
suspend fun getUserById(userId: Int): User?

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertUser(user: User)
}


Создание Database:
@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}


Использование базы данных:
class UserRepository(context: Context) {
private val db = Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java, "app_database"
).build()

suspend fun getUser(userId: Int): User? {
return db.userDao().getUserById(userId)
}

suspend fun saveUser(user: User) {
db.userDao().insertUser(user)
}
}


Glide — это мощная библиотека для загрузки и кэширования изображений.
// Загрузка и кэширование изображения с использованием Glide
Glide.with(context)
.load("https://example.com/image.jpg")
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(imageView)


Retrofit можно настроить для работы с OkHttp, чтобы кэшировать сетевые запросы.
val cacheSize = 10 * 1024 * 1024 // 10 MB
val cache = Cache(context.cacheDir, cacheSize)

val okHttpClient = OkHttpClient.Builder()
.cache(cache)
.addInterceptor { chain ->
var request = chain.request()
request = if (hasNetwork(context))
request.newBuilder().header("Cache-Control", "public, max-age=" + 5).build()
else
request.newBuilder().header("Cache-Control", "public, only-if-cached, max-stale=" + 60 * 60 * 24 * 7).build()
chain.proceed(request)
}
.build()


Настройка Retrofit с OkHttpClient:
val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build()


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍20
🤔 В Kotlin, какой оператор используется для безопасного вызова функции на объекте, который может быть `null`?
Anonymous Quiz
13%
`?:`
61%
`?.`
3%
`!!`
22%
`?.let`
🤔 Какие могут быть проблемы с элементами списка?

Проблемы с элементами списка в Android-приложениях могут быть разнообразными. Давайте рассмотрим некоторые из наиболее распространённых проблем и способы их решения.

🚩 Переполнение памяти (Out of Memory)

🟠Почему это происходит: Списки с большим количеством элементов, особенно если элементы содержат изображения или другие ресурсоемкие данные, могут вызывать переполнение памяти.
🟠Решение: Использовать RecyclerView вместо ListView. RecyclerView более эффективно управляет памятью за счет повторного использования представлений. Кроме того, стоит использовать библиотеки для загрузки изображений, такие как Glide или Picasso, которые обеспечивают кэширование и оптимизацию памяти
// Пример использования Glide для загрузки изображений
Glide.with(context)
.load(imageUrl)
.into(imageView)


🚩Медленная прокрутка (Lagging)

🟠Почему это происходит: Прокрутка может быть медленной, если элементы списка отрисовываются или загружаются слишком долго.
🟠Решение: Оптимизировать адаптер списка. Использовать ViewHolder паттерн, чтобы избежать ненужных вызовов findViewById. Также стоит выполнять тяжелые операции, такие как загрузка изображений, асинхронно.
   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
}


🚩Неправильное отображение данных (Data Inconsistency)

🟠Почему это происходит: Если адаптер списка неправильно управляет обновлением данных, элементы могут отображать неправильные или устаревшие данные.
🟠Решение: Обеспечить корректное обновление данных в адаптере и использовать DiffUtil для вычисления изменений в данных и обновления только необходимых элементов.
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)


🚩Многопоточность (Concurrency Issues)

🟠Почему это происходит: Если обновление данных списка происходит из разных потоков без должной синхронизации, это может привести к ошибкам.
🟠Решение: Обеспечить синхронизацию обновлений данных. Использовать подходы, такие как LiveData или Flow из библиотеки Jetpack, чтобы обновления происходили в главном потоке.
val liveData = MutableLiveData<List<Item>>()

liveData.observe(viewLifecycleOwner, Observer { items ->
myAdapter.submitList(items)
})


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