Kotlin | Вопросы собесов
2.57K subscribers
28 photos
964 links
Download Telegram
🤔 Для чего нужен метод hashCode?

Метод hashCode в Java используется для получения хэш-кода объекта. Этот метод играет важную роль при работе с коллекциями, такими как HashMap, HashSet и Hashtable. Основная задача метода hashCode — предоставить числовое представление объекта, которое позволяет быстро находить его в хэш-таблицах. Давайте разберем, почему это важно и как это используется.

🚩Почему нужен метод `hashCode`

🟠Эффективность поиска
Хэш-таблицы используют хэш-коды для быстрого поиска объектов. При добавлении объекта в коллекцию, такую как HashMap, хэш-код объекта определяет его место в таблице. При поиске объекта его хэш-код используется для нахождения соответствующего "ведра" (bucket), где может находиться объект.

🟠Устранение коллизий
Хотя разные объекты могут иметь одинаковый хэш-код (коллизии), правильно реализованный метод hashCode минимизирует их количество. В случае коллизий, объекты размещаются в одном ведре, и дальнейший поиск осуществляется с использованием метода equals.

🚩Как используется метод `hashCode`

Метод 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.

🚩Правила для метода hashCode

🟠Консистентность
Хэш-код должен оставаться неизменным, если объект не изменился.
🟠Равные объекты — равные хэш-коды:
Если два объекта равны (по методу 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
🤔 Какие есть способы работы с многопоточностью?

Основные способы работы с многопоточностью включают использование потоков (Thread), пулов потоков (ExecutorService), корутин (в Kotlin) и реактивного программирования (RxJava). Каждый из них имеет свои преимущества и подходит для различных задач. Например, корутины оптимальны для асинхронных операций, а Thread и ExecutorService подходят для низкоуровневого контроля.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4
🤔 Какие методы есть у view и что каждый из них делает?

В 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())
}


🟠invalidate()
Назначение: Этот метод используется для принудительного перерисовывания 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
🤔 Восьмая версия Java поддерживается всеми версиями Android?

Нет, восьмая версия Java поддерживается только начиная с Android версии 7.0 (Nougat) с ограничениями. Для более старых версий Android используется библиотека desugar, позволяющая частично поддерживать некоторые функции Java 8. Полная поддержка возможна только на современных версиях Android.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
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-запросов.

🟠HttpURLConnection
Встроенный в Java класс для отправки HTTP-запросов. Можно использовать для формирования multipart-запросов.
🟠OkHttp
Популярная библиотека для выполнения HTTP-запросов в Android.
🟠Retrofit
Высокоуровневая библиотека для выполнения HTTP-запросов, которая работает поверх OkHttp.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🤔 Зачем нужны методы equals и hashcode?

Метод equals сравнивает два объекта на логическое равенство, а hashCode возвращает числовое представление объекта. Они используются в коллекциях, таких как HashMap и HashSet, для корректного поиска и хранения элементов. Переопределение этих методов необходимо для правильного сравнения пользовательских объектов.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1
🤔 Как вернуть результат работы WorkManager в приложение?

Для того чтобы вернуть результат работы WorkManager в приложение, можно использовать несколько подходов. Самый распространенный способ — это использование LiveData для наблюдения за статусом выполнения задачи. Кроме того, можно использовать ListenableWorker.Result для передачи результата из самого рабочего процесса.

🚩Шаги с использование LiveData для наблюдения за статусом работы

1⃣Создайте Worker
import android.content.Context
import androidx.work.Worker
import androidx.work.WorkerParameters

class MyWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
override fun doWork(): Result {
// Выполните свою задачу
val result = performTask()

// Верните результат работы
return if (result) {
Result.success()
} else {
Result.failure()
}
}

private fun performTask(): Boolean {
// Ваша логика работы
return true
}
}


2⃣Запустите Worker и наблюдайте за его статусом
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager

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

// Создание и запуск запроса на выполнение работы
val workRequest = OneTimeWorkRequest.Builder(MyWorker::class.java).build()
WorkManager.getInstance(this).enqueue(workRequest)

// Наблюдение за статусом работы
WorkManager.getInstance(this).getWorkInfoByIdLiveData(workRequest.id)
.observe(this, Observer { workInfo ->
if (workInfo != null && workInfo.state.isFinished) {
if (workInfo.state == WorkInfo.State.SUCCEEDED) {
// Работа успешно завершена
val outputData = workInfo.outputData
// Обработка данных результата
} else if (workInfo.state == WorkInfo.State.FAILED) {
// Работа завершилась неудачно
}
}
})
}
}


3⃣Передача данных результата
import androidx.work.Data

class MyWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
override fun doWork(): Result {
// Выполните свою задачу
val result = performTask()

// Подготовка данных для возвращения
val outputData = Data.Builder()
.putString("key_result", "My Result")
.build()

// Верните результат работы с данными
return if (result) {
Result.success(outputData)
} else {
Result.failure()
}
}

private fun performTask(): Boolean {
// Ваша логика работы
return true
}
}


В MainActivity
// Получение данных результата
val resultString = workInfo.outputData.getString("key_result")


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
🤔 Чем array отличается от list?

Array — это фиксированный по размеру массив элементов, а List — изменяемая или неизменяемая коллекция с гибкой длиной. Array удобен для высокопроизводительных операций с фиксированным числом элементов, а List предоставляет богатый функционал для работы с динамическими данными. В Kotlin List также может быть неизменяемым, что повышает безопасность кода.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥1
🤔 В какой момент система может перезапустить сервис?

Система Android может перезапустить сервис в нескольких случаях, особенно если это касается долгосрочных или критически важных задач, которые должны продолжаться, даже если приложение было закрыто или убито системой.

🟠Использование `START_STICKY`
Если сервис был запущен с использованием START_STICKY, система попытается перезапустить его, если он был убит. Этот режим подходит для сервисов, которые выполняют важные фоновые задачи, которые должны продолжаться, даже если приложение было закрыто.
public class MyService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Выполнение задачи
return START_STICKY;
}

@Override
public IBinder onBind(Intent intent) {
return null;
}
}


🟠Использование `START_REDELIVER_INTENT`
Если сервис был запущен с использованием START_REDELIVER_INTENT, система также попытается перезапустить его, если он был убит, но с повторной доставкой последнего Intent. Это полезно для сервисов, которые должны обработать все интенты, даже если они были убиты и перезапущены.
public class MyService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Выполнение задачи
return START_REDELIVER_INTENT;
}

@Override
public IBinder onBind(Intent intent) {
return null;
}
}


🟠Использование Foreground Service
Foreground сервисы — это сервисы, которые пользователи знают, что они работают, и обычно показывают уведомление. Такие сервисы имеют более высокий приоритет и менее вероятно будут убиты системой. Однако, если это произойдет, система постарается их перезапустить.
public class MyForegroundService extends Service {
@Override
public void onCreate() {
super.onCreate();
// Создание уведомления
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Foreground Service")
.setContentText("Service is running")
.setSmallIcon(R.drawable.ic_service)
.build();

// Запуск сервиса переднего плана
startForeground(1, notification);
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Выполнение задачи
return START_STICKY;
}

@Override
public IBinder onBind(Intent intent) {
return null;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
🤔 В чем отличие между job и supervisor job?

Job управляет выполнением корутины и завершает её при возникновении ошибки. SupervisorJob позволяет дочерним корутинам продолжать выполнение, даже если одна из них завершилась с ошибкой. Это полезно для создания устойчивых структур, где сбой одной задачи не влияет на другие.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍2
🤔 Что будет со старым Activity, когда система запустит новое?

Когда система запускает новое Activity в Android, судьба старого Activity зависит от множества факторов, включая флаги намерения (intent flags), конфигурацию задачи (task configuration) и состояние памяти устройства.

🟠По умолчанию (без специальных флагов)
Если не используются специальные флаги или конфигурации, то при запуске нового Activity старое Activity остается в стеке задач (back stack).
Старое Activity переходит в состояние onPause(), затем onStop().
Новое Activity создается и проходит состояния onCreate(), onStart() и onResume().
Intent intent = new Intent(this, NewActivity.class);
startActivity(intent);


🟠Использование флага `FLAG_ACTIVITY_NEW_TASK`
Если флаг FLAG_ACTIVITY_NEW_TASK установлен, новое Activity запускается в новом отдельном стеке задач, если такого еще нет.
Старое Activity остается в своей задаче.
Новое Activity запускается в новой задаче.
Intent intent = new Intent(this, NewActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);


🟠Использование флага `FLAG_ACTIVITY_CLEAR_TOP`
Если флаг FLAG_ACTIVITY_CLEAR_TOP установлен, новое Activity будет запускаться, а все активности над ним в стеке будут удалены.
Если старое Activity уже в стеке задач, все активности выше него будут удалены.
Старое Activity будет возвращено в состояние onRestart(), onStart() и onResume().
Intent intent = new Intent(this, NewActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);


🟠Использование флага `FLAG_ACTIVITY_SINGLE_TOP`
Если флаг FLAG_ACTIVITY_SINGLE_TOP установлен и новое Activity уже находится на вершине стека, оно не будет пересоздано, а просто получит вызов onNewIntent().
Если новое Activity уже на вершине стека, его метод onNewIntent() будет вызван вместо создания нового экземпляра.
Intent intent = new Intent(this, NewActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);


🚩Сценарии работы с памятью

Если система нуждается в памяти, она может уничтожить старое Activity, которое находится в состоянии onStop(). Когда пользователь вернется к этому Activity, оно будет пересоздано и его метод onCreate() будет вызван снова.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Что является сущностью корутин контекста?

Основными сущностями корутинного контекста являются Job (управляет жизненным циклом), CoroutineDispatcher (определяет, на каком потоке выполняется корутина) и пользовательские элементы. Контекст передаёт данные и управляющие инструкции между корутинами. Это позволяет эффективно координировать выполнение задач.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1
🤔 Если Activity запускается после сервиса, можно ли подсоединиться к этому сервису?

Да, в Android можно подключиться к сервису после его запуска и взаимодействовать с ним через механизм привязки (binding). Это достигается с помощью метода bindService(). Привязка к сервису позволяет активити (или другому компоненту) взаимодействовать с уже запущенным сервисом, получать данные от него или отправлять команды.

🚩Шаги

1⃣Создание сервиса
Сначала создайте сервис, который можно будет запускать и к которому можно будет привязываться. В данном примере, используем BoundService.

2⃣Запуск сервиса
Запустите сервис с помощью метода startService().

3⃣Привязка к сервису
Используйте метод bindService() для подключения к уже запущенному сервису.

🚩Пример реализации

1⃣Создайте BoundService
public class MyBoundService extends Service {
private final IBinder binder = new LocalBinder();

public class LocalBinder extends Binder {
MyBoundService getService() {
return MyBoundService.this;
}
}

@Override
public IBinder onBind(Intent intent) {
return binder;
}

public String getGreeting() {
return "Hello from Bound Service!";
}
}


2⃣Запустите и привяжитесь к сервису в Activity
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="16dp">

<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Get Greeting" />

<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:textSize="18sp" />
</LinearLayout>


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🤔 Расскажи про наследование в Kotlin?

Наследование в Kotlin используется для создания новых классов на основе существующих с помощью ключевого слова open. Базовый класс может быть расширен, а его методы и свойства переопределены в дочернем классе с помощью override. Это позволяет повторно использовать код и добавлять новую функциональность.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥1
🤔 Как task manager передает результат?

В Android используется для выполнения асинхронных задач в фоновом режиме. Самый распространенный способ выполнения задач и передачи результатов — это использование WorkManager. WorkManager — это библиотека, которая предоставляет гибкий API для планирования однократных или повторяющихся задач, которые гарантированно будут выполнены даже при перезапуске устройства.

🚩Передача результата с помощью `WorkManager`

1⃣Создание Worker
Создайте класс, который наследует Worker или CoroutineWorker, и определите работу, которую необходимо выполнить в методе doWork().
import android.content.Context
import androidx.work.Worker
import androidx.work.WorkerParameters
import androidx.work.Data

class MyWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
override fun doWork(): Result {
// Выполните свою задачу
val outputData = Data.Builder()
.putString("key_result", "Task Completed Successfully")
.build()

// Возвращение результата
return Result.success(outputData)
}
}


2⃣Запуск задачи
Запланируйте и запустите задачу, используя WorkManager. Настройте WorkRequest и передайте данные, если это необходимо.
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
import androidx.work.Data
import androidx.work.ExistingWorkPolicy

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

// Создание WorkRequest
val workRequest = OneTimeWorkRequest.Builder(MyWorker::class.java)
.build()

// Запуск задачи
WorkManager.getInstance(this).enqueue(workRequest)
}
}


3⃣Наблюдение за результатами выполнения задачи
Используйте LiveData для наблюдения за статусом и результатами выполнения задачи. Это позволяет получать обновления о состоянии задачи в реальном времени.
import androidx.lifecycle.Observer
import androidx.work.WorkInfo

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

val workRequest = OneTimeWorkRequest.Builder(MyWorker::class.java).build()
WorkManager.getInstance(this).enqueue(workRequest)

// Наблюдение за результатами выполнения задачи
WorkManager.getInstance(this).getWorkInfoByIdLiveData(workRequest.id)
.observe(this, Observer { workInfo ->
if (workInfo != null && workInfo.state.isFinished) {
if (workInfo.state == WorkInfo.State.SUCCEEDED) {
val outputData = workInfo.outputData
val result = outputData.getString("key_result")
// Обработка результата
println("Result: $result")
} else if (workInfo.state == WorkInfo.State.FAILED) {
// Обработка ошибки
println("Task Failed")
}
}
})
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍51
🤔 Что знаешь о диспатчерах?

Диспетчеры в Kotlin определяют, на каком потоке будет выполняться корутина, например, Dispatchers.Main для UI-потока, Dispatchers.IO для ввода-вывода и Dispatchers.Default для фоновых вычислений. Они помогают распределять задачи по подходящим потокам, обеспечивая оптимальную производительность. Также можно создать собственный диспетчер для специфичных задач.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥1
🤔 Как можно получить сообщения на главном потоке с помощью Handler и Looper?

В Android для обработки сообщений и выполнения задач в основном (главном) потоке часто используются классы Handler и Looper. Handler позволяет отправлять и обрабатывать Message и Runnable объекты, ассоциированные с Looper. Главный поток приложения имеет свой Looper, который постоянно обрабатывает очередь сообщений и задач.

🚩Основные шаги для использования

1⃣Создание Handler
В главном потоке Handler можно создавать непосредственно, так как Looper уже существует. Это можно сделать в любом месте, например, в Activity или Fragment.
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

private Handler mainHandler;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

// Создание Handler, привязанного к Looper главного потока
mainHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
// Обработка сообщений
if (msg.what == 1) {
// Пример обработки сообщения
String messageData = (String) msg.obj;
System.out.println("Received message: " + messageData);
}
}
};

// Пример отправки сообщения
Message message = Message.obtain();
message.what = 1;
message.obj = "Hello from background thread!";
mainHandler.sendMessage(message);

// Пример отправки задачи
mainHandler.post(new Runnable() {
@Override
public void run() {
System.out.println("Runnable executed on main thread");
}
});
}
}


2⃣Отправка сообщений или задач на обработку в главный поток
Сообщения и задачи можно отправлять из любого потока. Например, из фонового потока:
new Thread(new Runnable() { 
@Override
public void run() {
// Отправка сообщения
Message message = Message.obtain();
message.what = 1;
message.obj = "Hello from background thread!";
mainHandler.sendMessage(message);

// Отправка задачи
mainHandler.post(new Runnable() {
@Override
public void run() {
System.out.println("Runnable executed on main thread from background thread");
}
});
}
}).start();


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2😁1👀1
🤔 Фреймворк Dagger

Dagger — это фреймворк для внедрения зависимостей в Java и Kotlin. Он использует аннотации для описания зависимостей и автоматического их создания. Dagger генерирует код на этапе компиляции, который управляет зависимостями и предоставляет их нуждающимся классам. Он основан на принципах инверсии управления и часто используется для масштабируемых приложений, таких как Android-приложения. В Android Dagger помогает удобно управлять зависимостями, улучшая тестируемость и читаемость кода.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥2🎉1
🤔 Как Looper связывается с потоком?

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

1⃣Создание Looper
По умолчанию главный поток приложения уже имеет Looper, и мы можем получить его с помощью Looper.getMainLooper(). Для других потоков мы должны создать Looper вручную.

2⃣Подготовка Looper для потока
Метод Looper.prepare() создает Looper для текущего потока. Метод Looper.loop() запускает цикл обработки сообщений для этого Looper.

3⃣Создание Handler, связанного с Looper
Handler использует Looper, чтобы определять, к какому потоку привязан, и куда отправлять сообщения и задачи.

🚩Пример создания Looper в новом потоке

1⃣Создание Looper и Handler в новом потоке
public class LooperThread extends Thread {
public Handler handler;
private Looper looper;

@Override
public void run() {
// Подготовка Looper для текущего потока
Looper.prepare();

// Создание Handler, связанного с этим Looper
handler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(Message msg) {
// Обработка сообщений
System.out.println("Received message: " + msg.what);
}
};

// Получение ссылки на Looper текущего потока
looper = Looper.myLooper();

// Запуск цикла обработки сообщений
Looper.loop();
}

// Метод для остановки Looper
public void quit() {
if (looper != null) {
looper.quit();
}
}
}


2⃣Использование LooperThread в Activity
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
private LooperThread looperThread;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

// Запуск LooperThread
looperThread = new LooperThread();
looperThread.start();

// Отправка сообщения в новый поток через Handler
findViewById(R.id.button_send_message).setOnClickListener(view -> {
if (looperThread.handler != null) {
Message message = Message.obtain();
message.what = 1;
looperThread.handler.sendMessage(message);
}
});
}

@Override
protected void onDestroy() {
super.onDestroy();
// Остановка LooperThread
looperThread.quit();
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Способы навигации в Kotlin

Jetpack Navigation Component — современный способ навигации, основанный на графе навигации и безопасных аргументах. Позволяет легко переходить между фрагментами и активностями, а также управлять состоянием навигации.
FragmentTransaction — ручной способ добавления, замены и удаления фрагментов.
Navigation через Intent — используется для переключения между активностями или фрагментами внутри приложения или между приложениями.
Explicit и Implicit Intents — явные и неявные намерения для навигации между компонентами.
NavHostFragment и NavController — связаны с использованием графа навигации для управления фрагментами в приложениях Android.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥2
🤔 Как работает проверка на то, есть ли в потоке Looper?

Проверка на наличие Looper в потоке в Android осуществляется с помощью метода Looper.myLooper(). Метод Looper.myLooper()
public class LooperCheck {
public static void main(String[] args) {
// Проверка наличия Looper в главном потоке
if (Looper.myLooper() != null) {
System.out.println("Looper существует в текущем потоке.");
} else {
System.out.println("Looper не существует в текущем потоке.");
}

// Запуск нового потока без Looper
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// Проверка наличия Looper в новом потоке
if (Looper.myLooper() != null) {
System.out.println("Looper существует в новом потоке.");
} else {
System.out.println("Looper не существует в новом потоке.");
}

// Создание Looper в новом потоке
Looper.prepare();

// Проверка снова после создания Looper
if (Looper.myLooper() != null) {
System.out.println("Looper теперь существует в новом потоке.");
} else {
System.out.println("Looper все еще не существует в новом потоке.");
}

// Запуск цикла обработки сообщений
Looper.loop();
}
});

thread.start();
}
}


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