ViewModel в Android гарантирует сохранение состояния до тех пор, пока соответствующее Activity или Fragment находится в памяти.
При изменении конфигурации, например, повороте экрана, Activity уничтожается и пересоздается. ViewModel выживает эти изменения конфигурации, обеспечивая сохранение состояния.
Когда вы переходите между фрагментами в одном Activity, ViewModel фрагмента сохраняет свои данные.
Если операционная система решает завершить процесс приложения для освобождения ресурсов, ViewModel будет уничтожен.
Когда пользователь закрывает Activity или приложение завершает работу (например, при нажатии кнопки "назад" до закрытия Activity), ViewModel будет уничтожен вместе с Activity.
Пример использования ViewModel с сохранением состояния при изменении конфигурации
// ViewModel
public class MyViewModel extends ViewModel {
private MutableLiveData<String> data;
public MyViewModel() {
data = new MutableLiveData<>();
}
public LiveData<String> getData() {
return data;
}
public void setData(String newData) {
data.setValue(newData);
}
}
// Activity
public class MyActivity extends AppCompatActivity {
private MyViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewModel = new ViewModelProvider(this).get(MyViewModel.class);
// Подписка на изменения данных
viewModel.getData().observe(this, newData -> {
// Обновление UI
});
// Установка новых данных
viewModel.setData("Hello, World!");
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
2. Если хэш-код совпадает, используется метод сравнения equals, чтобы отличить ключи.
3. При коллизии элементы сохраняются в одной ячейке, обычно в связанном списке или сбалансированном дереве.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥2
Для реализации приложения, которое загружает большие файлы на сервер, необходимо учитывать несколько аспектов, таких как асинхронная обработка, устойчивость к изменениям конфигурации, восстановление после неудачных попыток загрузки и отображение состояния загрузки пользователю.
В файле
build.gradle вашего модуля добавьте следующие зависимости: dependencies {
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'androidx.work:work-runtime-ktx:2.7.1'
}Создайте интерфейс для API и настройте Retrofit.
// UploadAPI.java
public interface UploadAPI {
@Multipart
@POST("/upload")
Call<ResponseBody> uploadFile(@Part MultipartBody.Part file);
}
// RetrofitClient.java
public class RetrofitClient {
private static Retrofit retrofit = null;
public static Retrofit getClient(String baseUrl) {
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
Используйте WorkManager для загрузки файла в фоновом режиме.
// FileUploadWorker.java
public class FileUploadWorker extends Worker {
public FileUploadWorker(@NonNull Context context, @NonNull WorkerParameters params) {
super(context, params);
}
@NonNull
@Override
public Result doWork() {
String filePath = getInputData().getString("file_path");
if (filePath == null) {
return Result.failure();
}
File file = new File(filePath);
RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);
MultipartBody.Part body = MultipartBody.Part.createFormData("file", file.getName(), requestFile);
UploadAPI api = RetrofitClient.getClient("https://yourserver.com/").create(UploadAPI.class);
Call<ResponseBody> call = api.uploadFile(body);
try {
Response<ResponseBody> response = call.execute();
if (response.isSuccessful()) {
return Result.success();
} else {
return Result.retry();
}
} catch (IOException e) {
e.printStackTrace();
return Result.retry();
}
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Нет, data class не может быть наследован. Это ограничение связано с оптимизацией и специфическими функциями, такими как copy и equals, которые автоматически генерируются для data class.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🔥6❤1
В Android существует несколько способов запуска асинхронных операций. Наиболее распространённые из них включают использование
AsyncTask (хотя он уже устарел), HandlerThread, AsyncTaskLoader, ExecutorService и современные подходы с использованием Kotlin Coroutines и библиотеки WorkManager.AsyncTask был одним из первых инструментов для выполнения асинхронных задач, однако его использование сейчас не рекомендуется из-за проблем с управлением жизненным циклом и утечками памяти.private class MyAsyncTask extends AsyncTask<Void, Void, String> {
@Override
protected String doInBackground(Void... voids) {
// Выполнение длительной операции
return "Result";
}
@Override
protected void onPostExecute(String result) {
// Обновление UI после завершения операции
}
}
// Запуск
new MyAsyncTask().execute();HandlerThread — это удобный способ создания фонового потока с циклом обработки сообщений.HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
handler.post(new Runnable() {
@Override
public void run() {
// Выполнение длительной операции
}
});ExecutorService из стандартной библиотеки Java предоставляет более гибкий способ управления потоками.ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(new Runnable() {
@Override
public void run() {
// Выполнение длительной операции
}
});
Корутины в Kotlin — это современный и мощный инструмент для асинхронного программирования. Они упрощают работу с асинхронными задачами и обеспечивают безопасность работы с UI.
import kotlinx.coroutines.*
fun performAsyncTask() {
GlobalScope.launch(Dispatchers.IO) {
// Выполнение длительной операции
val result = longRunningTask()
withContext(Dispatchers.Main) {
// Обновление UI после завершения операции
}
}
}
suspend fun longRunningTask(): String {
delay(1000) // Симуляция длительной операции
return "Result"
}
WorkManager — это библиотека для выполнения фоновых задач, которая обеспечивает выполнение задач даже после закрытия приложения или перезагрузки устройства.public class MyWorker extends Worker {
public MyWorker(@NonNull Context context, @NonNull WorkerParameters params) {
super(context, params);
}
@NonNull
@Override
public Result doWork() {
// Выполнение длительной операции
return Result.success();
}
}
// Запуск Worker
WorkManager workManager = WorkManager.getInstance(context);
OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(MyWorker.class).build();
workManager.enqueue(request);RxJava — это библиотека для реактивного программирования, которая также может быть использована для выполнения асинхронных задач.
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.schedulers.Schedulers;
Observable.fromCallable(() -> {
// Выполнение длительной операции
return "Result";
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
// Обновление UI после завершения операции
});
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6❤1👍1
Это центральный поток, который отвечает за управление пользовательским интерфейсом приложения. Этот поток критически важен, потому что именно он обрабатывает все действия пользовательского интерфейса, включая отрисовку вьюх (views), обработку взаимодействий пользователя и выполнение анимаций. Также основной поток обрабатывает системные вызовы, такие как события жизненного цикла активности.
Все события пользовательского интерфейса, такие как нажатия кнопок, касания экрана и другие взаимодействия с пользователем, обрабатываются основным потоком. Это гарантирует, что пользовательский интерфейс отзывчив и изменения отображаются немедленно.
Основной поток исполняет задачи, связанные с пользовательским интерфейсом, такие как обновление видов или выполнение анимаций. Это означает, что любые тяжелые или длительные операции, выполненные в основном потоке, могут "зависнуть" или замедлить интерфейс, делая приложение менее отзывчивым.
Основной поток управляется циклом обработки событий, который непрерывно проверяет наличие новых действий или событий для обработки. Этот цикл, известный как Looper, извлекает события из очереди и отправляет их соответствующим компонентам для обработки.
Чтобы избежать снижения производительности интерфейса, рекомендуется не выполнять тяжелые операции, такие как сетевые запросы или обработка больших объемов данных, непосредственно в основном потоке. Вместо этого такие задачи следует выносить в фоновые потоки с помощью таких инструментов, как AsyncTask, HandlerThreads, или использовать асинхронные библиотеки и фреймворки.
// Создаем новый Handler, привязанный к Looper основного потока
Handler mainHandler = new Handler(Looper.getMainLooper());
mainHandler.post(new Runnable() {
@Override
public void run() {
// Этот код будет выполняться в основном потоке
updateUI();
}
});
public void updateUI() {
// Обновление пользовательского интерфейса
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥2❤1
Это способность программы или операционной системы выполнять несколько задач одновременно в рамках одного процесса. Эти задачи, известные как потоки, работают параллельно и могут управлять различными частями программы, что ускоряет выполнение задач и повышает эффективность использования ресурсов компьютера.
Это легковесный процесс, который может выполняться независимо. В рамках одного процесса может существовать множество потоков, каждый из которых имеет доступ к ресурсам процесса.
Позволяет достичь параллелизма (одновременное выполнение) и конкурентности (эффективное переключение между задачами в условиях ограниченных ресурсов).
Поскольку потоки делят общие ресурсы, возникает необходимость в синхронизации доступа к этим ресурсам, чтобы избежать конфликтов и ошибок, таких как "гонки за ресурсы" (race conditions). Для управления доступом используются различные механизмы синхронизации, такие как мьютексы, семафоры и мониторы.
Возникает, когда два или более потоков взаимно блокируют друг друга, ожидая освобождения ресурсов. Голодание происходит, когда один или несколько потоков не получают доступ к необходимым ресурсам в течение длительного времени.
public class MultithreadingExample {
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("Поток 1: " + i);
try {
Thread.sleep(50); // Имитация выполнения работы
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("Поток 2: " + i);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
thread1.start();
thread2.start();
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5
Выбор Android-разработки предоставляет целый ряд преимуществ, как для разработчиков, так и для бизнеса.
Является самой популярной мобильной операционной системой в мире, что обеспечивает доступ к широкой аудитории. Приложения могут достичь значительного числа пользователей по всему миру, увеличивая потенциальные рыночные возможности.
Предоставляет больше гибкости в плане настройки приложений и интеграции с операционной системой. Это открытая платформа, что позволяет экспериментировать и внедрять новшества с меньшим количеством ограничений по сравнению с другими операционными системами.
Предоставляют разработчикам мощные инструменты для создания, тестирования и отладки приложений. Kotlin, который стал основным для Android-разработки, предлагает современные возможности и улучшает производительность и читаемость кода по сравнению с Java.
Работает на множестве устройств с различными размерами экрана и характеристиками, что дает возможность охватить более широкий спектр рынка. Однако это также создает вызовы, связанные с адаптацией приложений под разные устройства.
Тесно интегрирован с Google Services, такими как Google Drive, Google Maps и другими. Это предоставляет легкий доступ к мощным инструментам и API, которые могут значительно расширить функциональность приложений.
Приложения можно распространять не только через Google Play Market. Существуют альтернативные магазины приложений и платформы, что предоставляет больше вариантов монетизации и распространения своих продуктов.
Имеет одно из самых больших сообществ разработчиков, что означает обширную поддержку, большое количество ресурсов, форумов, блогов и документации, которые могут помочь новым и опытным разработчикам.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3❤1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥3
В Android передача данных между Activity осуществляется через механизм Intent. Intent — это объект, который позволяет передавать данные и запускать компоненты, такие как Activity, Service и BroadcastReceiver.
В первой Activity создайте Intent и добавьте данные, которые хотите передать, используя методы
putExtra.// MainActivity.java
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.putExtra("key", "value"); // передаем строку
intent.putExtra("number", 123); // передаем целое число
startActivity(intent);
Во второй Activity получите Intent, который запустил эту Activity, и извлеките данные из него.
// SecondActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
// Получение Intent и извлечение данных
Intent intent = getIntent();
String value = intent.getStringExtra("key");
int number = intent.getIntExtra("number", 0); // 0 - значение по умолчанию
// Использование полученных данных
TextView textView = findViewById(R.id.textView);
textView.setText("String: " + value + ", Number: " + number);
}
Если вам нужно передать сложные объекты, вы можете использовать интерфейс
Parcelable. Этот интерфейс позволяет сериализовать объекты для передачи через Intent.import android.os.Parcel;
import android.os.Parcelable;
public class User implements Parcelable {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
protected User(Parcel in) {
name = in.readString();
age = in.readInt();
}
public static final Creator<User> CREATOR = new Creator<User>() {
@Override
public User createFromParcel(Parcel in) {
return new User(in);
}
@Override
public User[] newArray(int size) {
return new User[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeString(name);
parcel.writeInt(age);
}
// Getters and setters (если нужны)
}
// MainActivity.java
User user = new User("John", 30);
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.putExtra("user", user);
startActivity(intent);
// SecondActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
Intent intent = getIntent();
User user = intent.getParcelableExtra("user");
// Использование полученного объекта
if (user != null) {
TextView textView = findViewById(R.id.textView);
textView.setText("Name: " + user.getName() + ", Age: " + user.getAge());
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤1
1. Связанные списки (chaining): элементы с одинаковым хешем помещаются в один bucket в виде связанного списка.
2. Сбалансированные деревья: современные реализации (например, в Java) используют деревья вместо списков для ускорения поиска при большом количестве коллизий.
3. Метод equals используется для проверки уникальности ключей в случае совпадения хеша.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥2
Это популярная библиотека для внедрения зависимостей в Java и Android приложениях. Инжект в поле при помощи Dagger позволяет автоматически управлять зависимостями, что упрощает код и делает его более чистым и удобным для тестирования.
Dagger автоматически управляет созданием и предоставлением экземпляров зависимостей, что упрощает и улучшает структуру кода.
Использование Dagger позволяет избежать написания большого количества шаблонного кода, связанного с созданием и управлением зависимостями вручную.
Dagger поддерживает различные области видимости (например,
@Singleton), что позволяет контролировать жизненный цикл зависимостей.Внедрение зависимостей через Dagger упрощает тестирование кода, так как зависимости можно легко замокать (заменить на тестовые версии).
@Inject для полей, в которые нужно внедрить зависимости.import dagger.Module;
import dagger.Provides;
@Module
public class NetworkModule {
@Provides
@Singleton
public NetworkService provideNetworkService() {
return new NetworkServiceImpl();
}
}
import dagger.Component;
import javax.inject.Singleton;
@Singleton
@Component(modules = {NetworkModule.class})
public interface AppComponent {
void inject(MainActivity mainActivity);
}
import javax.inject.Inject;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
@Inject
NetworkService networkService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Получение компонента и инжект зависимостей
((MyApplication) getApplication()).getAppComponent().inject(this);
// Теперь networkService можно использовать
networkService.performRequest();
}
}
import android.app.Application;
public class MyApplication extends Application {
private AppComponent appComponent;
@Override
public void onCreate() {
super.onCreate();
// Создание Dagger-компонента
appComponent = DaggerAppComponent.builder()
.networkModule(new NetworkModule())
.build();
}
public AppComponent getAppComponent() {
return appComponent;
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
1. Компилятор принимает решение на основе размера функции и оптимизации производительности.
2. Рекурсивные функции или сложные конструкции не могут быть встроены, так как это может вызвать ошибки или увеличенный размер кода.
3. Принудительное использование inline директив возможно, но это не всегда эффективно.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2😁2
В Kotlin,
companion object (объект-компаньон) используется для создания статических членов класса. Этот объект инициализируется при первом доступе к нему. companion object инициализируется лениво, то есть при первом обращении к любому из его членов. Это помогает избежать ненужных затрат ресурсов до тех пор, пока эти члены не понадобятся.По сути,
companion object работает как статический объект в Java, предоставляя статические методы и свойства.Пример использования
class MyClass {
companion object {
val staticProperty: String = "Hello, World!"
fun staticMethod() {
println("Static Method Called")
}
init {
println("Companion object is initialized")
}
}
}Пример инициализации
fun main() {
println("Before accessing companion object")
// Первое обращение к companion object
println(MyClass.staticProperty)
// Еще одно обращение к companion object
MyClass.staticMethod()
}Вывод программы
Before accessing companion object
Companion object is initialized
Hello, World!
Static Method Called
companion object можно называть, что позволяет иметь несколько объектов-компаньонов в одном классе, хотя это редко используется.class MyClass {
companion object NamedCompanion {
// Члены и методы
}
}companion object может реализовывать интерфейсы.interface MyInterface {
fun doSomething()
}
class MyClass {
companion object : MyInterface {
override fun doSomething() {
println("Doing something")
}
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13
2. В некоторых случаях может понадобиться использование ContentProvider, который инициализируется до Application.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥2🤯1
В Android приложениях можно использовать различные базы данных для хранения данных.
Является встроенной реляционной базой данных, которая поставляется вместе с Android. Это легковесная база данных, не требующая настройки сервера.
Плюсы и минусы
public class MyDatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "mydatabase.db";
private static final int DATABASE_VERSION = 1;
public MyDatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE mytable (id INTEGER PRIMARY KEY, name TEXT)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS mytable");
onCreate(db);
}
}Это библиотека, предоставляющая слой абстракции поверх SQLite. Она облегчает работу с базой данных, предоставляя удобный API и поддержку проверки запросов во время компиляции.
Плюсы и минусы
Пример использования
@Entity
public class User {
@PrimaryKey
public int uid;
public String firstName;
public String lastName;
}
@Dao
public interface UserDao {
@Query("SELECT * FROM user")
List<User> getAll();
@Insert
void insertAll(User... users);
}
@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract UserDao userDao();
}
Это современная база данных, созданная специально для мобильных приложений. Она имеет собственный движок и API, отличное от традиционных реляционных баз данных.
Плюсы и минусы
Пример использования
public class User extends RealmObject {
@PrimaryKey
private int id;
private String name;
// getters and setters
}
// Использование
Realm realm = Realm.getDefaultInstance();
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
User user = realm.createObject(User.class, 1);
user.setName("John Doe");
}
});Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
1. Примитивы: int, float, boolean, double.
2. Строки и массивы примитивов.
3. Сериализуемые или Parcelable объекты.
4. Для больших данных, например, файлов, лучше использовать ссылки или путь к данным.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1
Это абстрактная структура данных, работающая по принципу "последний вошел — первый вышел" (LIFO, Last In First Out). Это означает, что последний добавленный элемент будет первым, который будет удален.
добавление элемента на вершину стека.
удаление элемента с вершины стека.
добавляет элемент
item на вершину стека.удаляет и возвращает элемент с вершины стека.
возвращает элемент на вершине стека, но не удаляет его.
проверяет, пуст ли стек.
возвращает количество элементов в стеке.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5