Ставь 👍 и забирай 📚 Базу знаний
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
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🔥4
Тяжелые, требуют много ресурсов ОС. Легковесные, могут существовать в большом количестве без значительных затрат.
Управляются ОС, переключение контекста дорогостоящее. Управляются на уровне языка, переключение быстрое и дешевое.
Параллельное выполнение. Кооперативная многозадачность, задачи добровольно уступают управление.
Могут блокироваться на длительное время. Приостанавливаются и возобновляются, эффективны при операциях ввода-вывода.
Требуют сложного управления и синхронизации. Код проще и читаемее.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
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