HashMap — это структура данных, которая использует хеш-таблицу для хранения пар "ключ-значение". Она позволяет выполнять операции вставки, удаления и поиска элементов с почти постоянным временем выполнения, что делает её очень эффективной для определённых задач. Вот как она работает:
HashMap использует хеш-функцию для вычисления хеш-кода ключа. Хеш-код затем используется для определения индекса в массиве, где будет храниться значение. Это позволяет быстро находить значения по ключам.HashMap разрешает такие коллизии, сохраняя эти элементы в одной "корзине" или "ячейке" в виде списка (до Java 8 использовались связанные списки, начиная с Java 8 — сбалансированные деревья при большом количестве коллизий в одной корзине).HashMap вычисляет индекс корзины для ключа и помещает значение в эту корзину. При поиске значения по ключу HashMap снова вычисляет индекс, находит соответствующую корзину и затем перебирает элементы в ней, чтобы найти нужное значение.HashMap достигает определённого порога заполнения (загрузки), размер массива увеличивается, и все существующие элементы перераспределяются в новом массиве. Это необходимо для поддержания эффективности операций вставки и поиска.Представьте, что у вас есть
HashMap, где ключи — это имена пользователей, а значения — это их email. Когда вы добавляете новую пару "ключ-значение" ("John Doe", "[email protected]"), HashMap выполняет следующие действия:"John Doe"."[email protected]" в корзину этого индекса.Когда вы пытаетесь найти email по имени
"John Doe", HashMap снова вычисляет хеш-код для "John Doe", находит соответствующую корзину и возвращает сохранённый в ней email.HashMap — это структура данных, использующая хеш-таблицу для эффективного хранения и поиска пар "ключ-значение". Она вычисляет хеш-коды ключей для быстрого нахождения значений, разрешает коллизии и автоматически масштабируется для поддержания своей эффективности.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3❤1
Anonymous Quiz
10%
0
38%
1
8%
Множественные
44%
Зависит от контекста
🤔4👍1
Существуют специальные типы Any, Unit и Nothing, которые имеют уникальные цели и применения в языке программирования:
Object. Любой объект, за исключением null, наследуется от Any. Этот тип обычно используется там, где требуется представление любого возможного значения, за исключением null. Any определяет несколько базовых методов, таких как equals(), hashCode() и toString(), которые могут быть переопределены.fun printAnyObject(obj: Any) {
println(obj.toString())
}void, но в отличие от void, он является полноценным объектом. Функции в Kotlin, которые не возвращают значимый результат, на самом деле возвращают Unit. Этот тип обычно используется для указания, что функция выполняет действие, но не возвращает значение. Хотя возвращаемый тип Unit обычно опускается, его можно указать явно.fun printHello(): Unit {
println("Hello, World!")
}fun failWithErrorMessage(message: String): Nothing {
throw IllegalArgumentException(message)
}Использование
Nothing полезно для анализа потока выполнения программы, поскольку компилятор распознает, что код после вызова функции, возвращающей Nothing, никогда не будет выполнен.Any — это базовый тип для всех объектов в Kotlin, кроме null.Unit указывает, что функция не возвращает полезное значение, аналогично void в других языках программирования, но является объектом.Nothing используется для обозначения "невозможности" выполнения кода после определённой точки, например, после выброса исключения.Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Anonymous Quiz
18%
async
3%
await
67%
suspend
12%
coroutine
😁2🤯2👾1
Класс Nothing имеет уникальное и очень специфическое назначение. Он представляет тип, который не имеет значений и используется для обозначения операций, которые никогда не завершаются нормально. Вот несколько ключевых причин, почему данный тип полезен:
Nothing ясно демонстрирует этот намеренный аспект поведения функции.Nothing, для вывода о том, что последующий код недостижим. Это может помочь в оптимизации кода и предотвращении ошибок.fun throwError(message: String): Nothing {
throw IllegalArgumentException(message)
}В этом случае он указывает, что после вызова
throwError выполнение текущей функции не будет продолжено. Это позволяет компилятору правильно анализировать поток выполнения программы и разработчикам легче понять поведение кода.Nothing — это тип без значений, который используется для обозначения операций, не имеющих нормального завершения. Это предоставляет дополнительные возможности для управления потоком выполнения программы, статического анализа и улучшения понимания кода.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2❤1
Anonymous Quiz
12%
convert
15%
transform
58%
map
16%
cast
🤯2
Сериализация – это процесс преобразования объекта в поток байтов для сохранения его состояния или передачи его через сеть. Это нужно, чтобы можно было хранить объекты в файлы, базы данных или передавать их между разными компонентами приложения или даже разными приложениями.
Когда мы работаем с объектами в приложении, они находятся в оперативной памяти. Но, если нужно сохранить состояние объекта между запусками программы или передать его через сеть, нам нужно как-то его "упаковать". Вот тут и приходит на помощь сериализация. Например, вы можете сериализовать объект, сохранить его в файл, а потом прочитать этот файл и десериализовать объект обратно.
В Android для сериализации часто используется интерфейс
Serializable или Parcelable. Вот пример использования Serializable:import java.io.Serializable;
public class User implements Serializable {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
// геттеры и сеттеры
}
Чтобы сериализовать объект
User и сохранить его в файл, можно сделать так:User user = new User("John", 30);
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.ser"))) {
oos.writeObject(user);
} catch (IOException e) {
e.printStackTrace();
}Для десериализации объекта из файла:
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.ser"))) {
User user = (User) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}Parcelable предпочтительнее в Android, так как он быстрее работает по сравнению с Serializable.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 dest, int flags) {
dest.writeString(name);
dest.writeInt(age);
}
// геттеры и сеттеры
}
Теперь можно передавать объект
User между активити:Intent intent = new Intent(this, AnotherActivity.class);
User user = new User("John", 30);
intent.putExtra("user", user);
startActivity(intent);
И получить его в
AnotherActivity:User user = getIntent().getParcelableExtra("user");Сериализация – это способ сохранения или передачи объектов, преобразовывая их в поток байтов. В Android можно использовать
Serializable или Parcelable для этих целей.Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤1
Anonymous Quiz
70%
private constructor
8%
private init
16%
private class
6%
private fun
Подключение
BroadcastReceiver в Android состоит из двух основных шагов: создание самого ресивера и его регистрация. Ресивер можно зарегистрировать как статически в манифесте, так и динамически в коде.Создадим простой
BroadcastReceiver, который будет реагировать на определённое событие, например, на получение SMS.import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Сообщение получено!", Toast.LENGTH_SHORT).show();
}
}
Можно зарегистрировать ресивер в файле
AndroidManifest.xml. Это удобно, когда вы хотите, чтобы ресивер всегда был активен и слушал определённые системные события, например, перезагрузку устройства или получение SMS.<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="com.example.myapp">
<application
android:allowBackup="true"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<receiver android:name=".MyBroadcastReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
</application>
</manifest>
Иногда нужно регистрировать ресивер только на время выполнения определённой активности или службы. В этом случае лучше использовать динамическую регистрацию.
import android.content.IntentFilter;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private MyBroadcastReceiver myBroadcastReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myBroadcastReceiver = new MyBroadcastReceiver();
}
@Override
protected void onStart() {
super.onStart();
IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
registerReceiver(myBroadcastReceiver, filter);
}
@Override
protected void onStop() {
super.onStop();
unregisterReceiver(myBroadcastReceiver);
}
}
В этом примере ресивер регистрируется в методе
onStart() и отписывается в методе onStop(). Это позволяет ресиверу быть активным только тогда, когда активность видима.Чтобы подключить
BroadcastReceiver, создайте его и зарегистрируйте либо в манифесте, либо в коде. Статическая регистрация через манифест делает ресивер активным всегда, а динамическая регистрация в коде позволяет контролировать время его активности.Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥4
Anonymous Quiz
5%
Int
28%
String
53%
Boolean
14%
Long
🤯3
В Android-приложениях существует несколько типов хранилищ данных, каждый из которых подходит для различных сценариев и требований к данным. Основные типы хранилищ данных в Android включают:
String filename = "myfile";
String fileContents = "Hello, World!";
FileOutputStream fos = openFileOutput(filename, Context.MODE_PRIVATE);
fos.write(fileContents.getBytes());
fos.close();
// Чтение данных
FileInputStream fis = openFileInput(filename);
int c;
StringBuilder temp = new StringBuilder();
while( (c = fis.read()) != -1) {
temp.append((char)c);
}
fis.close();
String filename = "myfile.txt";
String fileContents = "Hello, World!";
File file = new File(getExternalFilesDir(null), filename);
FileOutputStream fos = new FileOutputStream(file);
fos.write(fileContents.getBytes());
fos.close();
// Чтение данных
FileInputStream fis = new FileInputStream(file);
int c;
StringBuilder temp = new StringBuilder();
while( (c = fis.read()) != -1) {
temp.append((char)c);
}
fis.close();
Cursor cursor = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
while (cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
}
cursor.close();
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Anonymous Quiz
50%
abstract
19%
open
31%
override
0%
final
StateFlow – это специальный тип потока данных, используемый в Kotlin и библиотеке Kotlin Coroutines. Он предназначен для управления состоянием и передачи данных в реальном времени в реактивных приложениях. StateFlow основан на концепции потоков данных, аналогичной LiveData в Android, но с улучшенной поддержкой сопрограмм.StateFlow всегда активен и хранит последнее значение состояния. Подписчики получают текущее состояние немедленно после подписки.StateFlow поддерживает изменение состояния через методы value или emit.StateFlow помогает создавать реактивные и асинхронные приложения, где состояние может изменяться динамически и пользователи получают обновления в реальном времени.LiveData, StateFlow требует начальное состояние, что делает его состояние всегда предсказуемым и никогда не null.LiveData.Для создания
StateFlow используется MutableStateFlow, который позволяет изменять его значение:import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
class MyViewModel : ViewModel() {
private val _state = MutableStateFlow("Initial State")
val state: StateFlow<String> get() = _state
fun updateState(newState: String) {
_state.value = newState
}
}
import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
class CounterActivity : AppCompatActivity() {
private val viewModel: CounterViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_counter)
// Подписка на StateFlow
lifecycleScope.launch {
viewModel.count.collect { count ->
// Обновляем UI
textView.text = count.toString()
}
}
// Пример использования методов инкремента и декремента
incrementButton.setOnClickListener {
viewModel.increment()
}
decrementButton.setOnClickListener {
viewModel.decrement()
}
}
}
StateFlow – это поток данных для управления состоянием в Kotlin, который всегда содержит последнее состояние и работает с сопрограммами. Он используется для реактивного программирования, обеспечивая предсказуемое и синхронизированное обновление состояния в приложении.Please open Telegram to view this post
VIEW IN TELEGRAM
👍6👀1
Anonymous Quiz
14%
Ошибка компиляции
3%
Ошибка выполнения
6%
Параметр принимает значение null
77%
Используется значение по умолчанию
Для работы с сетью в Android используются различные библиотеки и инструменты, обеспечивающие выполнение сетевых запросов, обработку ответов, и управление асинхронными операциями. Наиболее популярные и широко используемые инструменты включают:
new Thread(() -> {
try {
URL url = new URL("https://api.example.com/data");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
// Обработка ответа
} finally {
urlConnection.disconnect();
}
} catch (Exception e) {
e.printStackTrace();
}
}).start();
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://api.example.com/data")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
String responseData = response.body().string();
// Обработка ответа
}
}
});
Для работы с сетью в Android можно использовать
HttpURLConnection для простых задач, а также сторонние библиотеки, такие как OkHttp, Retrofit, Volley и Ktor, для более сложных и мощных сетевых операций. Эти инструменты помогают управлять HTTP-запросами, обрабатывать ответы и поддерживать асинхронные операции.Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Anonymous Quiz
52%
open
23%
override
0%
final
25%
abstract
Чтобы делать сетевые запросы с помощью Retrofit, следуйте этим шагам:
Сначала добавьте зависимости для Retrofit и конвертера JSON в файл
build.gradle вашего проекта:dependencies {
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
}Создайте класс, который будет представлять данные, полученные от API. Например, если ваш API возвращает информацию о пользователях, создайте класс
User:public class User {
private String name;
private String email;
// Геттеры и сеттеры
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}Создайте интерфейс, который описывает HTTP-запросы. Используйте аннотации Retrofit для указания типа запроса и конечной точки:
import retrofit2.Call;
import retrofit2.http.GET;
import java.util.List;
public interface ApiService {
@GET("users")
Call<List<User>> getUsers();
}
Создайте экземпляр Retrofit в вашем приложении. Обычно это делается в классе
Application или в отдельном синглтоне:import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class ApiClient {
private static final String BASE_URL = "https://api.example.com/";
private static Retrofit retrofit = null;
public static Retrofit getClient() {
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
Теперь вы можете использовать созданный
ApiService для выполнения сетевых запросов. Это обычно делается в активити или во ViewModel:import android.os.Bundle;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private ApiService apiService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
apiService = ApiClient.getClient().create(ApiService.class);
fetchUsers();
}
private void fetchUsers() {
Call<List<User>> call = apiService.getUsers();
call.enqueue(new Callback<List<User>>() {
@Override
public void onResponse(Call<List<User>> call, Response<List<User>> response) {
if (response.isSuccessful()) {
List<User> users = response.body();
// Обработка полученных данных
for (User user : users) {
Toast.makeText(MainActivity.this, "User: " + user.getName(), Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(MainActivity.this, "Response Error " + response.code(), Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<List<User>> call, Throwable t) {
Toast.makeText(MainActivity.this, "Network Error: " + t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1
Anonymous Quiz
52%
G1
21%
CMS
9%
Serial
18%
ZGC
👀8
Runtime (время выполнения) в контексте Android — это среда, в которой исполняется приложение. Она отвечает за выполнение кода, управление памятью и взаимодействие с операционной системой. В Android runtime включает такие компоненты, как:
Рассмотрим простой пример создания и использования объекта в Java:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Создание нового объекта
Person person = new Person("John", 30);
// Вызов метода объекта
String details = person.getDetails();
Log.d("MainActivity", details);
}
}
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getDetails() {
return "Name: " + name + ", Age: " + age;
}
}В этом примере:
MainActivity и Person.onCreate, создавая объект Person и вызывая его метод getDetails.Person и освобождает её, когда объект больше не нужен (например, при завершении активности или сборке мусора).NullPointerException), Runtime обработал бы его и вызвал соответствующий обработчик исключений.Runtime в Android отвечает за выполнение кода приложения, управление памятью, загрузку классов, обеспечение безопасности и обработку исключений. ART (Android Runtime) является текущей реализацией runtime в Android и предлагает улучшенную производительность и управление памятью по сравнению с предыдущей версией (Dalvik).
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Anonymous Quiz
28%
CoroutineDispatcher
13%
ContinuationInterceptor
47%
Continuation
13%
SuspendFunction