Kotlin | Вопросы собесов
2.57K subscribers
28 photos
959 links
Download Telegram
🤔 В 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
🤔 Вопрос: Какое ключевое слово используется для создания асинхронной функции в Kotlin?
Anonymous Quiz
22%
async
2%
await
76%
suspend
0%
future
🤔 Какие основные причины торможения UI?

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

🟠Тяжелые операции в главном потоке
Почему это происходит: Главный поток отвечает за отрисовку UI и обработку пользовательских взаимодействий. Если в нём выполняются длительные операции, такие как сетевые запросы или доступ к базе данных, это приводит к задержкам и подвисаниям интерфейса.
Решение: Выполнять тяжелые операции в фоновом потоке, используя AsyncTask, Handler, Thread, или современные решения, такие как Kotlin Coroutines или WorkManager.
// Пример использования Kotlin Coroutines для выполнения операции в фоне
CoroutineScope(Dispatchers.IO).launch {
// Выполнение фоновой операции
val result = someHeavyOperation()
withContext(Dispatchers.Main) {
// Обновление UI после завершения фоновой операции
updateUI(result)
}
}


🟠Неоптимизированные макеты (layouts)
Почему это происходит: Сложные макеты с глубокими уровнями вложенности или чрезмерным количеством элементов могут замедлять отрисовку интерфейса.
Решение: Использовать более простые и плоские макеты. Рассмотреть использование ConstraintLayout, который позволяет создавать сложные макеты с минимальной вложенностью.
<!-- Пример использования ConstraintLayout вместо вложенных LinearLayout -->
<ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
android:id="@+id/textView"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:text="Hello World!" />

</ConstraintLayout>


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


🟠Частое обновление UI
Почему это происходит: Частое обновление элементов интерфейса, особенно внутри циклов или таймеров, может перегружать главный поток.
Решение: Минимизировать количество обновлений UI. Объединять изменения и обновлять UI только при необходимости.
// Пример обновления UI только при изменении данных
fun updateData(newData: List<Item>) {
if (data != newData) {
data = newData
notifyDataSetChanged()
}
}


🟠Неоптимизированные анимации
Почему это происходит: Использование сложных или многочисленных анимаций без оптимизации может замедлить работу UI.
Решение: Использовать ViewPropertyAnimator или TransitionManager для более плавных анимаций. Ограничить количество одновременно выполняемых анимаций.
// Пример использования ViewPropertyAnimator для плавной анимации
imageView.animate()
.translationX(100f)
.setDuration(300)
.start()


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
🤔 Вопрос: Как в Kotlin можно объявить переменную, значение которой известно компилятору во время компиляции и не изменяется во время выполнения?
Anonymous Quiz
28%
Используя ключевое слово `val`
2%
Используя ключевое слово `var`
66%
Используя ключевое слово `const`
3%
Используя ключевое слово `static`
🤔 Как можно исправить плохой layout элемента?

🟠Уменьшите вложенность макетов
Глубокая вложенность макетов приводит к большому количеству вычислений при отрисовке. Использование более плоской структуры макетов может значительно улучшить производительность.

🟠Используйте `ViewStub` для редко используемых элементов
ViewStub - это невидимый и легковесный элемент, который можно использовать для элементов, которые отображаются нечасто.
<ViewStub
android:id="@+id/viewStub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="@layout/your_layout" />


🟠Используйте `merge` для сокращения уровней вложенности
Если у вас есть включаемые макеты (include), использование merge может помочь уменьшить количество уровней.
Вместо:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

<include layout="@layout/your_layout"/>
</LinearLayout>


Используйте: your_layout.xml:
<merge xmlns:android="https://schemas.android.com/apk/res/android">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Label" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Value" />
</merge>


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

🟠Профилируйте макеты с помощью инструментов
Используйте инструменты, такие как Layout Inspector и Profile GPU Rendering, для анализа и оптимизации производительности ваших макетов.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
🤔 Какая функция Kotlin используется для объединения двух коллекций?
Anonymous Quiz
32%
merge
21%
join
16%
concat
30%
zip
🤔 Как определить изменение скорости работы программы после наших действий?

🟠Profile GPU Rendering
Этот инструмент показывает время, затраченное на отрисовку каждого кадра. Использование этого инструмента позволяет выявить "тяжелые" кадры и измерить улучшения после оптимизации.

1⃣Включите режим разработчика на устройстве.
2⃣Перейдите в "Настройки" -> "Для разработчиков".
3⃣Включите опцию "Profile GPU Rendering" и выберите "On screen as bars".
4⃣Запустите ваше приложение и наблюдайте за графиками. Зеленые линии указывают на время отрисовки, и ваша цель - оставаться ниже 16 мс (для 60 кадров в секунду).

🟠Android Profiler
Предоставляет набор инструментов для анализа производительности приложения.

1⃣ Откройте Android Studio и запустите ваше приложение.
2⃣Перейдите в "View" -> "Tool Windows" -> "Profiler".
3⃣Выберите ваше устройство и запущенное приложение.
4⃣Используйте вкладки CPU, Memory, Network и Energy для анализа различных аспектов производительности.
5⃣Сравните данные до и после оптимизации.

🟠Benchmarking
Создание и использование тестов производительности помогает количественно оценить улучшения. Вы можете использовать библиотеку Jetpack Benchmark для создания и выполнения тестов производительности.

🚩Пример использования Jetpack Benchmark:

1⃣Добавьте зависимости в build.gradle:
dependencies {
androidTestImplementation "androidx.benchmark:benchmark-junit4:1.1.0"
androidTestImplementation "androidx.test:runner:1.3.0"
androidTestImplementation "androidx.test:rules:1.3.0"
}


2⃣Создайте класс теста:
import androidx.benchmark.junit4.BenchmarkRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class ExampleBenchmark {
@get:Rule
val benchmarkRule = BenchmarkRule()

@Test
fun myFunctionBenchmark() {
benchmarkRule.measureRepeated {
// Вызов вашей функции или кода для тестирования производительности
myFunction()
}
}
}


🟠Logcat
Используйте журналирование для измерения времени выполнения определенных операций.
val startTime = System.currentTimeMillis()
// Ваш код
val endTime = System.currentTimeMillis()
Log.d("Performance", "Время выполнения: ${endTime - startTime} мс")


🟠StrictMode
StrictMode помогает обнаружить операции, которые могут замедлить работу приложения, такие как работа с сетью или базой данных в главном потоке.
if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.build()
)
StrictMode.setVmPolicy(
StrictMode.VmPolicy.Builder()
.detectAll()
.penaltyLog()
.build()
)
}


🟠Systrace
Systrace позволяет собирать и анализировать трассировки производительности системы, предоставляя детализированные данные о времени выполнения различных операций.

1⃣Включите режим разработчика на устройстве.
2⃣В "Настройки" -> "Для разработчиков" включите "Enable GPU Debug Layers".
3⃣Запустите команду adb shell am broadcast -a com.android.systemui.screenshot.ScreenshotService.ACTION_SYSTRACE.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12
🤔 Вопрос: Как в Kotlin привести переменную типа `Any` к типу `String` безопасно, чтобы избежать исключения?
Anonymous Quiz
12%
as String
2%
(String) variable
56%
variable as? String
30%
variable.toString()
🤔 Какое API или другие инструменты будешь использовать для отправления файлов на сервер?

Для отправки файлов на сервер в Android-приложении можно использовать несколько API и библиотек, в зависимости от ваших требований. Наиболее популярные и удобные решения включают использование HttpURLConnection, OkHttp, и Retrofit. Ниже я подробно расскажу о каждом из них и приведу примеры.

🟠Использование HttpURLConnection
HttpURLConnection — это встроенный инструмент в Android для выполнения HTTP-запросов, включая загрузку файлов.
fun uploadFileToServer(url: String, file: File) {
val boundary = "===" + System.currentTimeMillis() + "==="
val LINE_FEED = "\r\n"

val connection = URL(url).openConnection() as HttpURLConnection
connection.requestMethod = "POST"
connection.doOutput = true
connection.doInput = true
connection.useCaches = false
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=$boundary")

val outputStream = connection.outputStream
val writer = PrintWriter(OutputStreamWriter(outputStream, "UTF-8"), true)

// Добавление файла
writer.append("--$boundary").append(LINE_FEED)
writer.append("Content-Disposition: form-data; name=\"file\"; filename=\"${file.name}\"").append(LINE_FEED)
writer.append("Content-Type: ${URLConnection.guessContentTypeFromName(file.name)}").append(LINE_FEED)
writer.append("Content-Transfer-Encoding: binary").append(LINE_FEED)
writer.append(LINE_FEED).flush()

val inputStream = FileInputStream(file)
inputStream.copyTo(outputStream, 4096)
outputStream.flush()
inputStream.close()

writer.append(LINE_FEED).flush()
writer.append("--$boundary--").append(LINE_FEED)
writer.close()

val responseCode = connection.responseCode
if (responseCode == HttpURLConnection.HTTP_OK) {
// Успешная загрузка
} else {
// Ошибка загрузки
}
}


🟠Использование OkHttp
OkHttp — это популярная и мощная библиотека для выполнения HTTP-запросов, которая значительно упрощает процесс отправки файлов на сервер.
fun uploadFileWithRetrofit(file: File) {
val requestBody = file.asRequestBody("application/octet-stream".toMediaTypeOrNull())
val multipartBody = MultipartBody.Part.createFormData("file", file.name, requestBody)

val call = apiService.uploadFile(multipartBody)
call.enqueue(object : Callback<ResponseBody> {
override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
// Ошибка
}

override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
if (response.isSuccessful) {
// Успешная загрузка
} else {
// Ошибка загрузки
}
}
})
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
🤔 Какой тип наследования по умолчанию используется для классов в Kotlin?
Anonymous Quiz
3%
sealed
4%
abstract
32%
open
61%
final
🤔 Как реализовать редактор фотографий в качестве отдельного компонента?

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

1⃣Создание пользовательского интерфейса
<!-- res/layout/activity_photo_editor.xml -->
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<ImageView
android:id="@+id/photo_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerInside" />

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="bottom"
android:layout_alignParentBottom="true"
android:background="#AA000000">

<Button
android:id="@+id/btn_rotate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Rotate" />

<Button
android:id="@+id/btn_crop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Crop" />

<Button
android:id="@+id/btn_filter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Filter" />
</LinearLayout>
</RelativeLayout>


2⃣Обработка изображений
Для обработки изображений можно использовать библиотеки, такие как Bitmap и Canvas, а также сторонние библиотеки, такие как GPUImage или Glide. Вот пример использования Bitmap и Canvas для базовых операций:
// PhotoEditor.kt
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Matrix

class PhotoEditor {

fun rotateBitmap(bitmap: Bitmap, degrees: Float): Bitmap {
val matrix = Matrix()
matrix.postRotate(degrees)
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
}

fun applyFilter(bitmap: Bitmap, filter: ColorMatrixColorFilter): Bitmap {
val filteredBitmap = Bitmap.createBitmap(bitmap.width, bitmap.height, bitmap.config)
val canvas = Canvas(filteredBitmap)
val paint = Paint()
paint.colorFilter = filter
canvas.drawBitmap(bitmap, 0f, 0f, paint)
return filteredBitmap
}
}


3⃣Интеграция компонента
Создайте Activity или Fragment, который будет использовать ваш редактор фотографий. В этом примере будем использовать Activity:

4⃣Обработка разных функций редактирования
Для более сложных функций, таких как обрезка или использование фильтров, можно интегрировать специализированные библиотеки:
GPUImage: для применения фильтров на основе OpenGL.
PhotoView: для простого масштабирования и перемещения изображений.
Ucrop: для обрезки изображений.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4😁2👀21
🤔 Какой из следующих типов данных используется для представления 64-битного целого числа в Kotlin?
Anonymous Quiz
16%
Int
75%
Long
4%
Short
4%
Byte
🤔 Какие есть механизмы для отмены запросов presenter у view?

В архитектуре MVP (Model-View-Presenter), когда Presenter отправляет запросы к View, важно иметь возможность отменять эти запросы. Это может быть полезно в различных ситуациях, таких как изменение состояния активности, смена ориентации экрана или отмена долгих операций.

🟠Использование CompositeDisposable из RxJava
Если вы используете RxJava для асинхронных операций, CompositeDisposable позволяет управлять множеством подписок и отменять их все сразу.
class MyPresenter {
private val disposables = CompositeDisposable()

fun loadData() {
val disposable = myApi.getData()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ data -> view.showData(data) },
{ error -> view.showError(error) }
)
disposables.add(disposable)
}

fun onDestroy() {
disposables.clear() // Отменяем все активные подписки
}
}


🟠Использование CoroutineScope и Job в Kotlin Coroutines
class MyPresenter(private val view: MyView) {
private val presenterJob = Job()
private val uiScope = CoroutineScope(Dispatchers.Main + presenterJob)

fun loadData() {
uiScope.launch {
try {
val data = withContext(Dispatchers.IO) { myApi.getData() }
view.showData(data)
} catch (e: Exception) {
view.showError(e)
}
}
}

fun onDestroy() {
presenterJob.cancel() // Отменяем все запущенные корутины
}
}


🟠Использование Call.cancel() с Retrofit
class MyPresenter(private val view: MyView, private val apiService: ApiService) {
private var call: Call<Data>? = null

fun loadData() {
call = apiService.getData()
call?.enqueue(object : Callback<Data> {
override fun onResponse(call: Call<Data>, response: Response<Data>) {
if (response.isSuccessful) {
view.showData(response.body())
} else {
view.showError(Throwable("Error: ${response.code()}"))
}
}

override fun onFailure(call: Call<Data>, t: Throwable) {
view.showError(t)
}
})
}

fun onDestroy() {
call?.cancel() // Отменяем запрос
}
}


🟠Использование собственных коллбеков и флагов
class MyPresenter(private val view: MyView) {
private var isCancelled = false

fun loadData() {
isCancelled = false
myApi.getData(object : MyCallback<Data> {
override fun onSuccess(data: Data) {
if (!isCancelled) {
view.showData(data)
}
}

override fun onError(error: Throwable) {
if (!isCancelled) {
view.showError(error)
}
}
})
}

fun onDestroy() {
isCancelled = true // Устанавливаем флаг отмены
}
}


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