Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥4🤔1
Оператор
== используется для сравнения двух переменных на равенство. Это означает, что == проверяет, указывают ли две переменные на один и тот же объект в памяти (сравнение ссылок).String str1 = new String("hello");
String str2 = new String("hello");
if (str1 == str2) {
System.out.println("References are equal");
} else {
System.out.println("References are not equal");
}
// Output: References are not equalВ данном примере
str1 == str2 вернет false, потому что str1 и str2 указывают на разные объекты в памяти, даже если их значения совпадают. Для сравнения значений строк в Java нужно использовать метод equals().if (str1.equals(str2)) {
System.out.println("Values are equal");
} else {
System.out.println("Values are not equal");
}
// Output: Values are equalОператор
== используется для сравнения значений, а не ссылок. Это аналог метода equals() в Java. Для сравнения ссылок в Kotlin используется оператор ===. В данном примере str1 == str2 вернет true, потому что оператор == в Kotlin сравнивает значения строк. Если нужно сравнить ссылки в Kotlin, используется оператор ===. val str1 = "hello"
val str2 = "hello"
if (str1 == str2) {
println("Values are equal")
} else {
println("Values are not equal")
}
// Output: Values are equal
Здесь
obj1 === obj2 вернет false, потому что obj1 и obj2 указывают на разные объекты в памяти.val obj1 = Any()
val obj2 = Any()
if (obj1 === obj2) {
println("References are equal")
} else {
println("References are not equal")
}
// Output: References are not equal
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍18🔥1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14🔥5👀1
Использую инструменты профилирования (например, Android Profiler в Android Studio) для сбора данных о времени выполнения различных частей кода при запуске приложения. Проанализирую логи, чтобы найти узкие места и определить, какие операции занимают больше всего времени. Проверю все зависимости и библиотеки, используемые в проекте, чтобы понять, не вызывают ли они задержки.
Проверю, какие объекты инициализируются при старте, и оценю, действительно ли все они необходимы на этом этапе. Выясню, не происходят ли тяжелые сетевые запросы или операции с базой данных во время запуска. Проверю, не загружаются ли большие ресурсы (изображения, файлы) в момент старта.
Перенесу инициализацию объектов, которые не нужны сразу, на более поздние этапы работы приложения. Использую асинхронные операции (например, с помощью Coroutines в Kotlin или AsyncTask в Java) для выполнения тяжелых задач в фоне. Оптимизирую сетевые запросы и запросы к базе данных, чтобы они выполнялись быстрее и потребляли меньше ресурсов.
Внедрение зависимостей с использованием Dagger/Hilt, что позволяет более гибко управлять инициализацией объектов. Перенос тяжелой логики из стартовой активности в фоновые сервисы или ViewModel, чтобы основной поток оставался свободным.
Использую кэширование данных, которые не нужно запрашивать каждый раз при запуске (например, данные, полученные из сети или базы данных).
Оптимизирую изображения и другие ресурсы, чтобы уменьшить их размер и, следовательно, время загрузки. Вместо тяжелых анимаций использую Lottie для уменьшения нагрузки на систему.
Внедряю автоматические тесты для регулярного тестирования производительности. Настраиваю инструменты мониторинга (например, Firebase Performance Monitoring) для отслеживания производительности приложения в реальном времени.
// Вместо выполнения сетевого запроса на главном потоке, перенесем его в IO поток
fun fetchData() {
CoroutineScope(Dispatchers.Main).launch {
val data = withContext(Dispatchers.IO) {
// Долгий сетевой запрос
apiService.getData()
}
updateUI(data)
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤1🔥1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥6
Возникают, когда два или более ключей имеют одинаковое значение хэш-кода. Это неизбежно, так как возможное количество ключей значительно превышает возможное количество хэш-кодов, что ведет к ситуации, когда разные ключи мапируются в одно и то же место (бакет) в таблице.
При добавлении пары ключ-значение в
HashMap, сначала вызывается метод hashCode() для ключа, чтобы получить его хэш-код.Затем хэш-код используется для определения индекса бакета в массиве таблицы, где должна храниться эта пара.
В бакете, который представляет собой связный список или дерево, проверяются все ключи с тем же индексом бакета, чтобы найти совпадение с помощью метода
equals().В случае коллизии пара добавляется в связный список внутри соответствующего бакета.
Процесс добавления: Если бакет пустой, новая пара просто добавляется. Если нет, то пара добавляется в конец списка или обновляется, если ключ уже существует.
Процесс поиска: Когда требуется доступ к элементу, хэш-код снова используется для определения бакета, затем перебираются все элементы в списке и сравниваются ключи с помощью
equals().Когда количество элементов в одном бакете превышает определенный порог (обычно 8), связный список преобразуется в сбалансированное двоичное дерево, что улучшает производительность поиска и вставки.
Процесс добавления: Если количество коллизий превысило порог, связный список заменяется на дерево. Новые пары добавляются в дерево.
Процесс поиска: При доступе к элементам в дереве используется логарифмическое время поиска.
Пример, демонстрирующий коллизию в
HashMap:import java.util.HashMap;
public class HashMapCollisionExample {
public static void main(String[] args) {
HashMap<Key, String> map = new HashMap<>();
// Два ключа с одинаковым хэш-кодом
Key key1 = new Key("A1", 42);
Key key2 = new Key("B1", 42);
// Добавляем ключи в карту
map.put(key1, "Value1");
map.put(key2, "Value2");
// Получение значений
System.out.println(map.get(key1)); // Output: Value1
System.out.println(map.get(key2)); // Output: Value2
}
}
class Key {
private String name;
private int id;
public Key(String name, int id) {
this.name = name;
this.id = id;
}
@Override
public int hashCode() {
return id; // Искусственно создаем коллизии
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Key key = (Key) obj;
return id == key.id && name.equals(key.name);
}
}
Важно, чтобы метод
hashCode() равномерно распределял значения, чтобы минимизировать вероятность коллизий.При превышении определенного порога заполненности (load factor), размер таблицы удваивается, и все элементы перераспределяются (rehashing).
Современные реализации
HashMap используют деревья вместо списков для бакетов с большим количеством элементов, что улучшает производительность при коллизиях.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍1
Создание новых объектов при каждом скролле. Правильное использование ViewHolder для повторного использования представлений.
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
public static class MyViewHolder extends RecyclerView.ViewHolder {
public TextView textView;
public MyViewHolder(View v) {
super(v);
textView = v.findViewById(R.id.textView);
}
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.my_text_view, parent, false);
return new MyViewHolder(v);
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.textView.setText(myDataset[position]);
}
@Override
public int getItemCount() {
return myDataset.length;
}
}Загрузка изображений или обработка данных. Использование асинхронных задач и библиотек для загрузки изображений.
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.textView.setText(myDataset[position]);
Glide.with(holder.imageView.getContext())
.load(imageUrls[position])
.into(holder.imageView);
}
Загрузка больших изображений без сжатия. Использование библиотек Glide или Picasso.
Glide.with(context)
.load(url)
.into(imageView);
Сложные иерархии макетов. Использование простых макетов и ViewStub для отложенной загрузки.
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageView"
android:layout_width="0dp"
android:layout_height="0dp"
android:contentDescription="@string/image_desc" />
<TextView
android:id="@+id/textView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/sample_text" />
</androidx.constraintlayout.widget.ConstraintLayout>
Перерисовка всего списка. Использование notifyItemInserted, notifyItemRemoved, notifyItemChanged для частичных обновлений.
adapter.notifyItemInserted(position);
adapter.notifyItemRemoved(position);
Повторная загрузка данных при каждом скролле. Кэширование данных с помощью LiveData.
LiveData<List<Item>> items = viewModel.getItems();
items.observe(this, new Observer<List<Item>>() {
@Override
public void onChanged(List<Item> items) {
adapter.setItems(items);
}
});
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥8
Является жадной коллекцией, что означает, что все операции над элементами выполняются немедленно и целиком. Когда вы применяете функции к списку, такие как
map, filter и т.д., все элементы проходят через каждую функцию сразу же. В данном примере все элементы списка numbers сначала умножаются на 2, затем фильтруются. Вся работа выполняется сразу для каждого элемента.val numbers = listOf(1, 2, 3, 4, 5)
val result = numbers
.map { it * 2 }
.filter { it > 5 }
println(result) // Output: [6, 8, 10]
Является ленивой коллекцией. Это означает, что элементы обрабатываются по мере необходимости. Функции, применяемые к последовательности, создают цепочку операций, которая выполняется только при обращении к элементам. В этом примере
numbers сначала преобразуется в Sequence. Операции map и filter создают цепочку, которая выполняется только при преобразовании обратно в List с помощью toList(). Это позволяет избежать лишних операций и обрабатывать элементы по мере необходимости.val numbers = listOf(1, 2, 3, 4, 5)
val result = numbers.asSequence()
.map { it * 2 }
.filter { it > 5 }
.toList()
println(result) // Output: [6, 8, 10]
List: Все элементы обрабатываются сразу при вызове функций.
Sequence: Элементы обрабатываются по мере необходимости, что может повысить эффективность.
List: Подходит для небольших коллекций, где выполнение всех операций сразу не критично.
Sequence: Эффективен для больших коллекций или длинных цепочек операций, так как уменьшает количество промежуточных коллекций.
List: Может использовать больше памяти из-за создания промежуточных коллекций.
Sequence: Уменьшает использование памяти, обрабатывая элементы по одному.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7👍5
Это компонент приложения, который выполняет долгосрочные операции в фоновом режиме и не предоставляет пользовательского интерфейса. Сервисы позволяют выполнять задачи, которые не требуют взаимодействия с пользователем, например, воспроизведение музыки, загрузка файлов, обработка данных и т.д.
Сервисы выполняют задачи в фоновом режиме, что позволяет не прерывать работу пользовательского интерфейса.
Сервисы не имеют пользовательского интерфейса. Они работают независимо от активности, которая может завершиться или быть приостановлена.
Сервисы предназначены для выполнения длительных операций, которые могут продолжаться даже после закрытия приложения.
Запускается с помощью метода
startService(). Выполняет свою задачу независимо и завершает работу сам, вызвав stopSelf(), или его можно остановить извне, вызвав stopService(). Загрузка файла в фоне.// Запуск сервиса
Intent intent = new Intent(this, MyService.class);
startService(intent);
// Остановка сервиса
stopService(intent);
Предоставляет интерфейс клиентам для взаимодействия с сервисом с помощью
bindService(). Связывается с компонентом приложения (например, Activity), и работает до тех пор, пока компонент не завершится. Сервис для взаимодействия с удаленной базой данных.// Привязка к сервису
Intent intent = new Intent(this, MyService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
// Отключение от сервиса
unbindService(serviceConnection);
Пример привязки к Bound Service в Activity:
public class MainActivity extends AppCompatActivity {
MyBoundService myService;
boolean isBound = false;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
MyBoundService.LocalBinder binder = (MyBoundService.LocalBinder) service;
myService = binder.getService();
isBound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
isBound = false;
}
};
@Override
protected void onStart() {
super.onStart();
Intent intent = new Intent(this, MyBoundService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
if (isBound) {
unbindService(serviceConnection);
isBound = false;
}
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17🔥4
Он используется для обозначения кода, который никогда не завершится успешно. Понимание того, почему и как
Nothing можно подставлять везде, требует изучения его особенностей и применения.Nothing является подтипом любого другого типа в Kotlin. Это означает, что значение типа Nothing можно присвоить переменной любого типа.Тип
Nothing не имеет значений. Любая функция, которая возвращает Nothing, либо выбрасывает исключение, либо не завершает выполнение (например, бесконечный цикл).Функции, которые всегда выбрасывают исключение, могут быть объявлены с возвращаемым типом
Nothing.fun fail(message: String): Nothing {
throw IllegalArgumentException(message)
}Тип
Nothing используется для обозначения точек кода, которые не могут быть достигнуты. Например, после выбрасывания исключения выполнение кода не продолжается.val result: Int = fail("Error occurred") // Тип Nothing может быть присвоен переменной типа IntNothing может быть использован в выражениях, где требуется любой тип. Это позволяет писать более выразительный и безопасный код.fun process(value: Any?) {
val result = value ?: fail("Value is null") // fail возвращает Nothing, который совместим с любым типом
}В некоторых случаях
Nothing используется в библиотеках для обработки ошибок или в случаях, когда выполнение программы не может продолжаться.sealed class Result<out T>
class Success<out T>(val data: T) : Result<T>()
class Error(val exception: Throwable) : Result<Nothing>() // Error использует Nothing
Функция, выбрасывающая исключение
fun terminate(): Nothing {
throw RuntimeException("This function never returns")
}
fun main() {
val x: Int = terminate() // Можно присвоить переменной типа Int
}Использование
Nothing в условных выражениях:fun checkNotNull(value: String?): String {
return value ?: fail("Value is null") // Если value null, вызовется fail, возвращающий Nothing
}
fun main() {
val name: String = checkNotNull(null) // Ошибка: Value is null
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥3❤1
Имеется богатый набор коллекций, которые предоставляют различные способы хранения и управления данными. Коллекции в Kotlin можно разделить на две основные категории: неизменяемые (immutable) и изменяемые (mutable). В рамках этих категорий есть несколько типов коллекций, таких как списки, множества и карты.
Неизменяемый список, который позволяет хранить элементы в определенном порядке и допускает дублирование элементов.
val immutableList: List<String> = listOf("Apple", "Banana", "Cherry")Неизменяемое множество, которое не допускает дублирования элементов и не гарантирует сохранение порядка.
val immutableSet: Set<String> = setOf("Apple", "Banana", "Cherry")Неизменяемая карта, которая хранит пары ключ-значение. Ключи должны быть уникальными.
val immutableMap: Map<String, Int> = mapOf("Apple" to 1, "Banana" to 2, "Cherry" to 3)Изменяемый список, который позволяет добавлять, удалять и изменять элементы.
val mutableList: MutableList<String> = mutableListOf("Apple", "Banana", "Cherry")
mutableList.add("Date")Изменяемое множество, которое позволяет добавлять и удалять элементы.
val mutableSet: MutableSet<String> = mutableSetOf("Apple", "Banana", "Cherry")
mutableSet.add("Date")Изменяемая карта, которая позволяет добавлять, удалять и изменять пары ключ-значение.
val mutableMap: MutableMap<String, Int> = mutableMapOf("Apple" to 1, "Banana" to 2, "Cherry" to 3)
mutableMap["Date"] = 4Изменяемый список, основанный на массиве. Обеспечивает быстрый доступ по индексу.
val arrayList: ArrayList<String> = arrayListOf("Apple", "Banana", "Cherry")Изменяемое множество, основанное на хэш-таблице. Обеспечивает быструю проверку принадлежности.
val hashSet: HashSet<String> = hashSetOf("Apple", "Banana", "Cherry")Изменяемая карта, основанная на хэш-таблице. Обеспечивает быстрый доступ к значениям по ключу.
val hashMap: HashMap<String, Int> = hashMapOf("Apple" to 1, "Banana" to 2, "Cherry" to 3)Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11❤1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🔥2🎉1
Причина: Создание новых объектов при каждом скролле приводит к значительным задержкам.
Решение: Используйте ViewHolder для повторного использования представлений.
class MyAdapter(private val myDataset: Array<String>) : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
class MyViewHolder(v: View) : RecyclerView.ViewHolder(v) {
val textView: TextView = v.findViewById(R.id.textView)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val v = LayoutInflater.from(parent.context)
.inflate(R.layout.my_text_view, parent, false)
return MyViewHolder(v)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.textView.text = myDataset[position]
}
override fun getItemCount(): Int {
return myDataset.size
}
}Причина: Выполнение тяжелых операций в главном потоке приводит к блокировке пользовательского интерфейса.
Решение: Переносите тяжелые операции в асинхронные задачи или используйте библиотеки для асинхронной загрузки.
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.textView.text = myDataset[position]
Glide.with(holder.imageView.context)
.load(imageUrls[position])
.into(holder.imageView)
}Причина: Загрузка больших изображений в главном потоке может замедлить приложение.
Решение: Используйте библиотеки, такие как Glide или Picasso, которые автоматически обрабатывают загрузку и кэширование изображений.
Glide.with(context)
.load(url)
.into(imageView);
Причина: Сложные иерархии макетов или невидимые представления занимают больше памяти и времени на рендеринг.
Решение: Оптимизируйте макеты, минимизируйте количество вложенных представлений и используйте ViewStub для отложенной загрузки.
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:contentDescription="@string/image_desc" />
<TextView
android:id="@+id/textView"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/imageView"
android:text="@string/sample_text" />
</androidx.constraintlayout.widget.ConstraintLayout>
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8
Добавляет элемент на вершину стека. Эта операция вставляет новый элемент в стек и делает его верхним элементом.
val stack = Stack<Int>()
stack.push(10) // Стек: [10]
stack.push(20) // Стек: [10, 20]
Удаляет и возвращает верхний элемент стека. Эта операция удаляет элемент, который находится на вершине стека, и возвращает его. Если стек пуст, обычно выбрасывается исключение (например,
EmptyStackException).val top = stack.pop() // top = 20, Стек: [10]
Возвращает верхний элемент стека без его удаления. Эта операция позволяет просмотреть верхний элемент стека без его удаления. Если стек пуст, обычно выбрасывается исключение.
val top = stack.peek() // top = 10, Стек: [10]
Ищет элемент в стеке и возвращает его позицию относительно вершины стека. Если элемент не найден, возвращает -1.
val position = stack.search(10) // position = 1
Пример использования стека
import java.util.Stack;
public class StackExample {
public static void main(String[] args) {
Stack<Integer> stack = new Stack<>();
// Добавление элементов (push)
stack.push(10);
stack.push(20);
stack.push(30);
// Просмотр верхнего элемента (peek)
System.out.println("Верхний элемент: " + stack.peek()); // Вывод: 30
// Удаление верхнего элемента (pop)
System.out.println("Удален элемент: " + stack.pop()); // Вывод: 30
System.out.println("Новый верхний элемент: " + stack.peek()); // Вывод: 20
// Проверка, пуст ли стек (isEmpty)
System.out.println("Стек пустой? " + stack.isEmpty()); // Вывод: false
// Размер стека (size)
System.out.println("Размер стека: " + stack.size()); // Вывод: 2
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥1