Kotlin | Вопросы собесов
2.57K subscribers
27 photos
957 links
Download Telegram
🤔 Вопрос: Какое ключевое слово используется для создания асинхронной функции в 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
🤔 Какой тип возвращает функция, объявленная с ключевым словом suspend?
Anonymous Quiz
18%
Unit
11%
Any
19%
Coroutine
53%
Любой тип
🤔 Как можно реализовать поведение view при ее добавлении в дерево?

Для реализации поведения View при её добавлении в дерево View в Android, можно воспользоваться несколькими подходами. Один из наиболее удобных способов — использование метода View.onAttachedToWindow(), который вызывается, когда View добавляется в окно. Этот метод позволяет выполнять какие-либо действия, когда View становится видимой для пользователя.

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

Создайте пользовательский класс View и переопределите метод onAttachedToWindow() для выполнения необходимых действий при добавлении View в дерево.

1⃣Создайте свой класс View
import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.View

class CustomView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

override fun onAttachedToWindow() {
super.onAttachedToWindow()
// Действия при добавлении View в дерево
Log.d("CustomView", "View added to the window")
// Дополнительные действия, например, запуск анимации
startAnimation()
}

private fun startAnimation() {
// Реализуйте логику анимации или другие действия
}
}


2⃣Используйте CustomView в вашем макете
<!-- res/layout/activity_main.xml -->
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<com.example.yourapp.CustomView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#FF0000"/>
</RelativeLayout>


🚩Альтернативный способ

Использование ViewTreeObserver.OnGlobalLayoutListener Если вам нужно выполнить действия не только при добавлении View, но и при изменении её размеров или других параметров, можно использовать ViewTreeObserver.OnGlobalLayoutListener.

1⃣Создайте свой класс View
import android.content.Context
import android.util.AttributeSet
import android.view.ViewTreeObserver
import android.widget.TextView

class CustomTextView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : TextView(context, attrs, defStyleAttr) {

init {
viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
// Действия при изменении макета или добавлении View в дерево
viewTreeObserver.removeOnGlobalLayoutListener(this)
performActions()
}
})
}

private fun performActions() {
// Реализуйте необходимые действия
}
}


2⃣Используйте CustomTextView в вашем макете
<!-- res/layout/activity_main.xml -->
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<com.example.yourapp.CustomTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello, World!"
android:background="#00FF00"/>
</RelativeLayout>


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2👾1
🤔 Как в Kotlin определить класс, который не может быть унаследован?
Anonymous Quiz
2%
open class NonInheritable {}
44%
final class NonInheritable {}
45%
class NonInheritable {}
9%
sealed class NonInheritable {}
👀3
🤔 Почему могут пропадать пользовательские данные при повороте экрана?

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

🚩Причины пропадания данных при повороте экрана

🟠Пересоздание активности
🟠Неправильное управление состоянием

🚩Способы предотвращения потери данных

Сохранение состояния с помощью onSaveInstanceState и onRestoreInstanceState
class MainActivity : AppCompatActivity() {

private var userData: String? = null

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

if (savedInstanceState != null) {
userData = savedInstanceState.getString("USER_DATA_KEY")
// Восстановите данные в пользовательском интерфейсе
}
}

override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putString("USER_DATA_KEY", userData)
}

override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState)
userData = savedInstanceState.getString("USER_DATA_KEY")
// Восстановите данные в пользовательском интерфейсе
}
}


Использование Retain Fragment. Этот метод сохраняет данные, используя фрагмент, который сохраняет своё состояние при пересоздании активности.
class RetainFragment : Fragment() {
var userData: String? = null

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
retainInstance = true
}
}

class MainActivity : AppCompatActivity() {

private lateinit var retainFragment: RetainFragment

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

val fragmentManager = supportFragmentManager
retainFragment = fragmentManager.findFragmentByTag("RETAIN_FRAGMENT") as RetainFragment?
?: RetainFragment().also {
fragmentManager.beginTransaction().add(it, "RETAIN_FRAGMENT").commit()
}

// Используйте данные из RetainFragment
val userData = retainFragment.userData
}
}


Использование SavedStateHandle в ViewModel
class UserViewModel(savedStateHandle: SavedStateHandle) : ViewModel() {
var userData: String?
get() = savedStateHandle.get("USER_DATA_KEY")
set(value) = savedStateHandle.set("USER_DATA_KEY", value)
}

class MainActivity : AppCompatActivity() {

private lateinit var viewModel: UserViewModel

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

viewModel = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(UserViewModel::class.java)

// Используйте данные из ViewModel
val userData = viewModel.userData
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🤯2
🤔 Какой из следующих методов используется для преобразования строки в число в Kotlin?
Anonymous Quiz
12%
parseInt()
81%
toInt()
5%
valueOf()
2%
intValue()
👍1🤔1👾1
🤔 В каких случаях может понадобиться вызывать commitAllowingStateLoss?

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

Пользовательская навигация с малой вероятностью возврата
fragmentManager.beginTransaction()
.replace(R.id.container, newFragment)
.commitAllowingStateLoss();


Операции, которые должны быть выполнены немедленно
supportFragmentManager.beginTransaction()
.remove(dialogFragment)
.commitAllowingStateLoss();


Автоматические процессы или системные изменения
supportFragmentManager.beginTransaction()
.add(systemFragment, "SYSTEM_FRAGMENT")
.commitAllowingStateLoss();


Устранение багов при смене конфигурации
supportFragmentManager.beginTransaction()
.replace(R.id.container, newFragment)
.commitAllowingStateLoss();


🚩Как это работает

Когда Android система пересоздаёт активность (например, при повороте экрана), она сохраняет текущее состояние активности и фрагментов. Если транзакция фрагмента выполняется после сохранения состояния, это может привести к ошибке IllegalStateException. Метод commitAllowingStateLoss() позволяет избежать этой ошибки, но с риском потери состояния, так как транзакция будет выполнена без учёта текущего сохраненного состояния.

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

Переход между фрагментами
class MainActivity : AppCompatActivity() {

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

val fragmentManager = supportFragmentManager
val transaction = fragmentManager.beginTransaction()
val newFragment = ExampleFragment()

transaction.replace(R.id.fragment_container, newFragment)
transaction.commitAllowingStateLoss()
}
}


Удаление диалогового фрагмента
class MainActivity : AppCompatActivity() {

override fun onDestroy() {
super.onDestroy()

val dialogFragment = supportFragmentManager.findFragmentByTag("DIALOG_FRAGMENT")
dialogFragment?.let {
supportFragmentManager.beginTransaction()
.remove(it)
.commitAllowingStateLoss()
}
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2👾1
🤔 Какой из следующих типов данных является неизменяемым в Kotlin?
Anonymous Quiz
13%
ArrayList
5%
MutableList
76%
List
7%
HashSet
🤯10👍1
🤔 Как из push открыть нужную Activity или фрагмент?

Чтобы открыть нужную Activity или фрагмент из push-уведомления в Android, необходимо настроить обработку данных из уведомления и создать Intent, который запускает соответствующую Activity или фрагмент.

🚩Процесс реализации

1⃣Настройка Firebase Cloud Messaging (FCM)
Если вы используете FCM для отправки push-уведомлений, добавьте зависимости FCM в build.gradle вашего проекта:
dependencies {
implementation 'com.google.firebase:firebase-messaging:23.0.6'
}


2⃣Создание сервиса для обработки уведомлений
Создайте класс, который наследуется от FirebaseMessagingService, чтобы обрабатывать входящие уведомления.
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import android.app.PendingIntent
import android.content.Intent
import android.util.Log

class MyFirebaseMessagingService : FirebaseMessagingService() {

override fun onMessageReceived(remoteMessage: RemoteMessage) {
super.onMessageReceived(remoteMessage)

// Обработка данных из уведомления
val data = remoteMessage.data
val action = data["action"]

val intent = Intent(this, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
putExtra("action", action)
}

val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)

// Создание и отображение уведомления (настройте NotificationCompat.Builder по вашему усмотрению)
val notificationBuilder = NotificationCompat.Builder(this, "default_channel")
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle("Notification Title")
.setContentText("Notification Message")
.setContentIntent(pendingIntent)
.setAutoCancel(true)

val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
notificationManager.notify(0, notificationBuilder.build())
}
}


3⃣Регистрация сервиса в манифесте
Добавьте сервис в файл AndroidManifest.xml:
<service
android:name=".MyFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>

<application>
...
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="default_channel" />
</application>


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