Глубокая вложенность макетов приводит к большому количеству вычислений при отрисовке. Использование более плоской структуры макетов может значительно улучшить производительность.
ViewStub - это невидимый и легковесный элемент, который можно использовать для элементов, которые отображаются нечасто.<ViewStub
android:id="@+id/viewStub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="@layout/your_layout" />
Если у вас есть включаемые макеты (
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
Anonymous Quiz
32%
merge
21%
join
16%
concat
30%
zip
Этот инструмент показывает время, затраченное на отрисовку каждого кадра. Использование этого инструмента позволяет выявить "тяжелые" кадры и измерить улучшения после оптимизации.
Предоставляет набор инструментов для анализа производительности приложения.
Создание и использование тестов производительности помогает количественно оценить улучшения. Вы можете использовать библиотеку Jetpack Benchmark для создания и выполнения тестов производительности.
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"
}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()
}
}
}
Используйте журналирование для измерения времени выполнения определенных операций.
val startTime = System.currentTimeMillis()
// Ваш код
val endTime = System.currentTimeMillis()
Log.d("Performance", "Время выполнения: ${endTime - startTime} мс")
StrictMode помогает обнаружить операции, которые могут замедлить работу приложения, такие как работа с сетью или базой данных в главном потоке.
if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.build()
)
StrictMode.setVmPolicy(
StrictMode.VmPolicy.Builder()
.detectAll()
.penaltyLog()
.build()
)
}Systrace позволяет собирать и анализировать трассировки производительности системы, предоставляя детализированные данные о времени выполнения различных операций.
adb shell am broadcast -a com.android.systemui.screenshot.ScreenshotService.ACTION_SYSTRACE.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12
Anonymous Quiz
12%
as String
2%
(String) variable
56%
variable as? String
30%
variable.toString()
Для отправки файлов на сервер в Android-приложении можно использовать несколько API и библиотек, в зависимости от ваших требований. Наиболее популярные и удобные решения включают использование
HttpURLConnection, OkHttp, и Retrofit. Ниже я подробно расскажу о каждом из них и приведу примеры.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 — это популярная и мощная библиотека для выполнения 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
Anonymous Quiz
3%
sealed
4%
abstract
32%
open
61%
final
Реализация редактора фотографий в Android как отдельного компонента требует нескольких шагов, включающих создание пользовательского интерфейса для редактирования, обработку изображений, а также возможность интеграции этого компонента в другие части вашего приложения.
<!-- 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>
Для обработки изображений можно использовать библиотеки, такие как
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
}
}
Создайте
Activity или Fragment, который будет использовать ваш редактор фотографий. В этом примере будем использовать Activity:Для более сложных функций, таких как обрезка или использование фильтров, можно интегрировать специализированные библиотеки:
GPUImage: для применения фильтров на основе OpenGL.
PhotoView: для простого масштабирования и перемещения изображений.
Ucrop: для обрезки изображений.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4😁2👀2❤1
Anonymous Quiz
16%
Int
75%
Long
4%
Short
4%
Byte
В архитектуре 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 Coroutinesclass 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() с Retrofitclass 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
Anonymous Quiz
18%
Unit
11%
Any
19%
Coroutine
53%
Любой тип
Для реализации поведения View при её добавлении в дерево View в Android, можно воспользоваться несколькими подходами. Один из наиболее удобных способов — использование метода
View.onAttachedToWindow(), который вызывается, когда View добавляется в окно. Этот метод позволяет выполнять какие-либо действия, когда View становится видимой для пользователя.Создайте пользовательский класс View и переопределите метод
onAttachedToWindow() для выполнения необходимых действий при добавлении 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() {
// Реализуйте логику анимации или другие действия
}
}
<!-- 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.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() {
// Реализуйте необходимые действия
}
}
<!-- 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
Anonymous Quiz
2%
open class NonInheritable {}
44%
final class NonInheritable {}
45%
class NonInheritable {}
9%
sealed class NonInheritable {}
👀3
Пропадание пользовательских данных при повороте экрана в Android-приложениях является распространенной проблемой, связанной с тем, как Android управляет жизненным циклом активности. Когда устройство поворачивается, система уничтожает текущую активность и создает её заново, что приводит к потере данных, если они не были сохранены должным образом.
Сохранение состояния с помощью
onSaveInstanceState и onRestoreInstanceStateclass 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 в ViewModelclass 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
Anonymous Quiz
12%
parseInt()
81%
toInt()
5%
valueOf()
2%
intValue()
👍1🤔1👾1
Метод
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
Anonymous Quiz
13%
ArrayList
5%
MutableList
76%
List
7%
HashSet
🤯10👍1
Чтобы открыть нужную Activity или фрагмент из push-уведомления в Android, необходимо настроить обработку данных из уведомления и создать Intent, который запускает соответствующую Activity или фрагмент.
Если вы используете FCM для отправки push-уведомлений, добавьте зависимости FCM в
build.gradle вашего проекта:dependencies {
implementation 'com.google.firebase:firebase-messaging:23.0.6'
}Создайте класс, который наследуется от
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())
}
}
Добавьте сервис в файл
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
👍9❤1
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15🔥1
Чтобы одновременно отобразить два одинаковых фрагмента на одном экране в Android-приложении, вам нужно добавить два экземпляра фрагмента в разные контейнеры в макете активности. В этом случае каждый фрагмент будет работать независимо, даже если они используют один и тот же класс.
Который будет содержать два контейнера для фрагментов. Обычно это делается с помощью
FrameLayout или LinearLayout.<!-- res/layout/activity_main.xml -->
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="@+id/fragment_container_1"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<FrameLayout
android:id="@+id/fragment_container_2"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
Класс фрагмента, который будет использоваться для отображения обоих экземпляров.
class MyFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Замените fragment_my на свой макет фрагмента
return inflater.inflate(R.layout.fragment_my, container, false)
}
companion object {
fun newInstance(): MyFragment {
return MyFragment()
}
}
}Теперь добавьте два экземпляра фрагмента в вашу активность.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container_1, MyFragment.newInstance())
.commit()
supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container_2, MyFragment.newInstance())
.commit()
}
}
}Это может быть любой макет, который вы хотите использовать.
<!-- res/layout/fragment_my.xml -->
<FrameLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Здесь добавьте элементы вашего фрагмента -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello, I am a fragment!"
android:layout_gravity="center" />
</FrameLayout>
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥1
Корутины и RxJava не стоит использовать, если асинхронность не даёт преимуществ, а код становится сложнее, например, для простых и быстрых задач или в проектах с ограниченными ресурсами.
Если задача достаточно проста и не требует сложного асинхронного управления, использование корутин может добавить ненужную сложность. Простое чтение файла или выполнение небольшого сетевого запроса.
Если команда разработчиков не имеет достаточного опыта работы с корутинами, это может привести к ошибкам и трудностям в отладке. Новая команда, которая только начинает изучать корутины.
Для задач, которые требуют низкоуровневого управления потоками или высокопроизводительных вычислений, корутины могут не подходить. Реализация собственного планировщика потоков или системы для управления реальными временными задачами.
RxJava добавляет уровень абстракции, который может быть избыточным для простых задач. Обработка одного или двух простых асинхронных событий.
RxJava может добавлять накладные расходы на производительность из-за создания большого количества объектов и обработки событий. Высокочастотные события, такие как обработка пользовательского ввода в реальном времени.
RxJava может быть трудно отлаживать и сопровождать из-за сложности потоков данных и операторов. Сложные цепочки операторов, которые трудно тестировать и отслеживать.
Если команда небольшая и не имеет достаточного опыта работы с функциональным программированием, использование RxJava может привести к проблемам в поддержке кода. Стартап с небольшой командой, где нет возможности инвестировать много времени в изучение RxJava.
Предположим, что у вас есть простое приложение, которое выполняет один сетевой запрос при запуске и показывает результат на экране. Использование корутин здесь может добавить ненужную сложность.
fun fetchData() {
// Простой сетевой запрос без использования корутин
val result = simpleNetworkRequest()
displayResult(result)
}Предположим, что у вас есть простое приложение, которое просто считывает данные из базы данных и отображает их. Использование RxJava здесь может быть избыточным.
public void loadData() {
// Простой запрос к базе данных без использования RxJava
List<Data> data = database.queryData();
displayData(data);
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔5👍3❤1🤯1