Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5
Да, в Kotlin возможно получить
NullPointerException (NPE), несмотря на его сильную систему типов, которая стремится избежать null-значений. Kotlin делает много для предотвращения NullPointerException, но есть определенные случаи, когда NPE все еще может возникнуть.При вызове методов из Java, которые могут возвращать
null без соответствующей аннотации, Kotlin не может гарантировать отсутствие null.val list = java.util.ArrayList<String>()
list.add("Hello")
val size = list.size // Java-код, возвращающий потенциальный null
Оператор
!! явно указывает компилятору, что переменная не может быть null, но если она все же null, будет выброшено NullPointerException.val name: String? = null
val length = name!!.length // NPE если name == null
Переменные, помеченные как
lateinit, должны быть инициализированы перед использованием. Если переменная не была инициализирована и используется, будет выброшено UninitializedPropertyAccessException, что является подтипом RuntimeException.lateinit var name: String
fun initializeName() {
name = "Kotlin"
}
fun useName() {
println(name.length) // NPE если name не инициализирован
}
Статические инициализаторы могут быть источником
NullPointerException в случае неправильного порядка инициализации.object Example {
val name: String? = null
val length = name!!.length // NPE при инициализации объекта
}Kotlin-коррутины и потоки могут привести к NPE, если происходят необработанные исключения, особенно при работе с
ThreadLocal переменными.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🤔1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3👍2
Для обеспечения безопасности при работе с Java-кодом в Kotlin можно применять несколько стратегий и подходов, которые помогут избежать
NullPointerException (NPE) и других потенциальных проблем. Использование аннотаций в Java-коде помогает Kotlin понять, какие значения могут быть
null, а какие — нет. Наиболее распространенные аннотации включают @Nullable и @NotNull.Java-код
import org.jetbrains.annotations.Nullable;
public class JavaExample {
@Nullable
public static String getNullableString() {
return null;
}
}
Kotlin-код
val result: String? = JavaExample.getNullableString()
result?.let {
println(it.length)
}
Безопасный вызов и оператор Элвиса помогают обрабатывать потенциально
null значения безопасно.val result: String? = JavaExample.getNullableString()
val length = result?.length ?: 0
println("Length: $length")
Перед использованием значений, полученных из Java-кода, можно проверять их на
null.val result: String? = JavaExample.getNullableString()
if (result != null) {
println(result.length)
} else {
println("Result is null")
}
Обработка исключений помогает избежать непредвиденных ситуаций, когда Java-код может бросить исключение.
try {
val result = JavaExample.getNullableString()
println(result!!.length)
} catch (e: NullPointerException) {
println("Caught a NullPointerException")
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3❤1
Anonymous Quiz
25%
httpClient.get()
9%
httpRequest.send()
46%
httpClient.request()
20%
httpRequest.execute()
Переменные по умолчанию не могут быть
null, что предотвращает NullPointerException.var a: String = "abc"
var b: String? = "abc"
b = null // Допустимо
Разделение на изменяемые и неизменяемые коллекции.
val list: List<String> = listOf("a", "b", "c") // Неизменяемый список
val mutableList: MutableList<String> = mutableListOf("a", "b", "c") // Изменяемый список Автоматическое создание методов
equals(), hashCode(), и toString().data class User(val name: String, val age: Int)
Автоматическое приведение типа после проверки с помощью
is.fun demo(x: Any) {
if (x is String) {
println(x.length)
}
} Упрощают обработку ограниченных иерархий классов.
sealed class Expr
data class Const(val number: Double) : Expr()
Kotlin автоматически определяет тип переменной.
val x = 10 // Int
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10
2. Bundle: сохранение состояния через onSaveInstanceState() и восстановление в onCreate() или onViewStateRestored().
3. SharedPreferences: для сохранения небольших данных между запусками приложения.
4. Базы данных или файлы: для долгосрочного хранения больших объёмов данных.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥1
Java: Все объекты могут быть
null, что приводит к NullPointerException.String s = null;
int length = s.length(); // NullPointerException
Kotlin: По умолчанию переменные не могут быть null. Для допуска null используется ?.
var s: String? = null
val length = s?.length // Вернет null, если s равно null
Java: Нет различия между изменяемыми и неизменяемыми коллекциями.
List<String> list = new ArrayList<>();
list.add("a");
Kotlin: Четкое разделение на изменяемые (
MutableList) и неизменяемые (List) коллекции.val immutableList: List<String> = listOf("a", "b", "c")
val mutableList: MutableList<String> = mutableListOf("a", "b", "c")Java: Нужно вручную переопределять equals(), hashCode(), и toString().
public class User {
private String name;
private int age;
// Конструктор, геттеры, сеттеры, equals(), hashCode(), toString()
}Kotlin: Автоматическая генерация этих методов.
data class User(val name: String, val age: Int)
Java: Необходимость явного указания типов.
int x = 10;
String s = "Hello";
Kotlin: Автоматическое выведение типов.
val x = 10 // Int
val s = "Hello" // String
Java: Необходимость явного приведения после проверки instanceof.
if (obj instanceof String) {
String s = (String) obj;
System.out.println(s.length());
}Kotlin: Автоматическое приведение типа после проверки is.
if (obj is String) {
println(obj.length) // obj приводится к String
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥1
Автоматически генерируют методы equals(), hashCode(), toString(), copy().
data class User(val name: String, val age: Int)
Ограничивают иерархию классов, обеспечивая безопасность при работе с альтернативами.
sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
Создают ограниченные множества констант.
enum class Direction {
NORTH, SOUTH, EAST, WEST
}Используют object для создания единственного экземпляра.
object Database {
fun connect() { /*...*/ }
} Позволяют определять члены, доступные без экземпляра класса.
class MyClass {
companion object {
fun create(): MyClass = MyClass()
}
}Обеспечивают легковесные типы без накладных расходов на уровень объекта.
inline class Password(val value: String)
Поддерживают передачу функций как параметров и их возврат.
fun performOperation(x: Int, y: Int, operation: (Int, Int) -> Int): Int {
return operation(x, y)
} Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2👍1
Для сохранения данных за пределами фрагмента в Android можно использовать несколько методов. Основные способы включают SharedPreferences, базы данных SQLite, Room, файлы и ViewModel с ViewModelFactory.
Используется для хранения небольших порций данных в виде пар "ключ-значение". Это удобно для хранения настроек пользователя или состояния приложения.
// Сохранение данных
SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString("key", "value");
editor.apply();
// Чтение данных
SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
String value = sharedPref.getString("key", "default_value");
Это встроенная реляционная база данных, которая позволяет хранить структурированные данные. Для работы с ней используются SQL-запросы.
// Создание базы данных
SQLiteDatabase db = getActivity().openOrCreateDatabase("MyDatabase", Context.MODE_PRIVATE, null);
db.execSQL("CREATE TABLE IF NOT EXISTS myTable (id INTEGER PRIMARY KEY, name TEXT)");
// Вставка данных
ContentValues values = new ContentValues();
values.put("name", "value");
db.insert("myTable", null, values);
// Чтение данных
Cursor cursor = db.rawQuery("SELECT * FROM myTable", null);
if (cursor.moveToFirst()) {
String name = cursor.getString(cursor.getColumnIndex("name"));
}
cursor.close();
Это библиотека, которая упрощает работу с SQLite, предоставляя абстракцию в виде аннотаций и DAO (Data Access Objects).
// Entity
@Entity
public class User {
@PrimaryKey
public int uid;
@ColumnInfo(name = "first_name")
public String firstName;
@ColumnInfo(name = "last_name")
public String lastName;
}
// DAO
@Dao
public interface UserDao {
@Insert
void insert(User user);
@Query("SELECT * FROM user")
List<User> getAll();
}
// Database
@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract UserDao userDao();
}
// Использование
AppDatabase db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "database-name").build();
UserDao userDao = db.userDao();
User user = new User();
user.uid = 1;
user.firstName = "John";
user.lastName = "Doe";
userDao.insert(user);
List<User> users = userDao.getAll();
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
•Это может случиться из-за циклических ссылок или неправильно управляемых ресурсов.
•Утечки памяти приводят к увеличению потребления памяти и ухудшению производительности приложения.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥1
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