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
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍1🤯1
Корутины позволяют писать асинхронный код, который выглядит и читается как синхронный. Это упрощает понимание и сопровождение кода.
suspend fun fetchData(): String {
val data = networkRequest() // Выглядит как обычный синхронный вызов
return processData(data)
}
fun main() = runBlocking {
val result = fetchData()
println(result)
}Observable<String> fetchData() {
return networkRequest()
.map(data -> processData(data));
}
fetchData()
.subscribe(result -> System.out.println(result));Корутины интегрированы с контекстами (например,
Dispatchers), что позволяет легко переключаться между потоками и управлять жизненным циклом.withContext(Dispatchers.IO) {
val data = networkRequest()
withContext(Dispatchers.Main) {
updateUI(data)
}
}networkRequest()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(data -> updateUI(data));
Корутины предоставляют простой и мощный механизм для отмены выполнения, что делает их удобными для задач, которые могут быть прерваны.
val job = launch {
val data = networkRequest()
updateUI(data)
}
// Отмена выполнения
job.cancel()Disposable disposable = networkRequest()
.subscribe(data -> updateUI(data));
// Отмена выполнения
disposable.dispose()
Корутины, как правило, имеют меньше накладных расходов по сравнению с RxJava, поскольку они не создают объекты для каждого оператора и события.
Корутины являются встроенной функцией языка Kotlin, что обеспечивает лучшую интеграцию и поддержку на уровне компилятора.
Корутины обеспечивают встроенные механизмы для работы с потоками, такие как
Mutex, Channel и Flow, что упрощает написание потокобезопасного кода.val mutex = Mutex()
suspend fun safeUpdate() {
mutex.withLock {
// Критическая секция
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11❤1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥5
Intent – это механизм в Android, который используется для связи между компонентами приложения (Activity, Service, BroadcastReceiver) или для связи между различными приложениями. Он позволяет запускать новые активности, сервисы, отправлять широковещательные сообщения и передавать данные между компонентами.
Intent используется для запуска новых экранов (Activity), фоновых процессов (Service) и широковещательных сообщений (BroadcastReceiver).
Intent позволяет передавать данные между компонентами, что упрощает обмен информацией.
С помощью Intent можно запускать активности и сервисы других приложений, что позволяет интегрировать функционал различных приложений.
Используется для запуска конкретного компонента внутри приложения. Здесь явно указывается компонент, который должен быть запущен.
Intent intent = new Intent(this, TargetActivity.class);
startActivity(intent);
Используется для выполнения действий, которые могут быть выполнены несколькими приложениями. В данном случае система Android определяет, какое приложение лучше всего подходит для выполнения действия.
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://www.example.com"));
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
Запуск новой Activity:
Intent intent = new Intent(this, NewActivity.class);
startActivity(intent);
Запуск Service:
Intent intent = new Intent(this, MyService.class);
startService(intent);
Отправка данных:
Intent intent = new Intent(this, TargetActivity.class);
intent.putExtra("KEY_NAME", "value");
startActivity(intent);
Отправка широковещательного сообщения:
Intent intent = new Intent("com.example.CUSTOM_INTENT");
sendBroadcast(intent);Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥2
Подход Single Activity означает использование одной основной активности (
Activity) на весь жизненный цикл приложения, в рамках которой все пользовательские интерфейсы представлены фрагментами (Fragment). Этот подход отличается от более традиционного подхода с использованием множества активностей, где каждый экран приложения представлен отдельной активностью.Меньшее количество активностей означает меньше затрат на циклы жизни активностей и смену контекстов, что может улучшить производительность приложения и управление памятью.
Управление всеми фрагментами в рамках одной активности может упростить коммуникацию между различными частями пользовательского интерфейса и сделать архитектуру приложения более простой и понятной.
Навигация между экранами становится более контролируемой и удобной, особенно при использовании
NavController из Android Jetpack, который оптимизирован для работы в рамках Single Activity.Сохранение и восстановление состояния приложения может быть более управляемым, так как вся информация о состоянии хранится и обрабатывается в одном месте.
Управление множеством фрагментов, их стеками и переходами может стать более сложным и запутанным, особенно в больших и сложных приложениях.
Хотя уменьшение количества активностей может повысить производительность, управление большим количеством фрагментов и их состояниями может, напротив, ухудшить производительность, если это не контролируется должным образом.
Тестирование приложения, где все фрагменты управляются одной активностью, может быть более сложным, так как каждый тестовый сценарий должен учитывать состояние всей активности и всех активных фрагментов.
Фрагменты должны тщательно управлять своими жизненными циклами в контексте родительской активности, что может привести к ошибкам в управлении ресурсами, если они не обрабатываются правильно.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6