Подключение
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
В Java лямбда-выражения имеют тип, который называется функциональным интерфейсом. Функциональный интерфейс — это интерфейс, который содержит только один абстрактный метод. Этот интерфейс может также содержать статические и по умолчанию (default) методы, но он должен иметь только один абстрактный метод, который определяет тип лямбда-выражения.
Java предоставляет несколько стандартных функциональных интерфейсов в пакете
java.util.function, таких как Function, Consumer, Supplier, и Predicate. Вы также можете создать свой собственный функциональный интерфейс.R apply(T t)Function<String, Integer> stringLength = s -> s.length();
void accept(T t)Consumer<String> print = s -> System.out.println(s);
T get()Supplier<Double> randomValue = () -> Math.random();
boolean test(T t)Predicate<Integer> isEven = i -> i % 2 == 0;
Вы можете создать свой собственный функциональный интерфейс, используя аннотацию
@FunctionalInterface (необязательно, но рекомендуется):@FunctionalInterface
public interface MyFunctionalInterface {
void myMethod();
}
public class Main {
public static void main(String[] args) {
MyFunctionalInterface myFunction = () -> System.out.println("Hello, World!");
myFunction.myMethod(); // Вывод: Hello, World!
}
}
Когда вы создаете лямбда-выражение, Java автоматически сопоставляет его с абстрактным методом функционального интерфейса. Лямбда-выражение должно соответствовать параметрам и возвращаемому типу этого метода.
Например, в следующем коде лямбда-выражение соответствует методу
apply интерфейса Function:Function<String, Integer> stringLength = s -> s.length();
Рассмотрим более полный пример с использованием функционального интерфейса
Function:import java.util.function.Function;
public class Main {
public static void main(String[] args) {
Function<String, Integer> stringLength = s -> s.length();
String testString = "Hello, World!";
Integer length = stringLength.apply(testString);
System.out.println("Length of the string: " + length); // Вывод: Length of the string: 13
}
}
Лямбда-выражения в Java имеют тип, называемый функциональным интерфейсом, который содержит только один абстрактный метод. Функциональные интерфейсы предоставляют способ описания сигнатуры лямбда-выражений и являются основой для работы с лямбдами в Java.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1👀1
Anonymous Quiz
61%
Unit
15%
Any
11%
Nothing
13%
Lambda
При передаче лямбда-выражений из Java в методы, написанные на Kotlin, существуют несколько потенциальных опасностей и проблем, которые необходимо учитывать. Некоторые из них включают:
В Kotlin строгая система типов, которая различает nullable и non-nullable типы. Java, в свою очередь, не имеет этой особенности, что может привести к проблемам при передаче лямбда-выражений.
Kotlin:
fun performAction(action: () -> Unit) {
action()
}Java:
public class Main {
public static void main(String[] args) {
MainKt.performAction(null); // NullPointerException
}
}В этом примере, если передать
null в метод performAction, это вызовет NullPointerException, так как Kotlin ожидает, что параметр action не будет null.Java компилятор может не поймать все ошибки, которые Kotlin компилятор обнаружил бы при использовании лямбда-выражений.
Kotlin:
fun transformData(transform: (String) -> Int): Int {
return transform("Kotlin")
}Java:
public class Main {
public static void main(String[] args) {
// Ошибка не будет обнаружена компилятором Java
int result = MainKt.transformData(str -> str.length()); // Ошибка при выполнении, если str будет null
}
}При использовании функциональных интерфейсов необходимо убедиться, что типы параметров и возвращаемые типы лямбда-выражений совпадают с ожидаемыми типами в Kotlin.
Kotlin:
fun executeOperation(operation: (Int, Int) -> Int): Int {
return operation(3, 4)
}Java:
public class Main {
public static void main(String[] args) {
// Типы должны совпадать с ожидаемыми в Kotlin
int result = MainKt.executeOperation((a, b) -> a + b);
}
}Кotlin предоставляет более строгую систему проверок типов, и отсутствие этих проверок в Java может привести к потенциальным ошибкам времени выполнения.
Kotlin:
fun processData(processor: (String) -> String) {
val result = processor("Kotlin")
println(result)
}Java:
public class Main {
public static void main(String[] args) {
// Неверное приведение типов не будет обнаружено компилятором Java
MainKt.processData(str -> (String) str.toUpperCase()); // ClassCastException при выполнении, если str будет null
}
}В Java отсутствуют аннотации на уровне типов, указывающие, может ли параметр или возвращаемое значение быть
null. Это может привести к ошибкам в Kotlin, где такие соглашения строго соблюдаются.Kotlin:
fun processString(processor: (String) -> String?) {
val result = processor("Kotlin")
println(result?.length)
}Java:
public class Main {
public static void main(String[] args) {
MainKt.processString(str -> null); // Возможный NPE, если Kotlin не учтет возможность null
}
}При передаче лямбда-выражений из Java в Kotlin нужно быть внимательным к:
null.При передаче лямбда-выражений из Java в Kotlin могут возникать проблемы с
null, несовпадением типов и отсутствием строгих проверок типов на стороне Java. Будьте осторожны с типами и проверками на null, чтобы избежать ошибок.Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Anonymous Quiz
12%
3.33
13%
3.0
73%
3
2%
Исключение
В архитектурных компонентах Android для сохранения состояния ViewModel используется специальный класс
SavedStateHandle. Этот класс позволяет сохранить и восстановить состояние ViewModel при изменении конфигурации (например, при повороте экрана) или при пересоздании активности или фрагмента.Убедитесь, что в вашем проекте добавлена зависимость на архитектурные компоненты Android:
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:2.3.1"
Для использования
SavedStateHandle в вашей ViewModel, убедитесь, что ваш ViewModel принимает его в конструкторе. Это можно сделать, используя фабрику ViewModel при создании ViewModel.import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
class MyViewModel(private val state: SavedStateHandle) : ViewModel() {
// Ключ для сохранения и восстановления состояния
private val MY_STATE_KEY = "my_state_key"
// Получение значения из SavedStateHandle
var myValue: String?
get() = state.get(MY_STATE_KEY)
set(value) {
state.set(MY_STATE_KEY, value)
}
// Инициализация состояния
init {
if (!state.contains(MY_STATE_KEY)) {
myValue = "Initial Value"
}
}
}
import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
class MainActivity : AppCompatActivity() {
private val myViewModel: MyViewModel by viewModels {
object : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return MyViewModel(defaultSavedStateHandle) as T
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
myViewModel.myLiveData.observe(this, { value ->
println("Observed value: $value")
})
// Установка нового значения
myViewModel.updateValue("New LiveData Value")
}
}
Для сохранения состояния ViewModel в архитектурных компонентах Android используется класс
SavedStateHandle. Он позволяет сохранять и восстанавливать состояние при изменениях конфигурации. Создайте ViewModel с SavedStateHandle и используйте его для сохранения данных. Используйте ViewModelProvider.Factory для правильного создания ViewModel с SavedStateHandle.Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🤔1
Anonymous Quiz
19%
==
72%
===
8%
equals
1%
!==
Объединение нескольких коммитов в один в Git — это процесс, известный как "squash" коммитов. Существует несколько способов выполнения этой операции, в зависимости от вашего сценария. Наиболее распространенные способы включают использование интерактивного rebase или создание нового коммита, объединяющего изменения, а затем перезапись истории.
git rebase -i HEAD~n
где
n — это количество коммитов, которые вы хотите объединить. Например, если вы хотите объединить последние 3 коммита, используйте HEAD~3.
pick e5b7e1a Commit message 1
pick d6f8f2b Commit message 2
pick f3a7a3c Commit message 3
pick e5b7e1a Commit message 1
squash d6f8f2b Commit message 2
squash f3a7a3c Commit message 3
# This is a combination of 3 commits.
# The first commit's message is:
Commit message 1
# This is the 2nd commit message:
Commit message 2
# This is the 3rd commit message:
Commit message 3
Способ
git checkout -b temp-branch
git reset --soft HEAD~n
где
n — это количество коммитов, которые вы хотите объединить.git commit -m "New combined commit message"
git checkout main
git reset --hard temp-branch
git branch -D temp-branch
git rebase -i HEAD~n для интерактивного ребейза и объединения коммитов.git reset --soft HEAD~n и создайте новый коммит со всеми изменениями.Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Anonymous Quiz
18%
param
10%
var
52%
val
20%
this
😁6👍1🔥1
Реализация безопасной и надежной загрузки видео в приложении требует соблюдения нескольких ключевых принципов. Важно учитывать не только технические аспекты, но и вопросы безопасности, производительности и пользовательского опыта.
Вот общие шаги и рекомендации для создания такой системы:
Для безопасной и надежной загрузки видео в Android приложении используйте:
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1