Управляет данными UI с учётом жизненного цикла.
class MyViewModel : ViewModel() {
val data: MutableLiveData<String> = MutableLiveData()
}Наблюдаемые данные, автоматически обновляющиеся при изменениях.
val data: LiveData<String> = viewModel.data
data.observe(this, Observer { value ->
// Обновление UI
})
Работа с базой данных SQLite.
@Entity
data class User(@PrimaryKey val uid: Int, val firstName: String?, val lastName: String?)
@Dao
interface UserDao {
@Query("SELECT * FROM user")
fun getAll(): List<User>
@Insert
fun insertAll(vararg users: User)
}
@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
Управление фоновыми задачами.
val uploadWorkRequest: WorkRequest = OneTimeWorkRequestBuilder<UploadWorker>().build()
WorkManager.getInstance(context).enqueue(uploadWorkRequest)
Привязка данных к элементам UI.
<layout xmlns:android="https://schemas.android.com/apk/res/android">
<data>
<variable name="viewModel" type="com.example.MyViewModel" />
</data>
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{viewModel.data}" />
</LinearLayout>
</layout>
Постраничная загрузка данных.
val pager = Pager(PagingConfig(pageSize = 20)) {
UserPagingSource()
}.flow.cachedIn(viewModelScope) Навигация между компонентами приложения.
<fragment
android:id="@+id/firstFragment"
android:name="com.example.FirstFragment">
<action
android:id="@+id/action_firstFragment_to_secondFragment"
app:destination="@id/secondFragment" />
</fragment>
Современное хранилище данных.
val dataStore: DataStore<Preferences> = context.createDataStore(name = "settings")
val exampleCounter = dataStore.data.map { preferences -> preferences[EXAMPLE_COUNTER] ?: 0 }
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8👍3
Это библиотека в Android, которая позволяет связывать компоненты пользовательского интерфейса (UI) напрямую с источниками данных, снижая количество шаблонного кода.
Добавьте в файл
build.gradle модуляandroid {
...
viewBinding {
enabled = true
}
}В макете XML добавьте корневой элемент
<layout> и определите переменные данных:<!-- res/layout/activity_main.xml -->
<layout xmlns:android="https://schemas.android.com/apk/res/android">
<data>
<variable
name="viewModel"
type="com.example.MyViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{viewModel.text}" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{() -> viewModel.onButtonClick()}"
android:text="Click Me" />
</LinearLayout>
</layout>
Создайте ViewModel для управления данными:
// MyViewModel.kt
package com.example
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class MyViewModel : ViewModel() {
private val _text = MutableLiveData("Hello, Data Binding!")
val text: LiveData<String> get() = _text
fun onButtonClick() {
_text.value = "Button Clicked!"
}
}
Инициализируйте Data Binding в вашей Activity и свяжите ViewModel с макетом:
// MainActivity.kt
package com.example
import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import com.example.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private val viewModel: MyViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.lifecycleOwner = this
binding.viewModel = viewModel
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥2
Библиотека Lifecycle в Android Jetpack помогает управлять и контролировать жизненный цикл компонентов Android, таких как Activities и Fragments. Она упрощает создание компонентов, которые осведомлены о своем жизненном цикле и могут корректно реагировать на изменения в нем. Это позволяет избегать утечек памяти и некорректной работы компонентов при изменении конфигураций или переходах между состояниями.
Это интерфейс, который определяет класс как владеющий жизненным циклом. Activity и Fragment уже реализуют этот интерфейс.
class MyActivity : AppCompatActivity(), LifecycleOwner {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}Это интерфейс, который позволяет классу наблюдать за изменениями в жизненном цикле компонента. Методы, аннотированные
@OnLifecycleEvent, будут вызываться при соответствующих событиях жизненного цикла.class MyObserver : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onStart() {
// Код, который выполняется при старте жизненного цикла
Log.d("MyObserver", "onStart called")
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onStop() {
// Код, который выполняется при остановке жизненного цикла
Log.d("MyObserver", "onStop called")
}
}Это класс, который содержит информацию о текущем состоянии и позволяет другим объектам наблюдать за изменениями в жизненном цикле.
class MyActivity : AppCompatActivity() {
private lateinit var myObserver: MyObserver
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
myObserver = MyObserver()
lifecycle.addObserver(myObserver)
}
}dependencies {
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
}class MyObserver : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun onResume() {
Log.d("MyObserver", "Activity resumed")
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun onPause() {
Log.d("MyObserver", "Activity paused")
}
}class MyActivity : AppCompatActivity() {
private lateinit var myObserver: MyObserver
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
myObserver = MyObserver()
lifecycle.addObserver(myObserver)
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11👍5
Автоматически управлять изменениями состояния компонентов.
Удалять ненужные ссылки на объекты при уничтожении Activity или Fragment.
Разделить код на логические модули и облегчить тестирование.
Интеграция с LiveData и ViewModel для реактивного подхода.
Уменьшить количество ручного кода для управления состояниями.
Без Lifecycle
public class MyActivity extends AppCompatActivity {
private MyAsyncTask myTask;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myTask = new MyAsyncTask();
myTask.execute();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (myTask != null) {
myTask.cancel(true);
}
}
private static class MyAsyncTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... voids) {
return null;
}
}
}С Lifecycle
public class MyActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getLifecycle().addObserver(new MyLifecycleObserver());
}
public class MyLifecycleObserver implements LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onStart() {
// Код запуска задач
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onStop() {
// Код остановки задач
}
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2😁2
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥1
Архитектура и дизайн: Определение архитектуры проекта и разработка технического дизайна.
Код-ревью: Проверка кода команды для обеспечения качества и соответствия стандартам.
Технические решения: Принятие ключевых решений по технологиям, инструментам и методам разработки.
Наставничество и обучение: Поддержка и обучение членов команды, проведение тренингов и воркшопов.
Оценка производительности: Оценка работы команды, предоставление обратной связи и помощь в профессиональном развитии.
Мотивация: Поддержание мотивации и хорошей рабочей атмосферы в команде.
Планирование и приоритизация: Определение приоритетов задач, планирование релизов и распределение ресурсов.
Управление сроками: Обеспечение выполнения проектов в срок, контроль за соблюдением дедлайнов.
Коммуникация с заинтересованными сторонами: Взаимодействие с клиентами, менеджерами проектов и другими заинтересованными сторонами для согласования требований и сроков.
Внедрение лучших практик: Обеспечение использования лучших практик разработки, таких как CI/CD, тестирование, кодирование и документирование.
Управление версиями: Контроль за версионностью проекта, внедрение и использование систем контроля версий (например, Git).
Инструменты и среды разработки: Настройка и поддержка инструментов и сред разработки для команды.
Идентификация и управление рисками: Определение возможных рисков и разработка стратегий их минимизации.
Решение технических проблем: Быстрое реагирование и решение технических проблем, возникающих в процессе разработки.
Понимание бизнес-требований: Глубокое понимание бизнес-требований и целей проекта.
Перевод бизнес-требований в технические: Трансформация бизнес-требований в технические задачи и спецификации.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1👍1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚Базу Знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥2😁1
Колбеки фрагмента отличаются от колбеков Activity, так как фрагменты управляют отдельными частями пользовательского интерфейса, могут динамически добавляться или удаляться, и имеют свои специфичные методы (onCreateView(), onAttach(), и т.д.), в то время как Activity управляет жизненным циклом всего экрана.
Activity: Основные стадии - onCreate(), onStart(), onResume(), onPause(), onStop(), onDestroy().
Fragment: Дополнительные стадии - onAttach(), onCreateView(), onViewCreated(), onDestroyView(), onDetach().
Activity: Независимая единица интерфейса.
Fragment: Модульная часть внутри Activity.
Activity: Управляет своим представлением.
Fragment: Управляет своим представлением внутри Activity.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👍2
Мои три любимые фичи в Kotlin: Extension Functions для добавления новых функций к существующим классам без их изменения, Null Safety для защиты от NullPointerException и упрощенного управления null-значениями, а также Coroutines для удобной работы с асинхронным кодом и многопоточностью, делая его более простым и понятным.
Одной из главных проблем при программировании на Java является
NullPointerException, который возникает при попытке использовать объект, равный null. Kotlin решает эту проблему на уровне языка. Это помогает избежать неожиданных ошибок и делает код более надежным. Программист явно указывает, когда переменная может быть null, что уменьшает количество ошибок, связанных с null-значениями.var name: String? = "Kotlin"
name = null // Это допустимо, так как тип переменной может быть null
var length = name?.length // Вернет длину строки или null, если name равно null
Kotlin позволяет добавлять новые методы к существующим классам без необходимости наследования или использования паттернов, таких как Decorator. Это улучшает читаемость и поддерживаемость кода, позволяя добавлять функциональность к существующим классам на лету, не нарушая их.
fun String.lastChar(): Char = this[this.length - 1]
val c = "Kotlin".lastChar() // Вернет 'n'
Корутины предоставляют простой и эффективный способ выполнения асинхронных задач. Они легче и удобнее в использовании по сравнению с традиционными потоками. Корутины упрощают написание асинхронного и параллельного кода, делая его более понятным и управляемым. Они обеспечивают неблокирующие операции, что улучшает производительность и отзывчивость приложений.
import kotlinx.coroutines.*
fun main() = runBlocking {
launch {
delay(1000L)
println("World!")
}
println("Hello,")
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍4
В Kotlin все классы по умолчанию наследуются от класса Any. Этот класс является корневым (базовым) классом для всех других классов в Kotlin. Он аналогичен классу Object в Java.
Наследование от Any обеспечивает всем классам базовые методы, такие как:
equals(): Проверка на равенство объектов.
hashCode(): Возвращает хэш-код объекта.
toString(): Возвращает строковое представление объекта.
Когда вы создаете класс в Kotlin, вам не нужно явно указывать, что он наследуется от Any — это происходит автоматически. Например:
class Person(val name: String, val age: Int)
Эквивалентно:
class Person(val name: String, val age: Int) : Any()
Вы можете переопределить методы Any, чтобы адаптировать их под свои нужды. Например, переопределим метод toString:
class Person(val name: String, val age: Int) {
override fun toString(): String {
return "Person(name=$name, age=$age)"
}
}
fun main() {
val person = Person("Alice", 30)
println(person.toString()) // Вывод: Person(name=Alice, age=30)
}Это нужно для обеспечения базовой функциональности всех объектов в языке. Например, метод equals позволяет сравнивать два объекта, а toString предоставляет удобный способ представления объекта в виде строки.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👍3
Метод
hashCode в Java используется для получения хэш-кода объекта. Этот метод играет важную роль при работе с коллекциями, такими как HashMap, HashSet и Hashtable. Основная задача метода hashCode — предоставить числовое представление объекта, которое позволяет быстро находить его в хэш-таблицах. Давайте разберем, почему это важно и как это используется.Хэш-таблицы используют хэш-коды для быстрого поиска объектов. При добавлении объекта в коллекцию, такую как
HashMap, хэш-код объекта определяет его место в таблице. При поиске объекта его хэш-код используется для нахождения соответствующего "ведра" (bucket), где может находиться объект.Хотя разные объекты могут иметь одинаковый хэш-код (коллизии), правильно реализованный метод
hashCode минимизирует их количество. В случае коллизий, объекты размещаются в одном ведре, и дальнейший поиск осуществляется с использованием метода equals.Метод
hashCode определяется в классе Object, от которого наследуются все классы в Java. Чтобы ваш класс работал корректно с хэш-таблицами, необходимо переопределить этот метод.public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}Метод
equals проверяет равенство объектов по полям name и age.Метод
hashCode возвращает хэш-код, основанный на этих же полях, используя метод Objects.hash.Хэш-код должен оставаться неизменным, если объект не изменился.
Если два объекта равны (по методу
equals), их хэш-коды должны совпадать.Это допустимо, но нежелательно.
В этом примере
HashMap использует метод hashCode для быстрого поиска объектов Person.public class Main {
public static void main(String[] args) {
Map<Person, String> map = new HashMap<>();
Person p1 = new Person("John", 25);
Person p2 = new Person("Jane", 30);
map.put(p1, "Engineer");
map.put(p2, "Doctor");
System.out.println(map.get(p1)); // Output: Engineer
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4
В Android, класс View является базовым классом для всех визуальных компонентов (например, кнопок, текстовых полей и т.д.). У View есть множество методов, которые обеспечивают его функциональность.
onMeasure(int widthMeasureSpec, int heightMeasureSpec)Назначение: Этот метод определяет размер View. Он вызывается системой во время этапа измерения макета, чтобы определить, как View хочет быть измерен. Вы можете переопределить этот метод, чтобы задать конкретные размеры для вашей View.
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val width = 200
val height = 100
setMeasuredDimension(width, height)
}onLayout(boolean changed, int left, int top, int right, int bottom)Назначение: Этот метод отвечает за позиционирование View внутри его родительского контейнера.
Переопределяя этот метод, вы можете задать конкретное расположение вашей View.
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
// Позиционирование дочерних элементов
}onDraw(Canvas canvas)Назначение: Этот метод отвечает за рисование View. В нем вы можете указать, как должен быть нарисован ваш компонент.
Пример: Переопределяя этот метод, вы можете нарисовать свою View с помощью методов класса Canvas.
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
// Нарисовать что-то на канвасе
canvas.drawRect(0f, 0f, 100f, 100f, Paint())
}Назначение: Этот метод используется для принудительного перерисовывания View. Когда вы вызываете invalidate(), система вызывает onDraw(). Вызывайте invalidate(), когда хотите обновить отображение View.
fun updateView() {
// Изменить данные
invalidate() // Перерисовать View
}setOnClickListener(OnClickListener l)Назначение: Устанавливает слушатель для обработки событий нажатия.
Вы можете установить обработчик для событий нажатия на View.
myView.setOnClickListener {
// Действие при нажатии
}setVisibility(int visibility)Назначение: Управляет видимостью View. Принимает значения VISIBLE, INVISIBLE и GONE.
myView.visibility = View.VISIBLE
getWidth() и getHeight()Назначение: Возвращают текущую ширину и высоту View.
val width = myView.width
val height = myView.height
setBackgroundColor(int color)Назначение: Устанавливает цвет фона View.
myView.setBackgroundColor(Color.RED)
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6
Отправка файла на сервер с помощью потока (Stream) напрямую невозможна из-за особенностей работы сетевых протоколов и ограничений в структурах данных, используемых для передачи данных по сети.
Большинство сетевых протоколов, таких как HTTP, используют стандартизированные методы для передачи данных, которые требуют использования специфичных структур и форматов. Для HTTP это включает использование заголовков, методов (POST, GET и т.д.) и тела запроса.
Multipart/form-data: Для отправки файлов обычно используется формат multipart/form-data, который позволяет отправлять файлы вместе с другими данными в одном запросе. Этот формат требует правильного формирования границ (boundary) и инкапсуляции данных, что не может быть выполнено напрямую через поток.
Base64 Encoding: В некоторых случаях файлы могут быть закодированы в Base64 и отправлены как часть JSON или XML. Однако это также требует преобразования данных и правильного форматирования запроса.
Формирование запроса: Для отправки файла необходимо сформировать HTTP-запрос, который включает заголовки, тело запроса и другие метаданные. Потоки не предоставляют удобных методов для формирования таких структурированных запросов.
Чтобы отправить файл на сервер, следует использовать специализированные библиотеки и классы, которые обеспечивают правильное формирование и отправку HTTP-запросов.
Встроенный в Java класс для отправки HTTP-запросов. Можно использовать для формирования multipart-запросов.
Популярная библиотека для выполнения HTTP-запросов в Android.
Высокоуровневая библиотека для выполнения HTTP-запросов, которая работает поверх OkHttp.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3