<?xml version="1.0" encoding="utf-8" ?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:tt="http://teletype.in/" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/"><title>Sora Nai</title><author><name>Sora Nai</name></author><id>https://teletype.in/atom/hikkidev</id><link rel="self" type="application/atom+xml" href="https://teletype.in/atom/hikkidev?offset=0"></link><link rel="alternate" type="text/html" href="https://teletype.in/@hikkidev?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=hikkidev"></link><link rel="next" type="application/rss+xml" href="https://teletype.in/atom/hikkidev?offset=10"></link><link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></link><updated>2026-04-04T05:21:33.721Z</updated><entry><id>hikkidev:arch-install-btrfs</id><link rel="alternate" type="text/html" href="https://teletype.in/@hikkidev/arch-install-btrfs?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=hikkidev"></link><title>Unencrypted Arch Linux + BTRFS as ROOT + rEFInd</title><published>2024-10-15T21:26:17.813Z</published><updated>2024-10-16T06:21:29.637Z</updated><category term="arch-linux" label="Arch Linux"></category><summary type="html">&lt;img src=&quot;https://img1.teletype.in/files/c9/0a/c90a6d03-154d-4207-94fa-7782ec08556b.png&quot;&gt;</summary><content type="html">
  &lt;h3 id=&quot;JZgw&quot;&gt;Пред-условия этой заметки&lt;/h3&gt;
  &lt;ul id=&quot;TkZt&quot;&gt;
    &lt;li id=&quot;ShEt&quot;&gt;Наличие установочного USB (Bootable USB drive: &lt;a href=&quot;https://archlinux.org/download/&quot; target=&quot;_blank&quot;&gt;Arch Linux&lt;/a&gt;, &lt;a href=&quot;https://rufus.ie&quot; target=&quot;_blank&quot;&gt;Rufus&lt;/a&gt;)&lt;/li&gt;
    &lt;li id=&quot;MqT5&quot;&gt;Motherboard boot mode: x64 UEFI&lt;/li&gt;
    &lt;li id=&quot;oEzq&quot;&gt;ОС на одном диске (будет 2 раздела)&lt;/li&gt;
    &lt;ul id=&quot;IuEQ&quot;&gt;
      &lt;li id=&quot;HVNY&quot;&gt;1Gb под загрузчик&lt;/li&gt;
      &lt;li id=&quot;33O4&quot;&gt;Оставшееся пространство под систему&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li id=&quot;yqB8&quot;&gt;Без шифрования и secure-boot &lt;/li&gt;
  &lt;/ul&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;Eizz&quot;&gt;Ну че, народ, погнали! &lt;/h2&gt;
  &lt;blockquote id=&quot;Cnv8&quot;&gt;&lt;a href=&quot;https://coub.com/view/9juiz80&quot; target=&quot;_blank&quot;&gt;https://coub.com/view/9juiz80&lt;/a&gt;&lt;/blockquote&gt;
  &lt;ol id=&quot;6hiE&quot;&gt;
    &lt;li id=&quot;Cl7p&quot;&gt;Выполнить шаги с 1.1 по 1.8 из официальной &lt;a href=&quot;https://wiki.archlinux.org/title/Installation_guide&quot; target=&quot;_blank&quot;&gt;инструкции&lt;/a&gt; до пункта о разметке диска&lt;/li&gt;
  &lt;/ol&gt;
  &lt;h3 id=&quot;39Lm&quot;&gt;1. Выбрать диск&lt;/h3&gt;
  &lt;ul id=&quot;zZky&quot;&gt;
    &lt;li id=&quot;XH4Q&quot;&gt;ВНИМАТЕЛЬНО, выбрать диск на накоторый будет установлена система. Для просмотра дисков можно использовать утилиты: &lt;code&gt;lsblk&lt;/code&gt;, &lt;code&gt;blkid&lt;/code&gt;, &lt;code&gt;fdisk -l&lt;/code&gt;&lt;/li&gt;
    &lt;li id=&quot;K0jN&quot;&gt;Пусть целевым диском будет SSD &lt;code&gt;nvme0n1&lt;/code&gt;, тогда сохранить диск в переменную окружения: &lt;code&gt;export DISK=&amp;quot;/dev/nvme0n1&amp;quot;&lt;/code&gt;&lt;/li&gt;
  &lt;/ul&gt;
  &lt;h3 id=&quot;ymaM&quot;&gt;2. Удалить старую разметку (желательно, на всякий случай)&lt;/h3&gt;
  &lt;pre id=&quot;ePvb&quot; data-lang=&quot;bash&quot;&gt;wipefs -af $DISK
sgdisk --zap-all --clear $DISK
partprobe $DISK&lt;/pre&gt;
  &lt;h3 id=&quot;PI9U&quot;&gt;3. Выполнить разметку&lt;/h3&gt;
  &lt;pre id=&quot;31Q2&quot; data-lang=&quot;bash&quot;&gt;parted -s $DISK mklabel gpt
parted -s $DISK mkpart primary fat32 1MiB 1025MiB
parted -s $DISK set 1 esp on
parted -s $DISK mkpart primary $FILESYSTEM 1025MiB 100%&lt;/pre&gt;
  &lt;h3 id=&quot;MZXO&quot;&gt;4. Форматировать разделы &lt;/h3&gt;
  &lt;blockquote id=&quot;Ojt9&quot;&gt;Предупреждение: разделы для SSD имеют префикс &amp;#x60;p&amp;#x60;, SATA как правило не имеют; проверьте одной из утилит, например &lt;code&gt;fdisk -l&lt;/code&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;08VG&quot;&gt;Загрузочный раздел под FAT32&lt;/p&gt;
  &lt;pre id=&quot;067a&quot; data-lang=&quot;bash&quot;&gt;mkfs.fat -F32 ${DISK}p1&lt;/pre&gt;
  &lt;p id=&quot;BDrs&quot;&gt;Второй раздел под BTRFS&lt;/p&gt;
  &lt;pre id=&quot;XQk0&quot; data-lang=&quot;bash&quot;&gt;mkfs.btrfs -f ${DISK}p2&lt;/pre&gt;
  &lt;p id=&quot;N90O&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;11oc&quot;&gt;5. Сконфигурировать разделы BTRFS&lt;/h3&gt;
  &lt;p id=&quot;Z01l&quot;&gt;Примонтировать раздел диска в папку &lt;code&gt;/mnt&lt;/code&gt;&lt;/p&gt;
  &lt;pre id=&quot;zTUy&quot; data-lang=&quot;shell&quot;&gt;mount ${DISK}p2 /mnt&lt;/pre&gt;
  &lt;p id=&quot;zwrN&quot;&gt;Создать корневой раздел BTRFS (&lt;code&gt;/&lt;/code&gt;)&lt;/p&gt;
  &lt;pre id=&quot;PBXV&quot; data-lang=&quot;shell&quot;&gt;btrfs subvolume create /mnt/@&lt;/pre&gt;
  &lt;p id=&quot;4oBz&quot;&gt;Создать под-разделы&lt;/p&gt;
  &lt;pre id=&quot;PBXV&quot; data-lang=&quot;shell&quot;&gt;btrfs subvolume create /mnt/@snapshots
btrfs subvolume create /mnt/@home
btrfs subvolume create /mnt/@libvirt
btrfs subvolume create /mnt/@cache
btrfs subvolume create /mnt/@log
btrfs subvolume create /mnt/@tmp&lt;/pre&gt;
  &lt;p id=&quot;RfkI&quot;&gt;Структура под-раздел : точка монтирования&lt;/p&gt;
  &lt;ul id=&quot;w8Js&quot;&gt;
    &lt;li id=&quot;05MQ&quot;&gt;&lt;code&gt;@snapshots&lt;/code&gt; : &lt;code&gt;/.snapshots&lt;/code&gt;&lt;/li&gt;
    &lt;li id=&quot;burr&quot;&gt;&lt;code&gt;@home&lt;/code&gt; : &lt;code&gt;/home&lt;/code&gt;&lt;/li&gt;
    &lt;li id=&quot;pOzU&quot;&gt;&lt;code&gt;@libvirt&lt;/code&gt; : &lt;code&gt;/var/lib/libvirt&lt;/code&gt; (виртуальные машины)&lt;/li&gt;
    &lt;li id=&quot;tJsX&quot;&gt;&lt;code&gt;@cache&lt;/code&gt; : &lt;code&gt;/var/cache&lt;/code&gt;&lt;/li&gt;
    &lt;li id=&quot;TUOv&quot;&gt;&lt;code&gt;@log&lt;/code&gt; : &lt;code&gt;/var/log&lt;/code&gt;&lt;/li&gt;
    &lt;li id=&quot;ChtW&quot;&gt;&lt;code&gt;@tmp&lt;/code&gt; : &lt;code&gt;/var/tmp&lt;/code&gt;&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;3TnD&quot;&gt;Исключение &lt;code&gt;@tmp&lt;/code&gt; и &lt;code&gt;@log&lt;/code&gt; облегчит последующую работу в &amp;quot;recovery mode&amp;quot; после отката всей системы (корневого раздела &lt;code&gt;/&lt;/code&gt;)&lt;/p&gt;
  &lt;p id=&quot;kGN7&quot;&gt;Размонтировать для последующей работы с созданными разделами&lt;/p&gt;
  &lt;pre id=&quot;nqDq&quot; data-lang=&quot;bash&quot;&gt;umount /mnt&lt;/pre&gt;
  &lt;p id=&quot;beok&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;htb6&quot;&gt;6. Монтировать разделы&lt;/h3&gt;
  &lt;p id=&quot;xrzh&quot;&gt;Основной раздел&lt;/p&gt;
  &lt;pre data-lang=&quot;bash&quot; id=&quot;pxWh&quot;&gt;export MY_OPT=&amp;quot;rw,noatime,compress-force=zstd,space_cache=v2&amp;quot;&lt;/pre&gt;
  &lt;pre data-lang=&quot;bash&quot; id=&quot;Qc4n&quot;&gt;mount -o ${MY_OPT},subvol=@ ${DISK}p2 /mnt&lt;/pre&gt;
  &lt;pre data-lang=&quot;bash&quot; id=&quot;6udu&quot;&gt;mkdir -p /mnt/{.snapshots,home,var/lib/libvirt,var/cache,var/log,var/tmp}&lt;/pre&gt;
  &lt;pre data-lang=&quot;bash&quot; id=&quot;HCFE&quot;&gt;mount -o ${MY_OPT},subvol=@snapshots ${DISK}p2 /mnt/.snapshots
mount -o ${MY_OPT},subvol=@home ${DISK}p2 /mnt/home
mount -o ${MY_OPT},subvol=@libvirt ${DISK}p2 /mnt/var/lib/libvirt
mount -o ${MY_OPT},subvol=@cache ${DISK}p2 /mnt/var/cache
mount -o ${MY_OPT},subvol=@log ${DISK}p2 /mnt/var/log
mount -o ${MY_OPT},subvol=@tmp ${DISK}p2 /mnt/var/tmp&lt;/pre&gt;
  &lt;p id=&quot;YAj6&quot;&gt;Загрузочный раздел&lt;/p&gt;
  &lt;pre id=&quot;nFLV&quot; data-lang=&quot;bash&quot;&gt;mkdir -p /mnt/boot/efi
mount ${DISK}p1 /mnt/boot/efi&lt;/pre&gt;
  &lt;p id=&quot;HNuA&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;VfwU&quot;&gt;7. Установить систему&lt;/h3&gt;
  &lt;pre data-lang=&quot;bash&quot; id=&quot;k6RA&quot;&gt;pacstrap /mnt base base-devel btrfs-progs linux-lts linux-lts-headers linux-firmware networkmanager sudo&lt;/pre&gt;
  &lt;p id=&quot;DmHm&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;nekq&quot;&gt;Конфигурация&lt;/h2&gt;
  &lt;h3 id=&quot;lttU&quot;&gt;1. Сгенерировать fstab&lt;/h3&gt;
  &lt;pre id=&quot;qmlH&quot; data-lang=&quot;shell&quot;&gt;genfstab -U /mnt &amp;gt;&amp;gt; /mnt/etc/fstab&lt;/pre&gt;
  &lt;p id=&quot;REEn&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;gDkF&quot;&gt;2. arch-chroot&lt;/h3&gt;
  &lt;p id=&quot;qVVO&quot;&gt;Выполнить шаги 3.1 - 3.6 из официальной &lt;a href=&quot;https://wiki.archlinux.org/title/Installation_guide&quot; target=&quot;_blank&quot;&gt;инструкции&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;2g38&quot;&gt;Моя краткая выжимка:&lt;/p&gt;
  &lt;pre id=&quot;gEfZ&quot;&gt;# Тайм-зона
export TIMEZONE=&amp;quot;Europe/Amsterdam&amp;quot; &amp;lt;- заменить на свою
ln -sf /usr/share/zoneinfo/$TIMEZONE /etc/localtime
hwclock --systohc

# Локализация, английский приоритетный

export locale=&amp;quot;ru_RU.UTF-8 UTF-8&amp;quot;
sed -i &amp;quot;s/^#\(${locale}\)/\1/&amp;quot; /etc/locale.gen

export locale=&amp;quot;en_US.UTF-8 UTF-8&amp;quot;
sed -i &amp;quot;s/^#\(${locale}\)/\1/&amp;quot; /etc/locale.gen

echo &amp;quot;LANG=${locale}&amp;quot; &amp;gt; /etc/locale.conf
locale-gen

# Установить имя машины
echo $HOSTNAME &amp;gt; /etc/hostname

# Пароль root пользователя
passwd

# Создать пользователя
export USERNAME=&amp;quot;hikkidev&amp;quot; &amp;lt;- заменить на свой
useradd -m -G wheel -s /bin/bash $USERNAME
passwd $USERNAME

# Привилегии sudo для группы wheel
echo &amp;quot;%wheel ALL=(ALL) ALL&amp;quot; &amp;gt; /etc/sudoers.d/wheel

# Заводим интернет
systemctl enable NetworkManager&lt;/pre&gt;
  &lt;p id=&quot;ErX0&quot;&gt;Экстра-софт:&lt;/p&gt;
  &lt;pre id=&quot;AqIX&quot;&gt;pacman -S refind efibootmgr tree btop bat eza tree&lt;/pre&gt;
  &lt;p id=&quot;lCel&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;WW9O&quot;&gt;3. Настройка загрузчика &lt;a href=&quot;https://wiki.archlinux.org/title/REFInd&quot; target=&quot;_blank&quot;&gt;rEFInd&lt;/a&gt;&lt;/h3&gt;
  &lt;p id=&quot;zD2Z&quot;&gt;&lt;strong&gt;Определить&lt;/strong&gt; &lt;code&gt;PARTUUID&lt;/code&gt; основного раздела, &lt;u&gt;куда установлена система&lt;/u&gt;, в данном случае это &lt;code&gt;${DISK}p2&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;VQlH&quot; data-lang=&quot;bash&quot;&gt;blkid -s PARTUUID /dev/nvme0n1p2 -o value&lt;/pre&gt;
  &lt;p id=&quot;Cya0&quot;&gt;Сохранить значение в переменную:&lt;/p&gt;
  &lt;pre id=&quot;o04B&quot; data-lang=&quot;bash&quot;&gt;export MYUUID=$(blkid -s PARTUUID /dev/nvme0n1p2 -o value)&lt;/pre&gt;
  &lt;p id=&quot;p5Ea&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;hGBn&quot;&gt;&lt;a href=&quot;https://wiki.archlinux.org/title/REFInd#Installation_with_refind-install_script&quot; target=&quot;_blank&quot;&gt;Установить&lt;/a&gt; загрузчик&lt;/p&gt;
  &lt;pre id=&quot;BKaF&quot;&gt;refind-install&lt;/pre&gt;
  &lt;p id=&quot;jU13&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;OR8q&quot;&gt;&lt;strong&gt;&lt;u&gt;Отредактировать&lt;/u&gt;&lt;/strong&gt; основные &lt;a href=&quot;https://wiki.archlinux.org/title/REFInd#Configuration&quot; target=&quot;_blank&quot;&gt;параметры&lt;/a&gt; загрузчика в &lt;code&gt;refind.conf&lt;/code&gt;, файл как правило находится где-то в &lt;code&gt;esp/EFI/refind/&lt;/code&gt;&lt;/p&gt;
  &lt;pre id=&quot;NABZ&quot;&gt;/boot/EFI/refind/refind.conf
/boot/efi/EFI/BOOT/refind.conf&lt;/pre&gt;
  &lt;ul id=&quot;rTrG&quot;&gt;
    &lt;li id=&quot;d6aI&quot;&gt;Включить поддержку схемы именования ядер Arch Linux для их автоматического обнаружения, раскоментировав или дописав:&lt;/li&gt;
  &lt;/ul&gt;
  &lt;pre id=&quot;lYja&quot;&gt;extra_kernel_version_strings &amp;quot;linux,linux-lts,linux-zen,linux-rt,linux-rt-lts,linux-hardened&amp;quot;&lt;/pre&gt;
  &lt;ul id=&quot;3bgC&quot;&gt;
    &lt;li id=&quot;k8VS&quot;&gt;Включить автоматическое &lt;a href=&quot;https://wiki.archlinux.org/title/REFInd#Auto_detection&quot; target=&quot;_blank&quot;&gt;обнаружение ядра на под-разделе BTRFS&lt;/a&gt;, раскоментировав или дописав:&lt;/li&gt;
  &lt;/ul&gt;
  &lt;pre id=&quot;yUX4&quot;&gt;also_scan_dirs +,boot,@/boot&lt;/pre&gt;
  &lt;ul id=&quot;SFAL&quot;&gt;
    &lt;li id=&quot;o2eK&quot;&gt;Удалить или закоментировать примеры manual stanza в конце файла&lt;/li&gt;
    &lt;li id=&quot;5Yhp&quot;&gt;Дописать в конце файла (&lt;a href=&quot;https://wiki.archlinux.org/title/REFInd#For_manual_boot_stanzas&quot; target=&quot;_blank&quot;&gt;что такое manual stanza&lt;/a&gt;):&lt;/li&gt;
  &lt;/ul&gt;
  &lt;pre id=&quot;iQbh&quot;&gt;include stanzas.conf&lt;/pre&gt;
  &lt;p id=&quot;gNMY&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;GoTS&quot;&gt;&lt;strong&gt;&lt;u&gt;Cоздать&lt;/u&gt;&lt;/strong&gt; файл &lt;code&gt;stanzas.conf&lt;/code&gt; в папке с &lt;code&gt;refind.conf&lt;/code&gt;  (&lt;a href=&quot;https://wiki.archlinux.org/title/REFInd#Manual_boot_stanza&quot; target=&quot;_blank&quot;&gt;подробнее&lt;/a&gt;):&lt;/p&gt;
  &lt;pre id=&quot;Fqwg&quot; data-lang=&quot;bash&quot;&gt;cat &amp;gt; stanzas.conf &amp;lt;&amp;lt;EOF
menuentry &amp;quot;Arch Linux LTS&amp;quot; {
    icon /EFI/refind/icons/os_arch.png
    volume primary
    loader /@/boot/vmlinuz-linux-lts
    initrd /@/boot/initramfs-linux-lts.img
    options &amp;quot;root=PARTUUID=$MYUUID rw rootflags=subvol=@&amp;quot;
    submenuentry &amp;quot;Boot - fallback&amp;quot; {
        initrd /@/boot/initramfs-linux-lts-fallback.img
    }
}
EOF&lt;/pre&gt;
  &lt;pre id=&quot;JTN8&quot; data-lang=&quot;bash&quot;&gt;mv stanzas.conf &amp;lt;path to refind&amp;gt;/&lt;/pre&gt;
  &lt;p id=&quot;dJRV&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;fCOI&quot;&gt;&lt;strong&gt;&lt;u&gt;Отредактировать&lt;/u&gt;&lt;/strong&gt; параметры ядра поумолчанию в &lt;a href=&quot;https://wiki.archlinux.org/title/REFInd#refind_linux.conf&quot; target=&quot;_blank&quot;&gt;refind_linux.conf &lt;/a&gt;для автоматически обнаруженных ядер.&lt;/p&gt;
  &lt;p id=&quot;Z5mr&quot;&gt;Как правило файл лежит тут: &lt;code&gt;/boot/refind_linux.conf&lt;/code&gt;&lt;/p&gt;
  &lt;pre id=&quot;vw1R&quot; data-lang=&quot;bash&quot;&gt;echo &amp;quot;\&amp;quot;Boot DEFAULT\&amp;quot;  \&amp;quot;root=PARTUUID=$MYUUID rw rootflags=subvol=@ initrd=@\boot\initramfs-%v.img\&amp;quot;&amp;quot; &amp;gt; /boot/refind_linux.conf&lt;/pre&gt;
  &lt;p id=&quot;B07Q&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;Lxve&quot;&gt;Убедиться, что запись rEFInd была добавлена в загрузчик UEFI первой, выполнив:&lt;/p&gt;
  &lt;pre data-lang=&quot;bash&quot; id=&quot;6hcu&quot;&gt;efibootmgr&lt;/pre&gt;
  &lt;p id=&quot;PfF4&quot;&gt;Если все ок - перезагрузка&lt;/p&gt;
  &lt;pre data-lang=&quot;bash&quot; id=&quot;KR0T&quot;&gt;exit
umount -R /mnt
reboot&lt;/pre&gt;
  &lt;p id=&quot;MLGg&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;relo&quot;&gt;Вход в систему + Snapper&lt;/h2&gt;
  &lt;p id=&quot;Jizy&quot;&gt;После входа в систему рекомендую настроить BTRFS snapshots сразу&lt;/p&gt;
  &lt;pre data-lang=&quot;bash&quot; id=&quot;PZBv&quot;&gt;sudo pacman -S snapper snap-pac&lt;/pre&gt;
  &lt;pre data-lang=&quot;bash&quot; id=&quot;Tdbe&quot;&gt;sudo umount /.snapshots
sudo rm -rf /.snapshots&lt;/pre&gt;
  &lt;pre data-lang=&quot;bash&quot; id=&quot;llLm&quot;&gt;sudo snapper -c root create-config /&lt;/pre&gt;
  &lt;pre data-lang=&quot;bash&quot; id=&quot;8qyV&quot;&gt;sudo btrfs subvolume delete /.snapshots&lt;/pre&gt;
  &lt;pre data-lang=&quot;bash&quot; id=&quot;NAlF&quot;&gt;sudo mkdir /.snapshots
sudo mount -a
sudo chmod 750 /.snapshots
sudo chown :wheel /.snapshots&lt;/pre&gt;
  &lt;pre data-lang=&quot;bash&quot; id=&quot;vvyb&quot;&gt;sudo snapper -c root create -d &amp;quot;Clean system install&amp;quot;&lt;/pre&gt;
  &lt;p id=&quot;b1AK&quot;&gt;Редактировать конфиг здесь: &lt;code&gt;/etc/snapper/configs/root&lt;/code&gt;&lt;/p&gt;
  &lt;p id=&quot;w6VZ&quot;&gt;Включить systemd таймеры для автоматического запуска снимков и периодической очистки старых:&lt;/p&gt;
  &lt;pre data-lang=&quot;bash&quot; id=&quot;0JsK&quot;&gt;sudo systemctl enable --now snapper-timeline.timer
sudo systemctl enable --now snapper-cleanup.timer&lt;/pre&gt;
  &lt;h2 id=&quot;tRpl&quot;&gt;Источники&lt;/h2&gt;
  &lt;ul id=&quot;O5kG&quot;&gt;
    &lt;li id=&quot;0BK4&quot;&gt;&lt;a href=&quot;https://wiki.archlinux.org/title/Installation_guide&quot; target=&quot;_blank&quot;&gt;https://wiki.archlinux.org/title/Installation_guide&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;oCv7&quot;&gt;&lt;a href=&quot;https://wiki.archlinux.org/title/REFInd&quot; target=&quot;_blank&quot;&gt;https://wiki.archlinux.org/title/REFInd&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;3elJ&quot;&gt;&lt;a href=&quot;https://www.dwarmstrong.org/archlinux-install&quot; target=&quot;_blank&quot;&gt;https://www.dwarmstrong.org/archlinux-install&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;OXVV&quot;&gt;&lt;a href=&quot;https://www.dwarmstrong.org/btrfs-snapshots-rollbacks&quot; target=&quot;_blank&quot;&gt;https://www.dwarmstrong.org/btrfs-snapshots-rollbacks&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;

</content></entry><entry><id>hikkidev:simple-android-permissions</id><link rel="alternate" type="text/html" href="https://teletype.in/@hikkidev/simple-android-permissions?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=hikkidev"></link><title>Разрешения в Android</title><published>2024-04-21T11:07:35.166Z</published><updated>2024-04-21T11:21:11.445Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img2.teletype.in/files/17/23/172364fa-d95c-4a2b-88c8-32677f3b65ea.png"></media:thumbnail><summary type="html">&lt;img src=&quot;https://img4.teletype.in/files/b7/dc/b7dc731f-c5fc-4ec3-8a6d-360be5f8747c.png&quot;&gt;Разрешения приложений в операционной системе Android - это механизм контроля доступа к данным и функциям вашего устройства.</summary><content type="html">
  &lt;nav&gt;
    &lt;ul&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#czBo&quot;&gt;Введение&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#Kfxv&quot;&gt;Зачем это нужно?&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#S39P&quot;&gt;Запрос разрешений&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#gSho&quot;&gt;Примеры разрешений:&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#e6PJ&quot;&gt;Изменить разрешения через системные Настройки&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#uFCP&quot;&gt;Изменить разрешения через контекстное меню&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/nav&gt;
  &lt;h2 id=&quot;czBo&quot;&gt;Введение&lt;/h2&gt;
  &lt;p id=&quot;mzCK&quot;&gt;Разрешения приложений в операционной системе Android - это механизм контроля доступа к данным и функциям вашего устройства. &lt;/p&gt;
  &lt;figure id=&quot;i0yt&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/b7/dc/b7dc731f-c5fc-4ec3-8a6d-360be5f8747c.png&quot; width=&quot;1800&quot; /&gt;
    &lt;figcaption&gt;Источник изображения - &lt;a href=&quot;https://www.android.com/intl/ru_ru/safety/privacy/#safety-privacy-permissions&quot; target=&quot;_blank&quot;&gt;android.com&lt;/a&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;A8fF&quot;&gt;Вы можете позволить приложениям использовать различные функции устройства, например камеру или список контактов. &lt;/p&gt;
  &lt;h2 id=&quot;Kfxv&quot;&gt;Зачем это нужно?&lt;/h2&gt;
  &lt;ul id=&quot;cTNV&quot;&gt;
    &lt;li id=&quot;4KIn&quot;&gt;&lt;strong&gt;Защита приватности&lt;/strong&gt;: Разрешения позволяют защищать вашу личную информацию. Например, приложение для обмена сообщениями может просить доступ к контактам, чтобы вы могли отправлять сообщения друзьям, но ему по умолчанию не дан доступ к вашим фотографиям или местоположению.&lt;/li&gt;
    &lt;li id=&quot;7JLV&quot;&gt;&lt;strong&gt;Безопасность данных&lt;/strong&gt;: Ограничение доступа приложений к определённым функциям и данным предотвращает возможные утечки информации. Это предотвращает сценарии, когда вредоносное приложение может скрытно собирать данные без вашего знания.&lt;/li&gt;
    &lt;li id=&quot;so0V&quot;&gt;&lt;strong&gt;Регулирование функционала&lt;/strong&gt;: Разрешения помогают обеспечить, чтобы приложения не использовали ресурсы устройства (например, камеру или микрофон) без ведома пользователя, что также может улучшать производительность устройства и его автономную работу.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;SfHC&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;S39P&quot;&gt;Запрос разрешений&lt;/h2&gt;
  &lt;figure id=&quot;GBja&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/48/dc/48dc81bb-4306-4a48-a615-5c580145d7bc.png&quot; width=&quot;1200&quot; /&gt;
    &lt;figcaption&gt;Источник изображения - &lt;a href=&quot;https://www.android.com/intl/ru_ru/safety/privacy/#safety-privacy-permissions&quot; target=&quot;_blank&quot;&gt;android.com&lt;/a&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Rzb2&quot;&gt;Когда приложение впервые пытается получить доступ, система отображает диалог, и пользователь может выбрать, выдать разрешение или отказать. Если отказать, то приложение не сможет использовать данные или запрашиваемую функцию, что повлияет на его работу. В лучшем случае запрет ограничит возможности приложения, в худшем сделает приложение неработоспособным. &lt;/p&gt;
  &lt;p id=&quot;iQGD&quot;&gt;Рассмотрим на примере приложения &amp;quot;Камера&amp;quot;. Для полноценной работы приложения необходимо выдать три разрешения к физическим датчикам устройства: &lt;strong&gt;камера&lt;/strong&gt;, &lt;strong&gt;микрофон&lt;/strong&gt; и &lt;strong&gt;местоположение&lt;/strong&gt;.&lt;/p&gt;
  &lt;figure id=&quot;NRb8&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;iframe src=&quot;https://www.youtube.com/embed/Tg50GNkcgN0?autoplay=0&amp;loop=1&amp;mute=1&amp;playlist=Tg50GNkcgN0&quot;&gt;&lt;/iframe&gt;
    &lt;figcaption&gt;Демонстрация запроса разрешений самим приложением.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Wv1k&quot;&gt;В данном случае очевидно, что доступ к &lt;strong&gt;Камере &lt;/strong&gt;обязателен, в противном случае  приложение не сможет снимать фото и видео. Доступ к &lt;strong&gt;Микрофону &lt;/strong&gt;нужен, чтобы записывать звук при съемке видео. А вот местоположение уже необязательное разрешение, и необходимо только для добавления сведений о месте съемки, подробнее что это такое, можно &lt;a href=&quot;https://support.google.com/photos/answer/6153599?hl=ru&amp;co=GENIE.Platform%253DAndroid&quot; target=&quot;_blank&quot;&gt;почитать здесь&lt;/a&gt;.&lt;/p&gt;
  &lt;p id=&quot;CfMV&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;gSho&quot;&gt;Примеры разрешений:&lt;/h3&gt;
  &lt;ul id=&quot;Sacj&quot;&gt;
    &lt;li id=&quot;HCoY&quot;&gt;&lt;u&gt;Физические датчики устойства&lt;/u&gt;&lt;/li&gt;
    &lt;ul id=&quot;W8OD&quot;&gt;
      &lt;li id=&quot;ZZyS&quot;&gt;&lt;strong&gt;Микрофон&lt;/strong&gt; – запись аудио.&lt;/li&gt;
      &lt;li id=&quot;j6gz&quot;&gt;&lt;strong&gt;Камера&lt;/strong&gt; – съемка фото и видео.&lt;/li&gt;
      &lt;li id=&quot;lZp6&quot;&gt;&lt;strong&gt;Местоположение&lt;/strong&gt; – доступ к данным о местоположении вашего устройства. &lt;/li&gt;
    &lt;/ul&gt;
    &lt;li id=&quot;5eC6&quot;&gt;&lt;u&gt;Телефония&lt;/u&gt;&lt;/li&gt;
    &lt;ul id=&quot;9Zw1&quot;&gt;
      &lt;li id=&quot;e63r&quot;&gt;&lt;strong&gt;Телефон&lt;/strong&gt; – совершение вызовов и управление ими.&lt;/li&gt;
      &lt;li id=&quot;h7IM&quot;&gt;&lt;strong&gt;Список вызовов&lt;/strong&gt; – просмотр списка вызовов на телефоне и создание записей в нем.&lt;/li&gt;
      &lt;li id=&quot;jNjy&quot;&gt;&lt;strong&gt;Контакты&lt;/strong&gt; – доступ к списку контактов.&lt;/li&gt;
      &lt;li id=&quot;1rAs&quot;&gt;&lt;strong&gt;SMS&lt;/strong&gt; – отправка и просмотр SMS-сообщений.&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li id=&quot;kCNu&quot;&gt;&lt;u&gt;Хранилище, данные на устройстве&lt;/u&gt;&lt;/li&gt;
    &lt;ul id=&quot;QrSq&quot;&gt;
      &lt;li id=&quot;kMqw&quot;&gt;&lt;strong&gt;Файлы&lt;/strong&gt; – доступ ко всем файлам на вашем устройстве.&lt;/li&gt;
      &lt;li id=&quot;aUup&quot;&gt;&lt;strong&gt;Фото и видео&lt;/strong&gt; – доступ к фото и видео на вашем устройстве.&lt;/li&gt;
      &lt;li id=&quot;nhoI&quot;&gt;&lt;strong&gt;Музыка и аудио&lt;/strong&gt; – доступ к музыке и другим аудиофайлам на устройстве.&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li id=&quot;dkJo&quot;&gt;&lt;u&gt;Другие разрешения&lt;/u&gt;&lt;/li&gt;
    &lt;ul id=&quot;u9Yd&quot;&gt;
      &lt;li id=&quot;yIxf&quot;&gt;&lt;strong&gt;Уведомления&lt;/strong&gt; – отправление уведомлений.&lt;/li&gt;
      &lt;li id=&quot;aZgJ&quot;&gt;&lt;strong&gt;Календарь&lt;/strong&gt; – доступ к вашему календарю.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;5OHM&quot;&gt;Полный список разрешений можно найти &lt;a href=&quot;https://support.google.com/android/answer/9431959#types&amp;zippy=%252C%D1%82%D0%B8%D0%BF%D1%8B-%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D1%88%D0%B5%D0%BD%D0%B8%D0%B9&quot; target=&quot;_blank&quot;&gt;по данной ссылке&lt;/a&gt;.&lt;/p&gt;
  &lt;p id=&quot;4R3z&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;e6PJ&quot;&gt;Изменить разрешения через системные Настройки&lt;/h2&gt;
  &lt;p id=&quot;dLY5&quot;&gt;В любой момент можно зайти в настройки Android, проверить выданные разрешения для приложений и изменить их по своему усмотрению. &lt;/p&gt;
  &lt;p id=&quot;F5xI&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;qWNa&quot;&gt;1) Откройте на устройстве приложение &amp;quot;&lt;strong&gt;Настройки&lt;/strong&gt;&amp;quot; и нажмите на раздел &lt;strong&gt;Приложения&lt;/strong&gt;.&lt;/p&gt;
  &lt;figure id=&quot;K9cl&quot; class=&quot;m_custom&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/48/8f/488f70af-5f5b-49c2-a0ba-f70bb7b4ea6d.png&quot; width=&quot;321.89761625635015&quot; /&gt;
    &lt;figcaption&gt;Главный экран системных Настроек&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;PYto&quot;&gt;2) Выберите нужное приложение. Если его нет в списке &amp;quot;Недавно открывавшиеся приложения&amp;quot;, нажмите &lt;strong&gt;Показать все приложения&lt;/strong&gt;, и затем выберите нужное.&lt;/p&gt;
  &lt;figure id=&quot;bUSf&quot; class=&quot;m_custom&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/9e/30/9e308037-13b2-438e-8ebb-80ff89dcfc99.png&quot; width=&quot;321.232121922626&quot; /&gt;
    &lt;figcaption&gt;Раздел &amp;quot;Приложения&amp;quot; в Настройках.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;M6OZ&quot;&gt;3) В правом верхнем углу подраздела есть кнопка с лупой. Нажмите на нее,чтобы войти в режим поиска по имени приложения. &lt;/p&gt;
  &lt;figure id=&quot;Kol3&quot; class=&quot;m_custom&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/fd/fc/fdfc560b-8cc1-4424-83a5-355236371511.png&quot; width=&quot;319.8276670574444&quot; /&gt;
    &lt;figcaption&gt;Подраздел &amp;quot;Все приложения&amp;quot; раздела &amp;quot;Приложения&amp;quot; в Настройках.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;hq4b&quot;&gt;3.1) Выберете приложение&lt;/p&gt;
  &lt;figure id=&quot;4W52&quot; class=&quot;m_custom&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/0d/90/0d903ba9-98eb-4ac7-9bc3-e7b09bf221b6.png&quot; width=&quot;319.99999999999994&quot; /&gt;
    &lt;figcaption&gt;Поиск приложения &amp;quot;Камера&amp;quot; в списке всех приложений.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;ipNJ&quot;&gt;4) В разделе &amp;quot;О приложении&amp;quot; выберите &lt;strong&gt;Разрешения&lt;/strong&gt;.&lt;/p&gt;
  &lt;figure id=&quot;za4i&quot; class=&quot;m_custom&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/13/f4/13f44b78-9318-426d-aef5-e356c05c6f0c.png&quot; width=&quot;322&quot; /&gt;
    &lt;figcaption&gt;Информация о приложении &amp;quot;Камера&amp;quot;.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;YI2z&quot;&gt;5) Откроется список разрешений приложения.&lt;/p&gt;
  &lt;figure id=&quot;NoK4&quot; class=&quot;m_custom&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/49/71/49719eb6-d8d6-4797-9dff-f1fd17b1fb28.png&quot; width=&quot;321.00000000000006&quot; /&gt;
    &lt;figcaption&gt;Все разрешения приложения &amp;quot;Камера&amp;quot;.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;OwbR&quot;&gt;6) Чтобы изменить настройки определенного разрешения, нажмите на него и выберите из списка.&lt;/p&gt;
  &lt;figure id=&quot;6iUB&quot; class=&quot;m_custom&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/4f/37/4f374976-99e5-4ebe-aa17-0f192baef94e.png&quot; width=&quot;320.1254396248534&quot; /&gt;
    &lt;figcaption&gt;Выбор разрешения для доступа к камере.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;iyIs&quot;&gt;Как правило возможны следующие варианты предоставления доступа:&lt;/p&gt;
  &lt;ul id=&quot;ouqJ&quot;&gt;
    &lt;li id=&quot;5hz9&quot;&gt;&lt;strong&gt;Всегда&lt;/strong&gt; (применимо только для доступа к данным о местоположении) – разрешение действует все время, даже когда приложение не используется.&lt;/li&gt;
    &lt;li id=&quot;I0MP&quot;&gt;&lt;strong&gt;Разрешить только во время использования приложения&lt;/strong&gt; – разрешение действует, пока вы пользуетесь приложением.&lt;/li&gt;
    &lt;li id=&quot;w8do&quot;&gt;&lt;strong&gt;Всегда спрашивать&lt;/strong&gt; – приложение будет запрашивать разрешение каждый раз, когда вы им пользуетесь. Разрешение будет действовать, пока вы не закроете приложение.&lt;/li&gt;
    &lt;li id=&quot;GxCD&quot;&gt;&lt;strong&gt;Запретить&lt;/strong&gt; – приложение не сможет пользоваться разрешением даже во время работы.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;VXiz&quot;&gt;Подробнее можно &lt;a href=&quot;https://support.google.com/android/answer/9431959&quot; target=&quot;_blank&quot;&gt;почитать здесь&lt;/a&gt;.&lt;/p&gt;
  &lt;p id=&quot;DqSo&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;uFCP&quot;&gt;Изменить разрешения через контекстное меню&lt;/h2&gt;
  &lt;p id=&quot;uYDv&quot;&gt;Альтернативный вариант настройки разрешений возможен через вызов контекстного меню &amp;quot;О приложении&amp;quot;. Оно несколько меняется в зависимости от версии операционной системы Android и пользовательской оболочки, но общий принцип следующий:&lt;/p&gt;
  &lt;ol id=&quot;M8nP&quot;&gt;
    &lt;li id=&quot;WQ7T&quot;&gt;&lt;strong&gt;Долгое нажатие на иконку приложения&lt;/strong&gt;: На главном экране или в панели приложений нажмите и удерживайте иконку приложения, для которого вы хотите изменить разрешения.&lt;/li&gt;
    &lt;li id=&quot;INmm&quot;&gt;&lt;strong&gt;Открытие контекстного меню&lt;/strong&gt;: После долгого нажатия появится контекстное меню. Ищите пункт, как правило, названный &amp;quot;О приложении&amp;quot; или &amp;quot;Информация о приложении&amp;quot;. В некоторых случаях это может быть иконка с символом &amp;quot;i&amp;quot; в маленьком кружке.&lt;/li&gt;
    &lt;li id=&quot;KkNu&quot;&gt;&lt;strong&gt;Переход к настройкам разрешений:&lt;/strong&gt; Коснитесь &amp;quot;О приложении&amp;quot; и в открывшемся окне информации о приложении найдите раздел &amp;quot;Разрешения&amp;quot;.&lt;/li&gt;
    &lt;li id=&quot;y4et&quot;&gt;&lt;strong&gt;Настройка разрешений&lt;/strong&gt;: В разделе &amp;quot;Разрешения&amp;quot; вы увидите список всех запрашиваемых приложением разрешений. Здесь вы сможете изменять разрешения, активируя или деактивируя доступ для каждого из них.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;pfYC&quot;&gt;&lt;/p&gt;
  &lt;figure id=&quot;CrzZ&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;iframe src=&quot;https://www.youtube.com/embed/5guul1zap_0?autoplay=0&amp;loop=1&amp;mute=1&amp;playlist=5guul1zap_0&quot;&gt;&lt;/iframe&gt;
    &lt;figcaption&gt;Видео демонстрация.&lt;/figcaption&gt;
  &lt;/figure&gt;

</content></entry><entry><id>hikkidev:kotlin-java-interop</id><link rel="alternate" type="text/html" href="https://teletype.in/@hikkidev/kotlin-java-interop?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=hikkidev"></link><title>Kotlin-Java interop: 'companion object' and 'private' visibility modifier</title><published>2024-04-02T13:19:32.693Z</published><updated>2024-04-04T04:12:33.664Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img1.teletype.in/files/c5/c0/c5c01923-c4cf-403c-8e70-d0646a3fb5c2.png"></media:thumbnail><category term="kotlin" label="Kotlin"></category><summary type="html">&lt;img src=&quot;https://img1.teletype.in/files/4e/e1/4ee120fa-620c-4d7d-9557-f74f1eaf0e46.jpeg&quot;&gt;Пост представляет собой ответ на частый вопрос &quot;почему ты использовал  private companion object с вложенными private const val?&quot;</summary><content type="html">
  &lt;blockquote id=&quot;9Fh1&quot;&gt;Заметка: данный пост представляет собой небольшое объяснение на частый вопрос &amp;quot;почему используешь  &lt;code&gt;private companion object&lt;/code&gt; с вложенными &lt;code&gt;private const val&lt;/code&gt;?&amp;quot;&lt;/blockquote&gt;
  &lt;p id=&quot;jkDv&quot;&gt;&lt;strong&gt;Оглавление&lt;/strong&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;NiPo&quot;&gt;Дано&lt;/h2&gt;
  &lt;p id=&quot;xYzx&quot;&gt;Рассмотрим пример с полями в &lt;code&gt;companion object&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;NfzR&quot; data-lang=&quot;kotlin&quot;&gt;class KotlinClassSample {

    companion object {
        @JvmField
        val PUBLIC_STATIC_FIELD  = emptyList()
        val publicNonStaticField = emptyList()
        const val PUBLIC_STATIC_PRIMITIVE_FIELD = 0

        // JvmField has no effect on a private property
        private val privateField = emptyList()
        private const val PRIVATE_STATIC_PRIMITIVE_FIELD = 0
    }
}&lt;/pre&gt;
  &lt;p id=&quot;R08m&quot;&gt;Проверим доступ к &lt;code&gt;KotlinClassSample&lt;/code&gt; коду из Java и Kotlin:&lt;/p&gt;
  &lt;pre id=&quot;WHoa&quot; data-lang=&quot;java&quot;&gt;class JavaClassAccessTest {

    void callingKotlinFromJava() {
        // OK
        KotlinClassSample.PUBLIC_STATIC_FIELD;
        KotlinClassSample.PUBLIC_STATIC_PRIMITIVE_FIELD;
        KotlinClassSample.Companion.getPublicNonStaticField();
    }
}&lt;/pre&gt;
  &lt;pre id=&quot;gH9g&quot; data-lang=&quot;kotlin&quot;&gt;class KotlinClassAccessTest {

    fun callingKotlinFromKotlin() {
        // OK
        KotlinClassSample.PUBLIC_STATIC_FIELD
        KotlinClassSample.PUBLIC_STATIC_PRIMITIVE_FIELD
        KotlinClassSample.publicNonStaticField
    }
}&lt;/pre&gt;
  &lt;p id=&quot;T6e3&quot;&gt;Ожидаемое поведение на основе модификатора доступа &lt;code&gt;public&lt;/code&gt; у &lt;code&gt;companion object&lt;/code&gt; подтвердилось. &lt;/p&gt;
  &lt;p id=&quot;Gjsa&quot;&gt;Теперь сменим модификатор на &lt;code&gt;private&lt;/code&gt; и можем наблюдать следующее:&lt;/p&gt;
  &lt;pre id=&quot;iQT8&quot; data-lang=&quot;java&quot;&gt;class JavaClassAccessTest {

    void callingKotlinFromJava() {
        // OK
        KotlinClassSample.PUBLIC_STATIC_FIELD;
        KotlinClassSample.PUBLIC_STATIC_PRIMITIVE_FIELD;

        // Error: &amp;#x27;Companion&amp;#x27; has private access in &amp;#x27;KotlinClassSample&amp;#x27;
        KotlinClassSample.Companion.getPublicNonStaticField(); // inaccessible
    }
}&lt;/pre&gt;
  &lt;pre id=&quot;P7H0&quot; data-lang=&quot;kotlin&quot;&gt;class KotlinClassAccessTest {

    fun callingKotlinFromKotlin() {
        // Error: Cannot access &amp;#x27;Companion&amp;#x27;: it is private in &amp;#x27;KotlinClassSample&amp;#x27;
        KotlinClassSample.PUBLIC_STATIC_FIELD           // inaccessible
        KotlinClassSample.PUBLIC_STATIC_PRIMITIVE_FIELD // inaccessible
        KotlinClassSample.publicNonStaticField          // inaccessible
    }
}&lt;/pre&gt;
  &lt;p id=&quot;BiDa&quot;&gt;В голове у непосвященного человека может возникнуть резонный вопрос:&lt;/p&gt;
  &lt;figure id=&quot;tqxm&quot; class=&quot;m_custom&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;iframe src=&quot;https://www.youtube.com/embed/hZYkVIEM_4A?autoplay=0&amp;loop=1&amp;mute=0&amp;playlist=hZYkVIEM_4A&quot;&gt;&lt;/iframe&gt;
    &lt;figcaption&gt;Почему так?⁠⁠&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;9e59&quot;&gt;Решение&lt;/h2&gt;
  &lt;p id=&quot;Qh3N&quot;&gt;Чтобы понять &amp;quot;почему&amp;quot;, декомпилируем &lt;code&gt;KotlinClassSample&lt;/code&gt; c &lt;code&gt;public companion object&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;d5FA&quot; data-lang=&quot;java&quot;&gt;public final class KotlinClassSampleDecompiled {
    public static final CompanionObject Companion = new CompanionObject();

    public  static final int  PUBLIC_STATIC_PRIMITIVE_FIELD = 0;
    public  static final List PUBLIC_STATIC_FIELD  = EmptyList();
    private static final List publicNonStaticField = EmptyList();
    
    private static final int  PRIVATE_STATIC_PRIMITIVE_FIELD = 0;
    private static final List privateField = EmptyList();


    public static final class CompanionObject {

        public List getPublicNonStaticField() {
            return KotlinClassSampleDecompiled.publicNonStaticField;
        }
    }
}&lt;/pre&gt;
  &lt;p id=&quot;HquM&quot;&gt;И декомпилируем &lt;code&gt;KotlinClassSample&lt;/code&gt;  c &lt;code&gt;private companion object&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;xEj6&quot; data-lang=&quot;java&quot;&gt;public final class KotlinClassSampleDecompiled {
    private static final CompanionObject Companion = new CompanionObject();

    public  static final int  PUBLIC_STATIC_PRIMITIVE_FIELD = 0;
    public  static final List PUBLIC_STATIC_FIELD  = EmptyList();
    private static final List publicNonStaticField = EmptyList();

    private static final int  PRIVATE_STATIC_PRIMITIVE_FIELD = 0;
    private static final List privateField = EmptyList();


    private static final class CompanionObject {

        public List getPublicNonStaticField() {
            return KotlinClassSampleDecompiled.publicNonStaticField;
        }
    }
}&lt;/pre&gt;
  &lt;blockquote id=&quot;DLWY&quot;&gt;Заметка: содержимое &lt;code&gt;Decompiled&lt;/code&gt; классов упрощено для повышения читабельности.&lt;/blockquote&gt;
  &lt;p id=&quot;lEEr&quot;&gt;Как можно видеть, применение модификатора &lt;code&gt;private&lt;/code&gt; к &lt;code&gt;companion object&lt;/code&gt;  изменило видимость только у класса &lt;code&gt;CompanionObject&lt;/code&gt;, поля &lt;code&gt;Companion&lt;/code&gt;, и как следствие геттера &lt;code&gt;CompanionObject#getPublicNonStaticField&lt;/code&gt;.&lt;/p&gt;
  &lt;h2 id=&quot;pezX&quot;&gt;Ответ&lt;/h2&gt;
  &lt;p id=&quot;K8Cx&quot;&gt;В общем-то магии никакой нет, и статические свойства объявленные в Kotlin через &lt;code&gt;@JvmField&lt;/code&gt; или &lt;code&gt;const val&lt;/code&gt; компилируются в Java как &lt;code&gt;static final&lt;/code&gt; поля &lt;u&gt;родительского класса&lt;/u&gt;, в который вкладывается сгенерированный класс &lt;code&gt;CompanionObject&lt;/code&gt;. &lt;/p&gt;
  &lt;p id=&quot;kcjb&quot;&gt;Поэтому  использование  &lt;code&gt;private companion object&lt;/code&gt; с вложенными &lt;code&gt;private const val&lt;/code&gt; следует воспринимать нормально, возможно даже более &amp;quot;верно&amp;quot;. Другое дело, если проект написан только на Kotlin, то &lt;code&gt;private companion object&lt;/code&gt; будет достаточно для ограничения видимости.&lt;/p&gt;
  &lt;blockquote id=&quot;ObGG&quot;&gt;Заметка: на последующих этапах компиляции применяются оптимизации и базовые типы объявленные через &lt;code&gt;const&lt;/code&gt; будут подставленны в место их вызова, как шаблоны в C++, но это отдельная тема :)&lt;/blockquote&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;SbUk&quot;&gt;&lt;strong&gt;Дополнительно &lt;/strong&gt;прилагаю пример с методами, вывод аналогичен - статические функции\методы компилируются к &lt;u&gt;родительскому классу&lt;/u&gt;, см. декомпилированный код внизу.&lt;/p&gt;
  &lt;p id=&quot;VPlJ&quot;&gt;Дано:&lt;/p&gt;
  &lt;pre id=&quot;NpXi&quot; data-lang=&quot;kotlin&quot;&gt;class KotlinClassSample {

    companion object {
        @JvmStatic
        fun publicStaticFun() = Unit
        fun publicNonStaticFun() = Unit

        @JvmStatic
        private fun privateStaticFun() = Unit
        private fun privateNonStaticFun() = Unit
    }
}&lt;/pre&gt;
  &lt;p id=&quot;7Vrz&quot;&gt;Проверяем доступ к &lt;code&gt;KotlinClassSample&lt;/code&gt; коду из Java и Kotlin:&lt;/p&gt;
  &lt;pre id=&quot;cjhk&quot; data-lang=&quot;java&quot;&gt;class JavaClassAccessTest {

    void callingKotlinFromJava() {
        // OK
        KotlinClassSample.publicStaticFun();
        KotlinClassSample.Companion.publicStaticFun();
        KotlinClassSample.Companion.publicNonStaticFun();
    }
}&lt;/pre&gt;
  &lt;pre id=&quot;MBDr&quot; data-lang=&quot;kotlin&quot;&gt;class KotlinClassAccessTest {

    fun callingKotlinFromKotlin() {
        // OK
        KotlinClassSample.publicStaticFun()
        KotlinClassSample.publicNonStaticFun()
    }
}&lt;/pre&gt;
  &lt;p id=&quot;zN2V&quot;&gt;Изменим модификатор доступа у &lt;code&gt;companion object&lt;/code&gt; на &lt;code&gt;private&lt;/code&gt; и посмотрим, что изменилось:&lt;/p&gt;
  &lt;pre id=&quot;lIjS&quot; data-lang=&quot;java&quot;&gt;class JavaClassAccessTest {

    void callingKotlinFromJava() {
        // OK
        KotlinClassSample.publicStaticFun();

        // Error: &amp;#x27;KotlinClassSample.Companion&amp;#x27; has private access
        KotlinClassSample.Companion.publicStaticFun();    // inaccessible
        KotlinClassSample.Companion.publicNonStaticFun(); // inaccessible
    }
}&lt;/pre&gt;
  &lt;pre id=&quot;HTem&quot; data-lang=&quot;kotlin&quot;&gt;class KotlinClassAccessTest {

    fun callingKotlinFromKotlin() {
        // Error: Cannot access &amp;#x27;Companion&amp;#x27;: it is private in &amp;#x27;KotlinClassSample&amp;#x27;
        KotlinClassSample.publicStaticFun()    // inaccessible
        KotlinClassSample.publicNonStaticFun() // inaccessible
    }
}&lt;/pre&gt;
  &lt;p id=&quot;b8IP&quot;&gt;Декомпилированный &lt;code&gt;KotlinClassSample&lt;/code&gt; c &lt;code&gt;public companion object&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;T8bp&quot; data-lang=&quot;java&quot;&gt;public final class KotlinClassSampleDecompiled {
 
    public static final CompanionObject Companion = new CompanionObject();

    public static void publicStaticFun() {
        Companion.publicStaticFun();
    }

    private static void privateStaticFun() {
        Companion.privateStaticFun();
    }

    public static final class CompanionObject {
  
        public void publicStaticFun() {}

        public void publicNonStaticFun() {}
        
        private void privateStaticFun() {}

        private void privateNonStaticFun() {}
    }
}&lt;/pre&gt;
  &lt;p id=&quot;uU3W&quot;&gt;Декомпилированный &lt;code&gt;KotlinClassSample&lt;/code&gt;  c &lt;code&gt;private companion object&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;H6SH&quot; data-lang=&quot;java&quot;&gt;public final class KotlinClassSampleDecompiled {

    private static final CompanionObject Companion = new CompanionObject();

    public static void publicStaticFun() {
        Companion.publicStaticFun();
    }

    private static void privateStaticFun() {
        Companion.privateStaticFun();
    }

    private static final class CompanionObject {

        public void publicStaticFun() {}

        public void publicNonStaticFun() {}

        private void privateStaticFun() {}

        private void privateNonStaticFun() {}
    }
}&lt;/pre&gt;
  &lt;p id=&quot;rPMo&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;49az&quot;&gt;Литература&lt;/h2&gt;
  &lt;ul id=&quot;klBg&quot;&gt;
    &lt;li id=&quot;wLuR&quot;&gt;&lt;a href=&quot;https://kotlinlang.org/docs/java-to-kotlin-interop.html#static-fields&quot; target=&quot;_blank&quot;&gt;https://kotlinlang.org/docs/java-to-kotlin-interop.html#static-fields&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;A186&quot;&gt;&lt;a href=&quot;https://kotlinlang.org/docs/java-to-kotlin-interop.html#static-methods&quot; target=&quot;_blank&quot;&gt;https://kotlinlang.org/docs/java-to-kotlin-interop.html#static-methods&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;dtC4&quot;&gt;&lt;a href=&quot;https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-jvm-field&quot; target=&quot;_blank&quot;&gt;https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-jvm-field&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;

</content></entry><entry><id>hikkidev:memo-ifecycle-runtime-ktx-and-kotlin-flow</id><link rel="alternate" type="text/html" href="https://teletype.in/@hikkidev/memo-ifecycle-runtime-ktx-and-kotlin-flow?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=hikkidev"></link><title>Памятка: как подписываться на Kotlin Coroutines Flow с lifecycle-runtime-ktx версии 2.4.0 и выше</title><published>2023-03-21T02:52:39.932Z</published><updated>2023-03-21T05:16:58.425Z</updated><summary type="html">&lt;img src=&quot;https://img1.teletype.in/files/0b/bb/0bbb9ba9-efdd-4142-b857-4039aa362d76.png&quot;&gt;
Рассмотрим поведение на примере с отображением некоторых данных на пользовательский интерфейс (UI).</summary><content type="html">
  &lt;nav&gt;
    &lt;ul&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#NIbn&quot;&gt;Введение&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#N6Hk&quot;&gt;Подписка на Flow для версии lifecycle-runtime-ktx ниже 2.4.0&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#ZViM&quot;&gt;Что за viewLifecycleOwner.lifecycleScope ?&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#DTpO&quot;&gt;Подписка на Flow для версии lifecycle-runtime-ktx 2.4.0 и выше&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/nav&gt;
  &lt;h3 id=&quot;NIbn&quot;&gt;Введение&lt;/h3&gt;
  &lt;p id=&quot;T3Im&quot;&gt;&lt;br /&gt;Рассмотрим поведение на примере с отображением некоторых данных на пользовательский интерфейс (UI).&lt;/p&gt;
  &lt;p id=&quot;WRbl&quot;&gt;Пусть дан фрагмент:&lt;/p&gt;
  &lt;pre id=&quot;yedk&quot; data-lang=&quot;kotlin&quot;&gt;class SampleFragment : BindingFragment(R.layout.fragment_sample) {
    override val binding by viewBinding&amp;lt;FragmentSampleBinding&amp;gt;()
    override val viewModel by viewModelFactory&amp;lt;SampleViewModel&amp;gt;()
}&lt;/pre&gt;
  &lt;p id=&quot;7vB5&quot;&gt;где функции &lt;code&gt;viewBinding&lt;/code&gt; и &lt;code&gt;viewModelFactory&lt;/code&gt; являются некоторыми &lt;a href=&quot;https://kotlinlang.org/docs/delegated-properties.html&quot; target=&quot;_blank&quot;&gt;PropertyDelegate&lt;/a&gt;.&lt;/p&gt;
  &lt;p id=&quot;l09E&quot;&gt;Цель - &lt;strong&gt;перезапускать&lt;/strong&gt; подписку на &lt;code&gt;Flow&lt;/code&gt; только в те моменты, когда пользовательский интерфейс &lt;strong&gt;виден&lt;/strong&gt;. Использование функций &lt;code&gt;launchWhen*&lt;/code&gt; неподходит, так как корутина &lt;strong&gt;приостанавливает&lt;/strong&gt; своё выполнение.&lt;/p&gt;
  &lt;ul id=&quot;9G3S&quot;&gt;
    &lt;li id=&quot;I0nO&quot;&gt;&lt;code&gt;&lt;a href=&quot;https://developer.android.com/reference/androidx/fragment/app/Fragment#onStart()&quot; target=&quot;_blank&quot;&gt;Fragment.onStart()&lt;/a&gt;&lt;/code&gt; срабатывает, когда &lt;code&gt;Fragment&lt;/code&gt; становится видимым для пользователя без взаимодействия. Это хорошее место, чтобы начать рисовать визуальные элементы, запускать анимацию и т.д.&lt;/li&gt;
    &lt;li id=&quot;wbCm&quot;&gt;&lt;code&gt;&lt;a href=&quot;https://developer.android.com/reference/androidx/fragment/app/Fragment#onStop()&quot; target=&quot;_blank&quot;&gt;Fragment.onStop()&lt;/a&gt;&lt;/code&gt; вызывается, когда &lt;code&gt;Fragment&lt;/code&gt; перестает быть видимым для пользователя. Это хорошее место для прекращения обновления пользовательского интерфейса, отмены анимации и других визуальных действий.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;hr /&gt;
  &lt;h3 id=&quot;N6Hk&quot;&gt;Подписка на Flow для версии lifecycle-runtime-ktx ниже 2.4.0&lt;/h3&gt;
  &lt;p id=&quot;rSjD&quot;&gt;&lt;br /&gt;Если требуется выполнить подписку только для одного &lt;code&gt;Flow&lt;/code&gt;, то достаточно вызвать &lt;code&gt;Flow.collect()&lt;/code&gt; в рамках начальной корутины &lt;code&gt;uiChangesJob&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;SRGT&quot; data-lang=&quot;kotlin&quot;&gt;import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.collect  
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
...
import androidx.lifecycle.lifecycleScope

class SampleFragment : BindingFragment(R.layout.fragment_sample) {
	...
    private var uiChangesJob: Job? = null
	
	override fun onStart() {
	    super.onStart()
	    uiChangesJob = viewLifecycleOwner.lifecycleScope.launch {
	        // Делаем свою магию, например подписка
	        viewModel.screenState
		        .onEach { state -&amp;gt; render(state) }
		        .collect()
	    }
	}
	
	override fun onStop() {
	    uiChangesJob?.cancel()
	    super.onStop()
	}
}&lt;/pre&gt;
  &lt;p id=&quot;wtBW&quot;&gt;Однако если требуется выполнить подписку для нескольких &lt;code&gt;Flow&lt;/code&gt; параллельно, то необходимо подписываться на каждый Flow в разных корутинах. В этом случае эффективнее использовать &lt;code&gt;&lt;a href=&quot;https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/launch-in.html&quot; target=&quot;_blank&quot;&gt;Flow.launchIn()&lt;/a&gt;&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;EQ2s&quot; data-lang=&quot;kotlin&quot;&gt;uiChangesJob = viewLifecycleOwner.lifecycleScope.launch {

	viewModel.screenTitleFlow
		.onEach { text -&amp;gt; binding.titleView.text = text }
		.launchIn(this)
	
	viewModel.buttonStateFlow
		.onEach { isEnabled -&amp;gt; binding.buttonView.isEnabled = isEnabled }
		.launchIn(this)
	...
}&lt;/pre&gt;
  &lt;hr /&gt;
  &lt;h3 id=&quot;ZViM&quot;&gt;Что за &lt;code&gt;viewLifecycleOwner.lifecycleScope&lt;/code&gt; ?&lt;/h3&gt;
  &lt;p id=&quot;xU42&quot;&gt;&lt;br /&gt;Начнём с того, что &lt;code&gt;&lt;a href=&quot;https://developer.android.com/reference/androidx/fragment/app/Fragment#getViewLifecycleOwner%28%29&quot; target=&quot;_blank&quot;&gt;viewLifecycleOwner&lt;/a&gt;&lt;/code&gt; - это &lt;code&gt;LifecycleOwner&lt;/code&gt;, который описывает жизненный цикл представления &lt;code&gt;&lt;a href=&quot;https://developer.android.com/reference/androidx/fragment/app/Fragment#onCreateView(android.view.LayoutInflater,android.view.ViewGroup,android.os.Bundle)&quot; target=&quot;_blank&quot;&gt;Fragment.onCreateView()&lt;/a&gt;&lt;/code&gt;. &lt;/p&gt;
  &lt;p id=&quot;41VA&quot;&gt;Далее &lt;code&gt;&lt;a href=&quot;https://developer.android.com/topic/libraries/architecture/coroutines#lifecyclescope&quot; target=&quot;_blank&quot;&gt;LifecycleScope&lt;/a&gt;&lt;/code&gt;  -  это &lt;code&gt;&lt;a href=&quot;https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/&quot; target=&quot;_blank&quot;&gt;CoroutineScope&lt;/a&gt;&lt;/code&gt; жизненного цикла, который определен для каждого объекта &lt;code&gt;Lifecycle&lt;/code&gt;. &lt;br /&gt;По умолчанию экземпляр &lt;code&gt;LifecycleScope&lt;/code&gt; &lt;u&gt;создается &lt;strong&gt;только&lt;/strong&gt; в момент доступа&lt;/u&gt; к свойству &lt;code&gt;LifecycleOwner.lifecycleScope&lt;/code&gt;. &lt;br /&gt;&lt;br /&gt;Поскольку &lt;code&gt;androidx.fragment.app.Fragment&lt;/code&gt; является объектом &lt;code&gt;Lifecycle&lt;/code&gt;, то&lt;/p&gt;
  &lt;ul id=&quot;rgnu&quot;&gt;
    &lt;li id=&quot;ommw&quot;&gt;корутины объявленные во &lt;code&gt;Fragment.lifecycleScope&lt;/code&gt; могут существовать                                   после вызова первичного конструктора &lt;code&gt;Fragment()&lt;/code&gt; и до вызова &lt;code&gt;Fragment.onDestroy()&lt;/code&gt;.&lt;/li&gt;
    &lt;li id=&quot;yRc0&quot;&gt;корутины объявленные во &lt;code&gt;Fragment.viewLifecycleOwner.lifecycleScope&lt;/code&gt; могут существовать от вызова &lt;code&gt;Fragment.onViewStateRestored()&lt;/code&gt; до вызова &lt;code&gt;Fragment.onDestroyView()&lt;/code&gt;.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;HCF5&quot;&gt;&lt;/p&gt;
  &lt;figure id=&quot;w1kq&quot; class=&quot;m_retina&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/0b/bb/0bbb9ba9-efdd-4142-b857-4039aa362d76.png&quot; width=&quot;928&quot; /&gt;
    &lt;figcaption&gt;Диаграмма сопоставления состояний ЖЦ &lt;code&gt;Lifecycle&lt;/code&gt; и обратных вызовов &lt;code&gt;Fragment&lt;/code&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;M1ks&quot;&gt;&lt;/p&gt;
  &lt;blockquote id=&quot;2iTz&quot;&gt;Для эффективного использования ресурсов устройства разработчику необходимо (но недостаточно) понимать тонкости работы жизненного цикла и особенностей Coroutines. Все зависит от целей использования, главное понимание границ!&lt;/blockquote&gt;
  &lt;hr /&gt;
  &lt;h3 id=&quot;DTpO&quot;&gt;Подписка на Flow для версии lifecycle-runtime-ktx 2.4.0 и выше&lt;/h3&gt;
  &lt;p id=&quot;dXVC&quot;&gt;&lt;br /&gt;Тут все гораздо проще. Теперь API предоставляет специальную функцию, которая избавляет разработчика писать &lt;a href=&quot;https://ru.wikipedia.org/wiki/%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D0%BD%D1%8B%D0%B9_%D0%BA%D0%BE%D0%B4&quot; target=&quot;_blank&quot;&gt;шаблонный код&lt;/a&gt; с подписками/отписками. &lt;/p&gt;
  &lt;blockquote id=&quot;uZfC&quot;&gt;Данный поход является официальной рекомендацией к использованию.&lt;/blockquote&gt;
  &lt;p id=&quot;2sdS&quot;&gt;Если требуется выполнить подписку только для одного &lt;code&gt;Flow&lt;/code&gt;, то достаточно вызвать &lt;code&gt;&lt;a href=&quot;https://developer.android.com/reference/kotlin/androidx/lifecycle/package-summary#(kotlinx.coroutines.flow.Flow).flowWithLifecycle(androidx.lifecycle.Lifecycle,androidx.lifecycle.Lifecycle.State)&quot; target=&quot;_blank&quot;&gt;Flow.flowWithLifecycle()&lt;/a&gt;&lt;/code&gt; в рамках начальной корутины:&lt;/p&gt;
  &lt;pre id=&quot;ckOc&quot; data-lang=&quot;kotlin&quot;&gt;import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.collect  
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
...
import androidx.lifecycle.lifecycleScope

class SampleFragment : BindingFragment(R.layout.fragment_sample) {
	...
	
	override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
	    viewLifecycleOwner.lifecycleScope.launch {
	        viewModel.screenState
		        .flowWithLifecycle(viewLifecycleOwner.lifecycle,Lifecycle.State.STARTED)
		        .collect { state -&amp;gt; render(state) }
	    }
	}
}&lt;/pre&gt;
  &lt;p id=&quot;6rQb&quot;&gt;Однако если требуется выполнить подписку для нескольких &lt;code&gt;Flow&lt;/code&gt; параллельно, то необходимо подписываться на каждый &lt;code&gt;Flow&lt;/code&gt; в разных корутинах. В этом случае эффективнее использовать &lt;code&gt;&lt;a href=&quot;https://developer.android.com/reference/kotlin/androidx/lifecycle/package-summary#(androidx.lifecycle.LifecycleOwner).repeatOnLifecycle(androidx.lifecycle.Lifecycle.State,kotlin.coroutines.SuspendFunction1)&quot; target=&quot;_blank&quot;&gt;LifecycleOwner.repeatOnLifecycle()&lt;/a&gt;&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;hAuQ&quot; data-lang=&quot;kotlin&quot;&gt;viewLifecycleOwner.lifecycleScope.launch {
    // Можно вставить код, который исполнится до состояния ЖЦ STARTED
	viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
	    // repeatOnLifecycle запускает блок в новой короутине каждый раз, когда
		// жизненный цикл находится в состоянии STARTED (или выше)
		// и отменяет его, когда он STOPPED.
		viewModel.screenTitleFlow
			.onEach { text -&amp;gt; binding.titleView.text = text }
			.launchIn(this)
		
		viewModel.buttonStateFlow
			.onEach { isEnabled -&amp;gt; binding.buttonView.isEnabled = isEnabled }
			.launchIn(this)
	}
}&lt;/pre&gt;

</content></entry><entry><id>hikkidev:yubikey-as-login-pam</id><link rel="alternate" type="text/html" href="https://teletype.in/@hikkidev/yubikey-as-login-pam?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=hikkidev"></link><title>The Yubikey as a Login device on local Arch Linux</title><published>2022-10-07T16:00:10.449Z</published><updated>2022-10-17T04:27:50.157Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img1.teletype.in/files/0e/da/0edacf72-f2a8-4292-9112-bec39de11faf.png"></media:thumbnail><category term="arch-linux" label="Arch Linux"></category><summary type="html">&lt;img src=&quot;https://img3.teletype.in/files/e7/9f/e79f928b-e3bf-4450-b3b5-c67cb49f8207.png&quot;&gt;Note: Recommended specifying the actual hostname into the environment variableHOST. Keep in mind that in the command above, the actual hostname is picked from the file /etc/hostname.</summary><content type="html">
  &lt;h3 id=&quot;mx03&quot;&gt;1) Installing the &lt;a href=&quot;https://archlinux.org/packages/community/x86_64/pam-u2f/&quot; target=&quot;_blank&quot;&gt;PAM module&lt;/a&gt;&lt;/h3&gt;
  &lt;pre id=&quot;JT3S&quot;&gt;sudo pacman -S pam-u2f&lt;/pre&gt;
  &lt;hr /&gt;
  &lt;h3 id=&quot;HzJl&quot;&gt;2) Associating the U2F Key with Your Account&lt;/h3&gt;
  &lt;ul id=&quot;1Aon&quot;&gt;
    &lt;li id=&quot;0MW9&quot;&gt;Insert your U2F Key&lt;/li&gt;
    &lt;li id=&quot;ULgR&quot;&gt;Run command below. When your device begins flashing, touch the metal contact to confirm the association.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;pre id=&quot;VIJO&quot;&gt;HOST=$(cat /etc/hostname) pamu2fcfg -o pam://$HOST -i pam://$HOST &amp;gt; u2f_keys &amp;amp;&amp;amp; sudo mkdir -vp /etc/Yubico &amp;amp;&amp;amp; sudo mv -v u2f_keys /etc/Yubico&lt;/pre&gt;
  &lt;p id=&quot;hHnK&quot;&gt;&lt;strong&gt;Note:&lt;/strong&gt; Recommended specifying the actual hostname into the environment variable&lt;code&gt;HOST&lt;/code&gt;. Keep in mind that in the command above, the actual hostname is picked from the file &lt;code&gt;/etc/hostname&lt;/code&gt;.&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h3 id=&quot;pIT7&quot;&gt;3) Configuring the System to use the U2F Keys&lt;/h3&gt;
  &lt;p id=&quot;mC43&quot;&gt;Open the &lt;code&gt;system-login&lt;/code&gt; file and add the following &lt;strong&gt;debug&lt;/strong&gt; or &lt;strong&gt;release&lt;/strong&gt; line to the top of the &lt;code&gt;auth&lt;/code&gt; section. &lt;/p&gt;
  &lt;pre id=&quot;90Gf&quot;&gt;sudo $EDITOR /etc/pam.d/system-login&lt;/pre&gt;
  &lt;p id=&quot;nMs5&quot;&gt;&lt;strong&gt;MODE: Debug&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;fI8W&quot;&gt;auth  sufficient  pam_u2f.so  debug debug_file=/var/log/pam_u2f.log authfile=/etc/Yubico/u2f_keys cue&lt;/pre&gt;
  &lt;p id=&quot;f5Yf&quot;&gt;&lt;strong&gt;MODE: Release&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;Xx4T&quot;&gt;auth  sufficient  pam_u2f.so  authfile=/etc/Yubico/u2f_keys cue&lt;/pre&gt;
  &lt;p id=&quot;Qxoj&quot;&gt;&lt;strong&gt;Notes:&lt;/strong&gt; &lt;/p&gt;
  &lt;ul id=&quot;eZhE&quot;&gt;
    &lt;li id=&quot;IJ3K&quot;&gt;The reason that the &lt;code&gt;sufficient&lt;/code&gt; line is there is that if the u2f-key is messed up, then you&amp;#x27;ll be able to log on via password.&lt;/li&gt;
    &lt;li id=&quot;JxeZ&quot;&gt;The option &lt;code&gt;cue&lt;/code&gt; is set to provide indication of what to do, i.e. &lt;code&gt;Please touch the device&lt;/code&gt;.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;figure id=&quot;YPlA&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/e7/9f/e79f928b-e3bf-4450-b3b5-c67cb49f8207.png&quot; width=&quot;859&quot; /&gt;
    &lt;figcaption&gt;An example of the content of &amp;#x60;system-login&amp;#x60; with a release line.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;aK8v&quot;&gt;&lt;strong&gt;Note:&lt;/strong&gt; You can select another PAM-stack:&lt;/p&gt;
  &lt;blockquote id=&quot;ZnJ0&quot;&gt;The &lt;code&gt;/etc/pam.d/&lt;/code&gt; path is exclusive for the PAM configuration to link the applications to the individual systems&amp;#x27; authentication schemes. &lt;/blockquote&gt;
  &lt;blockquote id=&quot;JEG6&quot;&gt;The different configuration files of the base installation link together and are stacked during runtime. For example, on a local user logon, the &lt;em&gt;login&lt;/em&gt; application sources the &lt;code&gt;system-local-login&lt;/code&gt; policy, which in turn sources others:&lt;/blockquote&gt;
  &lt;pre id=&quot;imEP&quot;&gt;/etc/pam.d/
----------------------------------------------------------
login -&amp;gt; system-local-login -&amp;gt; system-login -&amp;gt; system-auth&lt;/pre&gt;
  &lt;p id=&quot;jqrl&quot;&gt;Source: &lt;a href=&quot;https://wiki.archlinux.org/title/PAM&quot; target=&quot;_blank&quot;&gt;https://wiki.archlinux.org/title/PAM&lt;/a&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h3 id=&quot;izZx&quot;&gt;4) Reboot the computer or exit from your session.&lt;/h3&gt;
  &lt;h3 id=&quot;eUxq&quot;&gt;5) When the login screen is loaded, it should ask you to touch the device.&lt;/h3&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;3kPx&quot;&gt;&lt;/h2&gt;
  &lt;h2 id=&quot;vSnT&quot;&gt;References&lt;/h2&gt;
  &lt;ol id=&quot;JCfr&quot;&gt;
    &lt;li id=&quot;3Iqw&quot;&gt;&lt;a href=&quot;https://wiki.archlinux.org/title/PAM&quot; target=&quot;_blank&quot;&gt;https://wiki.archlinux.org/title/PAM&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;arWT&quot;&gt;&lt;a href=&quot;https://wiki.archlinux.org/title/Universal_2nd_Factor&quot; target=&quot;_blank&quot;&gt;https://wiki.archlinux.org/title/Universal_2nd_Factor&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;JMB0&quot;&gt;&lt;a href=&quot;https://wiki.archlinux.org/title/YubiKey#Linux_user_authentication_with_PAM&quot; target=&quot;_blank&quot;&gt;https://wiki.archlinux.org/title/YubiKey#Linux_user_authentication_with_PAM&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;tMk1&quot;&gt;&lt;a href=&quot;https://support.yubico.com/hc/en-us/articles/360016649099-Ubuntu-Linux-Login-Guide-U2F&quot; target=&quot;_blank&quot;&gt;https://support.yubico.com/hc/en-us/articles/360016649099-Ubuntu-Linux-Login-Guide-U2F&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;TSON&quot;&gt;&lt;a href=&quot;https://jamesthebard.net/archlinux-and-u2f-login/&quot; target=&quot;_blank&quot;&gt;https://jamesthebard.net/archlinux-and-u2f-login/&lt;/a&gt;&lt;/li&gt;
  &lt;/ol&gt;

</content></entry><entry><id>hikkidev:android-studio-logcat-config</id><link rel="alternate" type="text/html" href="https://teletype.in/@hikkidev/android-studio-logcat-config?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=hikkidev"></link><title>View Logs with Logcat (Android Studio Dolphin и ниже)</title><published>2022-04-13T15:56:31.920Z</published><updated>2023-10-05T10:38:04.303Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img4.teletype.in/files/38/50/38509653-b7d4-492a-80fe-fcf1efdb05d7.png"></media:thumbnail><category term="android-studio" label="Android Studio"></category><summary type="html">&lt;img src=&quot;https://img2.teletype.in/files/1e/d0/1ed03ca1-be26-4c23-8080-336c8408213f.png&quot;&gt;Обновленный Logcat -&gt; https://alexzh.com/new-logcat-5-features-for-effective-android-app-debugging/</summary><content type="html">
  &lt;p id=&quot;CgEb&quot;&gt;В версии Android Studio Electric Eel | 2022.1.1 (Jan 2023) был включен новый Logcat, чтобы упростить анализ, запросы и отслеживание журналов. Поэтому данная актуальна только для старых версий Android Studio: Dolphin и ниже.&lt;br /&gt;&lt;/p&gt;
  &lt;p id=&quot;kXDH&quot;&gt;Обновленный Logcat -&amp;gt; &lt;a href=&quot;https://alexzh.com/new-logcat-5-features-for-effective-android-app-debugging/&quot; target=&quot;_blank&quot;&gt;https://alexzh.com/new-logcat-5-features-for-effective-android-app-debugging/&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;
  &lt;nav&gt;
    &lt;ul&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#x0BA&quot;&gt;Что такое Logcat&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#XCU7&quot;&gt;Просмотр журнала (View your app logs)&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#RIzT&quot;&gt;Основные функции 1-9 в окне Logcat&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#1rHO&quot;&gt;Формат сообщения Logcat&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#e6jr&quot;&gt;Установка цветовой схемы&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#jMRF&quot;&gt;Фильтрация сообщений Logcat&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#WvLs&quot;&gt;Global-Filter (E)&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#kPDu&quot;&gt;Добавление новых фильтров&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#tMi9&quot;&gt;Исключить сообщения ОС из Logcat&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#HSYA&quot;&gt;Log level (описание)&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#pvQU&quot;&gt;Search Filter (D)&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#T5k5&quot;&gt;Поиск в логах&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/nav&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;x0BA&quot; data-align=&quot;center&quot;&gt;Что такое Logcat&lt;/h2&gt;
  &lt;p id=&quot;2Ehm&quot;&gt;Окно Logcat в Android Studio отображает системные сообщения (Логи) в режиме реального времени и хранит историю, чтобы вы могли просматривать более старые сообщения. Например, когда приложение выдает исключение, logcat показывает сообщение, за которым следует соответствующая трассировка стека, содержащая ссылки на строку кода.&lt;/p&gt;
  &lt;p id=&quot;C645&quot;&gt;Чтобы отображать только интересующую информацию, вы можете создавать фильтры, изменять объем информации, отображаемой в сообщениях, устанавливать уровни приоритета, отображать сообщения, созданные только кодом приложения, и выполнять поиск в журнале. &lt;/p&gt;
  &lt;p id=&quot;EeMg&quot;&gt;По умолчанию logcat показывает выходные данные журнала, относящиеся только к последнему запущенному приложению.&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;XCU7&quot;&gt;Просмотр журнала (View your app logs)&lt;/h2&gt;
  &lt;p id=&quot;y6Oh&quot;&gt;Чтобы отобразить сообщения журнала для приложения:&lt;/p&gt;
  &lt;ol id=&quot;hTwG&quot;&gt;
    &lt;li id=&quot;ho3C&quot;&gt;Запустите приложение&lt;/li&gt;
    &lt;li id=&quot;Ck7G&quot;&gt;Нажмите &lt;strong&gt;View &amp;gt; Tool Windows &amp;gt; Logcat&lt;/strong&gt; (или нажмите Logcat на панели инструментов)&lt;/li&gt;
  &lt;/ol&gt;
  &lt;figure id=&quot;WJHM&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/1e/d0/1ed03ca1-be26-4c23-8080-336c8408213f.png&quot; width=&quot;407&quot; /&gt;
    &lt;figcaption&gt;Рисунок 1. Скриншот из Android Studio&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;I2yC&quot;&gt;В окне Logcat отображаются сообщения журнала для выбранного приложения, как показано на рисунке 2.&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;RIzT&quot; data-align=&quot;center&quot;&gt;Основные функции 1-9 в окне Logcat&lt;/h2&gt;
  &lt;figure id=&quot;gRXH&quot; class=&quot;m_retina&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/93/a3/93a38503-834b-479b-b725-1557a0d856ce.png&quot; width=&quot;1108&quot; /&gt;
    &lt;figcaption&gt;Рисунок 2. Окно Logcat.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;GyNh&quot;&gt;Рассмотрим боковые функции 1-9:&lt;/p&gt;
  &lt;ol id=&quot;cHV1&quot;&gt;
    &lt;li id=&quot;N6Oh&quot;&gt;&lt;strong&gt;Очистка:&lt;/strong&gt; Нажмите, чтобы очистить видимый журнал.&lt;/li&gt;
    &lt;li id=&quot;ujfQ&quot;&gt;&lt;strong&gt;Прокрутка в конец: &lt;/strong&gt;нажмите, чтобы перейти к нижней части журнала и просмотреть последние сообщения журнала. Если затем щелкнуть строку в журнале, представление приостановит прокрутку в этой точке.&lt;/li&gt;
    &lt;li id=&quot;3BNB&quot;&gt;&lt;strong&gt;Вверх и Вниз&lt;/strong&gt; по трассировке стека: Нажмите, чтобы перемещаться вверх и вниз по трассировке стека в журнале, выбирая последующие имена файлов (и просматривая соответствующие номера строк в редакторе), которые появляются в печатных исключениях. Это то же самое поведение, что и при нажатии на имя файла в журнале.&lt;/li&gt;
    &lt;li id=&quot;uKGz&quot;&gt;Использовать&lt;strong&gt; мягкие переносы&lt;/strong&gt;: нажмите, чтобы включить перенос строк и запретить горизонтальную прокрутку (хотя любые неразрывные строки по-прежнему требуют горизонтальной прокрутки).&lt;/li&gt;
    &lt;li id=&quot;Ixpc&quot;&gt;&lt;strong&gt;Печать&lt;/strong&gt;: Нажмите, чтобы распечатать сообщения logcat. После выбора настроек печати в появившемся диалоговом окне вы также можете сохранить файл в формате PDF.&lt;/li&gt;
    &lt;li id=&quot;VgGA&quot;&gt;&lt;strong&gt;Перезапустить&lt;/strong&gt;: нажмите, чтобы очистить журнал и перезапустить logcat. В отличие от кнопки «Очистить logcat», эта кнопка восстанавливает и отображает предыдущие сообщения журнала, поэтому наиболее полезна, если Logcat перестает отвечать на запросы и вы не хотите терять сообщения журнала.&lt;/li&gt;
    &lt;li id=&quot;1ubH&quot;&gt;&lt;strong&gt;Заголовок Logcat:&lt;/strong&gt; нажмите, чтобы открыть диалоговое окно «Настройка заголовка Logcat», в котором можно настроить внешний вид каждого сообщения logcat, например указать, показывать ли дату и время (Рисунки 3-4.)&lt;/li&gt;
    &lt;li id=&quot;a7R6&quot;&gt;&lt;strong&gt;Снимок &lt;/strong&gt;экрана: нажмите, чтобы сделать снимок экрана.&lt;/li&gt;
    &lt;li id=&quot;WUjf&quot;&gt;&lt;strong&gt;Запись &lt;/strong&gt;экрана: Нажмите, чтобы записать видео с устройства (максимум 3 минуты).&lt;/li&gt;
  &lt;/ol&gt;
  &lt;figure id=&quot;G72W&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/da/c7/dac73c58-8d57-4f48-8633-4d6ac05e6bd9.png&quot; width=&quot;830&quot; /&gt;
    &lt;figcaption&gt;Рисунок 3.  Настройка заголовка Logcat.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;S0DI&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/e3/4b/e34bf816-f109-4de8-b381-5501979be0f2.png&quot; width=&quot;830&quot; /&gt;
    &lt;figcaption&gt;Рисунок 4. Рекомендую следующие настройки для повышения читабельности.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;MSbc&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;1rHO&quot;&gt;Формат сообщения Logcat&lt;/h3&gt;
  &lt;p id=&quot;hTj8&quot;&gt;Все сообщения журнала Android имеют определенный формат:&lt;/p&gt;
  &lt;pre id=&quot;hK6r&quot;&gt;Date Time PID-TID/package priority/tag: message &lt;/pre&gt;
  &lt;p id=&quot;aw9c&quot;&gt;На рисунках 3-4, можно наблюдать пример настройки отображения данного формата. Подробнее &lt;a href=&quot;https://developer.android.com/studio/debug/am-logcat#format&quot; target=&quot;_blank&quot;&gt;https://developer.android.com/studio/debug/am-logcat#format&lt;/a&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;e6jr&quot; data-align=&quot;center&quot;&gt;Установка цветовой схемы&lt;/h2&gt;
  &lt;ol id=&quot;qvrD&quot;&gt;
    &lt;li id=&quot;kU7s&quot;&gt;В Android Studio нажмите &lt;strong&gt;File &amp;gt; Settings &lt;/strong&gt;(Рисунок 5)&lt;strong&gt;.&lt;/strong&gt;&lt;/li&gt;
    &lt;li id=&quot;PxGp&quot;&gt;В окне настроек откройте раздел &lt;strong&gt;Editor &amp;gt; Color Scheme &amp;gt; Android Logcat.&lt;/strong&gt;&lt;/li&gt;
    &lt;li id=&quot;7nFJ&quot;&gt;&lt;a href=&quot;https://mega.nz/file/oY1yBIrY#gKM4LgOjnFBAGYY6z-FciMeQZuMiFNgRT2oWF3j2MtE&quot; target=&quot;_blank&quot;&gt;Скачайте &lt;/a&gt;файл настроек цветовой схемы.&lt;/li&gt;
    &lt;li id=&quot;cwt9&quot;&gt;Импортируйте и примените цветовую схему (Рисунок 6).&lt;/li&gt;
  &lt;/ol&gt;
  &lt;figure id=&quot;sCU1&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/3a/05/3a057152-4cf6-4759-82c1-2be0b428423a.png&quot; width=&quot;295&quot; /&gt;
    &lt;figcaption&gt;Рисунок 5. Настройки Android Studio.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;6gwP&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/2d/c8/2dc8cd41-5e8c-475f-8286-bd762faa2b36.png&quot; width=&quot;984&quot; /&gt;
    &lt;figcaption&gt;Рисунок 6. Импортирование цветовой схемы для Logcat.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;tI8L&quot;&gt;Теперь логи относящиеся к разным типа сообщений будут иметь различные цвета, что упростит навигацию.&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;jMRF&quot; data-align=&quot;center&quot;&gt;Фильтрация сообщений Logcat&lt;/h2&gt;
  &lt;figure id=&quot;Fx0G&quot; class=&quot;m_retina&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/93/a3/93a38503-834b-479b-b725-1557a0d856ce.png&quot; width=&quot;1108&quot; /&gt;
    &lt;figcaption&gt;Рисунок 7. Окно Logcat.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;yPan&quot;&gt;Перейдем к основным функциям A-E:&lt;/p&gt;
  &lt;ul id=&quot;GcpS&quot;&gt;
    &lt;li id=&quot;ZZW2&quot;&gt;&lt;strong&gt;A) Current-Device:&lt;/strong&gt; Выбор устройства к которому подключится adb. По клику отобразится список доступных устройств (те у которых включен &lt;a href=&quot;https://docs.microsoft.com/ru-ru/mem/intune/user-help/you-need-to-turn-off-usb-debugging-android&quot; target=&quot;_blank&quot;&gt;режим отладки&lt;/a&gt; в &lt;a href=&quot;https://www.google.com/search?q=android+%D1%80%D0%B5%D0%B6%D0%B8%D0%BC+%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%87%D0%B8%D0%BA%D0%B0&amp;ei=Me1WYoDFHaiorgTsw5qgBw&amp;start=0&amp;sa=N&amp;ved=2ahUKEwjAoaGmrpH3AhUolIsKHeyhBnQ4ChDy0wN6BAgBEDw&amp;biw=1718&amp;bih=1200&amp;dpr=1&quot; target=&quot;_blank&quot;&gt;настройках разработчика&lt;/a&gt;)&lt;/li&gt;
    &lt;li id=&quot;tZoV&quot;&gt;&lt;strong&gt;B) Current-Application:&lt;/strong&gt; Выбор приложения для отладки к которому подключится Logcat. По клику отобразится список запущенных приложений для отладки. Приложение должно быть скомпилировано в режиме  отладки (DEBUG). По умолчанию выбирается последнее запущенное приложение, &lt;strong&gt;если &lt;/strong&gt;это возможно.&lt;/li&gt;
    &lt;li id=&quot;IMu8&quot;&gt;&lt;strong&gt;C) &lt;a href=&quot;#HSYA&quot;&gt;Log-Level&lt;/a&gt;-Filter:&lt;/strong&gt; Верхне уровневый фильтр по типу сообщения.&lt;/li&gt;
    &lt;li id=&quot;B50d&quot;&gt;&lt;strong&gt;D) &lt;a href=&quot;#pvQU&quot;&gt;Search-Filter&lt;/a&gt;:&lt;/strong&gt; Для поиска сообщений, отображаемых в данный момент в Logcat (При необходимости выберите Regex, если вы хотите использовать шаблон поиска &lt;a href=&quot;https://ru.wikipedia.org/wiki/%D0%A0%D0%B5%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D0%B5_%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F&quot; target=&quot;_blank&quot;&gt;регулярного выражения&lt;/a&gt;)&lt;/li&gt;
    &lt;li id=&quot;Jk5v&quot;&gt;&lt;strong&gt;E) &lt;a href=&quot;#WvLs&quot;&gt;Global-Filter&lt;/a&gt;:&lt;/strong&gt; Верхне уровневый фильтр, применяется ко всей вашей истории Logcat, а не только к тем сообщениям, которые в данный момент отображаются в logcat.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;v7Hc&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;WvLs&quot;&gt;Global-Filter (E)&lt;/h2&gt;
  &lt;p id=&quot;UspL&quot;&gt;&lt;a href=&quot;https://developer.android.com/studio/debug/am-logcat#filtering&quot; target=&quot;_blank&quot;&gt;Оригинал&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;oO7Y&quot;&gt;В меню фильтра выберите параметр фильтра:&lt;/p&gt;
  &lt;figure id=&quot;qAzK&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/11/70/117078d6-dc35-47a7-bb43-4ff8aa3e56dc.png&quot; width=&quot;324&quot; /&gt;
    &lt;figcaption&gt;Рисунок 8. Меню выбора настроек для глобального фильтра.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;ul id=&quot;GLCf&quot;&gt;
    &lt;li id=&quot;N8VL&quot;&gt;&lt;strong&gt;Show only selected application&lt;/strong&gt;: отображать только сообщения, созданные кодом приложения (по умолчанию). Logcat фильтрует сообщения журнала, используя PID активного приложения.&lt;/li&gt;
    &lt;li id=&quot;iCVO&quot;&gt;&lt;strong&gt;No filters:&lt;/strong&gt; не применять фильтры. Logcat отображает все сообщения журнала с устройства, независимо от того, какой процесс вы выбрали.&lt;/li&gt;
    &lt;li id=&quot;QXAO&quot;&gt;&lt;strong&gt;Edit Filter Configuration: &lt;/strong&gt;Создайте или измените пользовательский фильтр. Например, вы можете создать фильтр для одновременного просмотра сообщений журнала из двух приложений.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;h3 id=&quot;kPDu&quot;&gt;Добавление новых фильтров&lt;/h3&gt;
  &lt;p id=&quot;SNGd&quot;&gt;Чтобы создать новый фильтр, нажмите &lt;strong&gt;Edit Filter Configuration&lt;/strong&gt; в списке (Рис. 8).&lt;/p&gt;
  &lt;figure id=&quot;cUxK&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/9b/9e/9b9eee35-b55d-4808-a19a-6a7904532a38.png&quot; width=&quot;570&quot; /&gt;
    &lt;figcaption&gt;Рисунок 9. Диалоговое окно создания фильтра.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;r97r&quot;&gt;Укажите параметры фильтра в диалоговом окне Create New Logcat Filter:&lt;/p&gt;
  &lt;ul id=&quot;iHUz&quot;&gt;
    &lt;li id=&quot;KOc2&quot;&gt;&lt;strong&gt;Filter Name:&lt;/strong&gt; введите название фильтра или выберите его на левой панели, чтобы изменить существующий фильтр. Имя может содержать только символы нижнего регистра, символы подчеркивания и цифры.&lt;/li&gt;
    &lt;li id=&quot;Dzsc&quot;&gt;&lt;strong&gt;Log Tag:&lt;/strong&gt; При необходимости укажите тег. Тег определяется разработчиком, например это может быть название класса.&lt;/li&gt;
    &lt;li id=&quot;SLis&quot;&gt;&lt;strong&gt;Log Message:&lt;/strong&gt; При необходимости укажите текст сообщения.&lt;/li&gt;
    &lt;li id=&quot;6C6k&quot;&gt;&lt;strong&gt;Package Name:&lt;/strong&gt; При необходимости укажите &lt;a href=&quot;https://support.google.com/admob/answer/9972781?hl=ru&quot; target=&quot;_blank&quot;&gt;название пакета приложения&lt;/a&gt;.&lt;/li&gt;
    &lt;li id=&quot;bLp5&quot;&gt;&lt;strong&gt;PID: &lt;/strong&gt;При необходимости укажите идентификатор процесса.&lt;/li&gt;
    &lt;li id=&quot;eI8r&quot;&gt;&lt;strong&gt;Log Level:&lt;/strong&gt; При необходимости выберите &lt;a href=&quot;#HSYA&quot;&gt;log-level&lt;/a&gt;.&lt;/li&gt;
    &lt;li id=&quot;1cxP&quot;&gt;&lt;strong&gt;Regex:&lt;/strong&gt; выберите этот параметр, чтобы использовать синтаксис &lt;a href=&quot;https://ru.wikipedia.org/wiki/%D0%A0%D0%B5%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D0%B5_%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F&quot; target=&quot;_blank&quot;&gt;регулярного выражения&lt;/a&gt; для этого параметра.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;blockquote id=&quot;xnLA&quot;&gt;Примечание: Имейте ввиду, что параметры фильтрации (tag, message, PID и т.д.) определены в &lt;a href=&quot;#1rHO&quot;&gt;формате вывода логов&lt;/a&gt; как сообщалось ранее.&lt;/blockquote&gt;
  &lt;h3 id=&quot;tMi9&quot;&gt;Исключить сообщения ОС из Logcat&lt;/h3&gt;
  &lt;p id=&quot;8c6U&quot;&gt;В журнале отображается очень много мусора, который в 90% случаев не важен, решение: создайте новый фильтр с регулярным выражением&lt;/p&gt;
  &lt;pre id=&quot;dWtQ&quot;&gt;^(?!.*(BtGatt|dalvik|Environment|DataRouter|FA|art|Wifi|ServiceManager|Atfwd|tnet|MDnsDS|Download|Bluetooth|slim|QSEECOMAPI|WVCdm|QC-time|sensors|nanohub|Drm|Babel|Dropbox|gsamlab|Cryptd|Vold|QC_|Conscrypt|Dns|sound|NetWork|OpenGL|TLog|GMPM|Microphone|Process|Dynamite|cr_|VideoCapabilities|libEGL|NetdEventListenerService|Sensors|Netd|audit|Zygote|Watchdog|ity|memtrack|fb4a|LoadedApk|ImsAdaptorImpl|EPDG|CursorWindow|tworkdiagnosti|PackageManager))&lt;/pre&gt;
  &lt;figure id=&quot;0npu&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/26/36/26364a44-abfc-42f6-b3f8-d55f61aee957.png&quot; width=&quot;570&quot; /&gt;
    &lt;figcaption&gt;Рисунок 10. Создание нового фильтра для Logcat.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;P0ee&quot;&gt;А затем выберете его из списка фильтров:&lt;/p&gt;
  &lt;figure id=&quot;Km2j&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/ce/b6/ceb69217-2ff6-4b0d-93f6-18d5853addec.png&quot; width=&quot;237&quot; /&gt;
    &lt;figcaption&gt;Рисунок 11. Список доступных фильтров.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;2vO2&quot;&gt;Вы также можете добавить новое ключевое слово\тег, который хотите игнорировать, с помощью «|» как разделитель.&lt;/p&gt;
  &lt;p id=&quot;LONE&quot;&gt;Автор: &lt;a href=&quot;https://medium.com/zinuzoid/if-you-developing-android-application-1bdff0a96205&quot; target=&quot;_blank&quot;&gt;https://medium.com/zinuzoid/if-you-developing-android-application-1bdff0a96205&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;RuGX&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;HSYA&quot;&gt;Log level (&lt;a href=&quot;https://developer.android.com/studio/debug/am-logcat#level&quot; target=&quot;_blank&quot;&gt;описание&lt;/a&gt;)&lt;/h3&gt;
  &lt;p id=&quot;6Gg9&quot;&gt;В меню Уровень журнала выберите одно из следующих значений: &lt;/p&gt;
  &lt;ul id=&quot;EdaU&quot;&gt;
    &lt;li id=&quot;PW8j&quot;&gt; &lt;strong&gt;Verbose&lt;/strong&gt;: показать все сообщения журнала (по умолчанию). &lt;/li&gt;
    &lt;li id=&quot;zyKC&quot;&gt; &lt;strong&gt;Debug&lt;/strong&gt;: Показать сообщения журнала отладки, которые полезны только во время разработки, а также уровни сообщений ниже в этом списке. &lt;/li&gt;
    &lt;li id=&quot;TF2Y&quot;&gt; &lt;strong&gt;Info&lt;/strong&gt;: Показать ожидаемые сообщения журнала для регулярного использования, а также уровни сообщений ниже в этом списке. &lt;/li&gt;
    &lt;li id=&quot;YGai&quot;&gt; &lt;strong&gt;Warn&lt;/strong&gt;: показывать возможные проблемы, которые еще не являются ошибками, а также уровни сообщений ниже в этом списке. &lt;/li&gt;
    &lt;li id=&quot;Wv2Q&quot;&gt; &lt;strong&gt;Error&lt;/strong&gt;: Показать проблемы, вызвавшие ошибки, а также уровень сообщения ниже в этом списке. &lt;/li&gt;
    &lt;li id=&quot;wiER&quot;&gt;&lt;strong&gt;Assert&lt;/strong&gt;: Показать проблемы, которые, по мнению разработчика, никогда не должны возникать.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;pvQU&quot;&gt;Search Filter (D)&lt;/h2&gt;
  &lt;p id=&quot;mqEa&quot;&gt;Данный тип фильтрации используется как уточнение для Global-Filter. Поскольку его удобно менять &amp;quot;на ходу&amp;quot;. Его &lt;strong&gt;отличие от Global-Filter&lt;/strong&gt; заключается в том, что &lt;strong&gt;поисковый запрос распространяется на сообщение целиком&lt;/strong&gt;, а не на определенный параметр(tag, level, PID, message) как это указывается при создании фильтра.&lt;/p&gt;
  &lt;p id=&quot;rCKa&quot;&gt;В качестве поискового запроса можно использовать шаблон &lt;a href=&quot;https://ru.wikipedia.org/wiki/%D0%A0%D0%B5%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D0%B5_%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F&quot; target=&quot;_blank&quot;&gt;регулярного выражения.&lt;/a&gt;&lt;/p&gt;
  &lt;figure id=&quot;bPLj&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/93/47/934717e8-fdd3-49e7-b17a-b04ab4e458d9.png&quot; width=&quot;494&quot; /&gt;
    &lt;figcaption&gt;Фильтр поисковой строки.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;8gTq&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/c0/55/c055e640-11a0-4a6b-974d-7f2ad67eea87.png&quot; width=&quot;1189&quot; /&gt;
    &lt;figcaption&gt;Результаты фильтрации: Вывод всех строк, где встречается слово &amp;quot;connection&amp;quot;.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Zjxa&quot;&gt;Примеры фильтрации поиска: в качестве запроса укажу пакет приложения &lt;strong&gt;id.apps.tachyo&lt;/strong&gt;&lt;/p&gt;
  &lt;figure id=&quot;qLaj&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/34/f9/34f9d4d5-dfe8-456a-bfb7-8e0f652717c5.png&quot; width=&quot;1096&quot; /&gt;
    &lt;figcaption&gt;Результаты фильтрации: Вывод всех строк, где встречается текст &amp;quot;id.apps.tachyo:&amp;quot;&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;fqNp&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/21/58/2158da94-52c5-4ff4-aa13-61781b64e983.png&quot; width=&quot;1098&quot; /&gt;
    &lt;figcaption&gt;Результаты фильтрации: Вывод всех строк, где встречается текст &amp;quot;id.apps.tachyo:&amp;quot; c Log-Level = Error&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;K42P&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/69/80/6980a594-f516-45da-88da-32397c036925.png&quot; width=&quot;1096&quot; /&gt;
    &lt;figcaption&gt;Результаты фильтрации: Вывод всех строк, где встречается текст &amp;quot;id.apps.tachyo:&amp;quot; c Log-Level = Warn&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;ZG6m&quot;&gt;Тот же самый результат, если добавить в поисковый результат Tag &amp;quot;W&amp;quot;, который отображает log-level.&lt;/p&gt;
  &lt;figure id=&quot;seYZ&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/1b/80/1b80f83d-394e-4a9d-8d2d-928775783463.png&quot; width=&quot;981&quot; /&gt;
    &lt;figcaption&gt;Результаты фильтрации: Вывод всех строк, где встречается текст &amp;quot;W/id.apps.tachyo:&amp;quot;&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;hr /&gt;
  &lt;h3 id=&quot;T5k5&quot;&gt;Поиск в логах&lt;/h3&gt;
  &lt;p id=&quot;IoBV&quot;&gt;Также, если нажать в окно вывода, а затем &lt;strong&gt;Ctrl+F&lt;/strong&gt;, то откроется поисковая строка, которая позволяет не фильтруя Logcat искать в нем нужный текст. Это бывает удобно, например если нужно подсветить ключевые фразы и видеть остальные логи.&lt;/p&gt;
  &lt;figure id=&quot;zX02&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/1f/b6/1fb6628c-4c4a-4e91-98a3-1b0ab6b6af23.png&quot; width=&quot;991&quot; /&gt;
    &lt;figcaption&gt;Поиск слова &amp;quot;hidden&amp;quot; в журнале.&lt;/figcaption&gt;
  &lt;/figure&gt;

</content></entry><entry><id>hikkidev:software-win</id><link rel="alternate" type="text/html" href="https://teletype.in/@hikkidev/software-win?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=hikkidev"></link><title>Windows 10 Software Pack 2022</title><published>2020-09-19T11:17:42.353Z</published><updated>2022-10-17T04:26:01.066Z</updated><summary type="html">Note: [⮋] - direct download, platform x64; [⚠] - manual download; ✅ - open source</summary><content type="html">
  &lt;blockquote id=&quot;07BS&quot;&gt;Note: [⮋] - direct download, platform x64; [⚠] - manual download; ✅ - open source&lt;/blockquote&gt;
  &lt;p id=&quot;HJKQ&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;Haaj&quot;&gt;UX&lt;/h2&gt;
  &lt;ul id=&quot;1Hhk&quot;&gt;
    &lt;li id=&quot;dgQW&quot;&gt;&lt;a href=&quot;https://download.mozilla.org/?product=firefox-devedition-stub&amp;os=win&quot; target=&quot;_blank&quot;&gt;[⮋]&lt;/a&gt; &lt;a href=&quot;https://www.mozilla.org/ru/firefox/developer/&quot; target=&quot;_blank&quot;&gt;Firefox Browser Developer Edition&lt;/a&gt; ✅&lt;/li&gt;
    &lt;li id=&quot;ECyf&quot;&gt;&lt;a href=&quot;https://www.google.com/chrome/&quot; target=&quot;_blank&quot;&gt;[⚠]&lt;/a&gt; &lt;a href=&quot;https://www.google.com/chrome/&quot; target=&quot;_blank&quot;&gt;Chrome&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;a5rb&quot;&gt;&lt;a href=&quot;https://www.torproject.org/download/&quot; target=&quot;_blank&quot;&gt;[⚠]&lt;/a&gt; &lt;a href=&quot;https://www.torproject.org/&quot; target=&quot;_blank&quot;&gt;Tor Browser&lt;/a&gt; ✅&lt;/li&gt;
  &lt;/ul&gt;
  &lt;hr /&gt;
  &lt;ul id=&quot;tIXn&quot;&gt;
    &lt;li id=&quot;4S7o&quot;&gt;&lt;a href=&quot;https://discordapp.com/api/download?platform=win&quot; target=&quot;_blank&quot;&gt;[⮋]&lt;/a&gt; &lt;a href=&quot;https://discordapp.com&quot; target=&quot;_blank&quot;&gt;Discord&lt;/a&gt; ✅&lt;/li&gt;
    &lt;li id=&quot;8kIs&quot;&gt;&lt;a href=&quot;https://telegram.org/dl/desktop/win&quot; target=&quot;_blank&quot;&gt;[⮋]&lt;/a&gt; &lt;a href=&quot;https://telegram.org&quot; target=&quot;_blank&quot;&gt;Telegram&lt;/a&gt; ✅&lt;/li&gt;
  &lt;/ul&gt;
  &lt;hr /&gt;
  &lt;ul id=&quot;qXep&quot;&gt;
    &lt;li id=&quot;BtOr&quot;&gt;&lt;a href=&quot;https://www.audacityteam.org/download/windows/&quot; target=&quot;_blank&quot;&gt;[⚠]&lt;/a&gt; &lt;a href=&quot;https://www.audacityteam.org/&quot; target=&quot;_blank&quot;&gt;Audacity&lt;/a&gt; ✅ - Audio editor \ recorder&lt;/li&gt;
    &lt;li id=&quot;V9JN&quot;&gt;&lt;a href=&quot;https://vault.bitwarden.com/download/?app=desktop&amp;platform=windows&quot; target=&quot;_blank&quot;&gt;[⮋]&lt;/a&gt; &lt;a href=&quot;https://bitwarden.com/&quot; target=&quot;_blank&quot;&gt;Bitwarden ✅ &lt;/a&gt;- Password Manager&lt;/li&gt;
    &lt;li id=&quot;CD1r&quot;&gt;&lt;a href=&quot;https://sourceforge.net/projects/qbittorrent/files/latest/download&quot; target=&quot;_blank&quot;&gt;[⮋]&lt;/a&gt; &lt;a href=&quot;https://www.qbittorrent.org&quot; target=&quot;_blank&quot;&gt;qBitTorrent&lt;/a&gt; ✅&lt;/li&gt;
    &lt;li id=&quot;YvFK&quot;&gt;&lt;a href=&quot;https://www.videolan.org/vlc/index.ru.html&quot; target=&quot;_blank&quot;&gt;[⚠]&lt;/a&gt; &lt;a href=&quot;https://www.videolan.org/vlc/&quot; target=&quot;_blank&quot;&gt;VLC&lt;/a&gt; ✅&lt;/li&gt;
    &lt;li id=&quot;ZK2v&quot;&gt;&lt;a href=&quot;https://www.spotify.com/download/windows/&quot; target=&quot;_blank&quot;&gt;[⮋]&lt;/a&gt; &lt;a href=&quot;https://www.spotify.com&quot; target=&quot;_blank&quot;&gt;Spotify&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;sAKX&quot;&gt;&lt;a href=&quot;https://steamcdn-a.akamaihd.net/client/installer/SteamSetup.exe&quot; target=&quot;_blank&quot;&gt;[⮋]&lt;/a&gt; &lt;a href=&quot;https://store.steampowered.com/&quot; target=&quot;_blank&quot;&gt;Steam&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;kjvs&quot;&gt;&lt;a href=&quot;https://www.screentogif.com/downloads&quot; target=&quot;_blank&quot;&gt;[⚠]&lt;/a&gt; &lt;a href=&quot;https://www.screentogif.com/&quot; target=&quot;_blank&quot;&gt;ScreenToGif&lt;/a&gt; ✅ - Tool to record\edit&lt;/li&gt;
    &lt;li id=&quot;QqaZ&quot;&gt;&lt;a href=&quot;https://www.voidtools.com/downloads/&quot; target=&quot;_blank&quot;&gt;[⚠]&lt;/a&gt; &lt;a href=&quot;https://www.voidtools.com/&quot; target=&quot;_blank&quot;&gt;Everything &lt;/a&gt;- Instantly search by name&lt;/li&gt;
    &lt;li id=&quot;UaDa&quot;&gt;&lt;a href=&quot;https://www.7-zip.org/download.html&quot; target=&quot;_blank&quot;&gt;[⚠]&lt;/a&gt; &lt;a href=&quot;https://www.7-zip.org/&quot; target=&quot;_blank&quot;&gt;7-Zip&lt;/a&gt; ✅&lt;/li&gt;
    &lt;li id=&quot;dR3Y&quot;&gt;&lt;a href=&quot;https://download.wireguard.com/windows-client/wireguard-installer.exe&quot; target=&quot;_blank&quot;&gt;[⮋]&lt;/a&gt; &lt;a href=&quot;https://www.wireguard.com&quot; target=&quot;_blank&quot;&gt;Wireguard&lt;/a&gt; ✅ - VPN&lt;/li&gt;
  &lt;/ul&gt;
  &lt;h2 id=&quot;m5UB&quot;&gt;Development&lt;/h2&gt;
  &lt;ul id=&quot;hLVI&quot;&gt;
    &lt;li id=&quot;dBwx&quot;&gt;&lt;a href=&quot;https://dl.pstmn.io/download/latest/win64&quot; target=&quot;_blank&quot;&gt;[⮋]&lt;/a&gt; &lt;a href=&quot;https://www.postman.com/&quot; target=&quot;_blank&quot;&gt;Postman &lt;/a&gt;- Quickly and easily send requests&lt;/li&gt;
    &lt;li id=&quot;Ig85&quot;&gt;&lt;a href=&quot;https://gpg4win.org/thanks-for-download.html&quot; target=&quot;_blank&quot;&gt;[⮋]&lt;/a&gt; &lt;a href=&quot;https://gpg4win.org/&quot; target=&quot;_blank&quot;&gt;GPG4win&lt;/a&gt; ✅ - GNU Privacy Guard&lt;/li&gt;
    &lt;li id=&quot;iFG3&quot;&gt;&lt;a href=&quot;https://git-scm.com/download/win&quot; target=&quot;_blank&quot;&gt;[⚠]&lt;/a&gt; &lt;a href=&quot;https://git-scm.com&quot; target=&quot;_blank&quot;&gt;Git&lt;/a&gt; ✅&lt;/li&gt;
    &lt;li id=&quot;wI8s&quot;&gt;&lt;a href=&quot;https://code.visualstudio.com/docs/?dv=win64user&quot; target=&quot;_blank&quot;&gt;[⮋]&lt;/a&gt; &lt;a href=&quot;https://code.visualstudio.com&quot; target=&quot;_blank&quot;&gt;Visual Studio Code&lt;/a&gt; ✅&lt;/li&gt;
  &lt;/ul&gt;
  &lt;hr /&gt;
  &lt;ul id=&quot;Lwnn&quot;&gt;
    &lt;li id=&quot;K1Za&quot;&gt;&lt;a href=&quot;https://www.jetbrains.com/toolbox-app/download/download-thanks.html?platform=windows&quot; target=&quot;_blank&quot;&gt;[⮋]&lt;/a&gt; &lt;a href=&quot;https://www.jetbrains.com/toolbox-app/&quot; target=&quot;_blank&quot;&gt;JetBrains Toolbox App&lt;/a&gt; - Manage IDEs&lt;/li&gt;
    &lt;li id=&quot;phoS&quot;&gt;&lt;a href=&quot;https://www.java.com/en/download/manual.jsp&quot; target=&quot;_blank&quot;&gt;[⚠]&lt;/a&gt; &lt;a href=&quot;https://www.java.com/en/download/faq/whatis_java.xml&quot; target=&quot;_blank&quot;&gt;JRE&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;SPeV&quot;&gt;&lt;a href=&quot;https://www.oracle.com/java/technologies/javase-downloads.html#javasejdk&quot; target=&quot;_blank&quot;&gt;[⚠]&lt;/a&gt; &lt;a href=&quot;https://www.java.com/en/download/faq/develop.xml&quot; target=&quot;_blank&quot;&gt;JDK&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;fv6I&quot;&gt;&lt;a href=&quot;https://github.com/Genymobile/scrcpy/releases/&quot; target=&quot;_blank&quot;&gt;[⚠]&lt;/a&gt; &lt;a href=&quot;https://github.com/Genymobile/scrcpy/&quot; target=&quot;_blank&quot;&gt;scrcpy&lt;/a&gt; ✅ - Display\control of Android devices&lt;/li&gt;
  &lt;/ul&gt;
  &lt;hr /&gt;
  &lt;ul id=&quot;xehm&quot;&gt;
    &lt;li id=&quot;7g4u&quot;&gt;&lt;a href=&quot;https://www.anaconda.com/products/individual#Downloads&quot; target=&quot;_blank&quot;&gt;[⚠]&lt;/a&gt; &lt;a href=&quot;https://www.anaconda.com/&quot; target=&quot;_blank&quot;&gt;Anaconda Project&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;ot0x&quot;&gt;&lt;a href=&quot;https://www.python.org/downloads/&quot; target=&quot;_blank&quot;&gt;[⚠]&lt;/a&gt; &lt;a href=&quot;https://www.python.org/&quot; target=&quot;_blank&quot;&gt;Python&lt;/a&gt; ✅&lt;/li&gt;
    &lt;li id=&quot;7eHD&quot;&gt;&lt;a href=&quot;https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html&quot; target=&quot;_blank&quot;&gt;[⚠]&lt;/a&gt; &lt;a href=&quot;https://www.putty.org/&quot; target=&quot;_blank&quot;&gt;PuTTY&lt;/a&gt; ✅&lt;/li&gt;
  &lt;/ul&gt;

</content></entry><entry><id>hikkidev:z5PPVTo6</id><link rel="alternate" type="text/html" href="https://teletype.in/@hikkidev/z5PPVTo6?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=hikkidev"></link><title>Android studio 4.x configuration</title><published>2020-07-05T13:41:08.585Z</published><updated>2022-10-17T04:29:30.617Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://teletype.in/files/1e/35/1e35b84b-5e41-477a-b25c-db8225dfe05f.png"></media:thumbnail><category term="android-studio" label="Android Studio"></category><summary type="html">&lt;img src=&quot;https://teletype.in/files/d4/77/d47729c9-b31d-44d6-bebc-6d8e122562e8.png&quot;&gt;1) Disable line numbers</summary><content type="html">
  &lt;h3 id=&quot;U4wC&quot;&gt;Settings&lt;/h3&gt;
  &lt;p id=&quot;Yv3G&quot;&gt;1) Disable line numbers&lt;/p&gt;
  &lt;figure id=&quot;wHSR&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/d4/77/d47729c9-b31d-44d6-bebc-6d8e122562e8.png&quot; width=&quot;674&quot; /&gt;
    &lt;figcaption&gt;Switch to OFF&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;zBNy&quot;&gt;2) Disable tabs&lt;/p&gt;
  &lt;figure id=&quot;IdMh&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/fb/e6/fbe698ff-c310-40ab-a6df-0f18a3fb9f7e.png&quot; width=&quot;674&quot; /&gt;
    &lt;figcaption&gt;Switch &lt;strong&gt;None &lt;/strong&gt;placement to ON&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;XAs6&quot;&gt;3) Enable auto-scroll&lt;/p&gt;
  &lt;figure id=&quot;imlr&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/08/9e/089ec71c-1df2-404e-a812-32433e0d8f56.png&quot; width=&quot;674&quot; /&gt;
    &lt;figcaption&gt;Switch to ON&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;LWh4&quot;&gt;4) Enable Semantic Highlighting&lt;/p&gt;
  &lt;figure id=&quot;1dC1&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/1d/11/1d118d9b-dd19-4b1a-98b5-78ecadb07d36.png&quot; width=&quot;984&quot; /&gt;
    &lt;figcaption&gt;Toggle checkbox&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;h3 id=&quot;FFpU&quot;&gt;Plugins&lt;/h3&gt;
  &lt;ul id=&quot;lwzH&quot;&gt;
    &lt;li id=&quot;cyKq&quot;&gt;&lt;a href=&quot;https://plugins.jetbrains.com/plugin/8580-cpu-usage-indicator&quot; target=&quot;_blank&quot;&gt;.&lt;/a&gt;&lt;a href=&quot;https://plugins.jetbrains.com/plugin/7495--ignore&quot; target=&quot;_blank&quot;&gt;ignore&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;CVRk&quot;&gt;&lt;a href=&quot;https://plugins.jetbrains.com/plugin/2162-string-manipulation&quot; target=&quot;_blank&quot;&gt;String manipulation&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;lwD5&quot;&gt;&lt;a href=&quot;https://plugins.jetbrains.com/plugin/10080-rainbow-brackets&quot; target=&quot;_blank&quot;&gt;Rainbow Brackets&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;5zjc&quot;&gt;&lt;a href=&quot;https://plugins.jetbrains.com/plugin/8579-translation&quot; target=&quot;_blank&quot;&gt;Translation&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
  &lt;h3 id=&quot;Td39&quot;&gt;Keymap&lt;/h3&gt;
  &lt;p id=&quot;gnc1&quot;&gt;Double Shift, Ctrl+Space, Alt+Enter - our all&lt;/p&gt;
  &lt;p id=&quot;GfvG&quot;&gt;Ctrl+E - Recent files (Ctrl+Tab - quick version)&lt;/p&gt;
  &lt;figure id=&quot;istF&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/17/7e/177e9fbf-baab-4098-a1e7-fdcba5210f1f.png&quot; width=&quot;500&quot; /&gt;
    &lt;figcaption&gt;Example usage&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;ehVo&quot;&gt;Ctrl+P - Show params | Ctrl + Shift + P - Show data type&lt;/p&gt;
  &lt;figure id=&quot;VsXi&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/a0/cb/a0cb4f00-8f72-4db7-b403-36338b857a66.png&quot; width=&quot;626&quot; /&gt;
    &lt;figcaption&gt;Example usage&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;qq9t&quot;&gt;Ctrl+Q - Quick documentation&lt;/p&gt;
  &lt;figure id=&quot;8YBF&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/56/9c/569cd70e-6878-4fd7-bda0-f323f4a27478.png&quot; width=&quot;338&quot; /&gt;
    &lt;figcaption&gt;Example usage&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;NlAs&quot;&gt;Ctrl+Shift+I - Quick definition&lt;/p&gt;
  &lt;figure id=&quot;LbYj&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/e2/78/e278c729-6e6d-4e7f-86f9-bc4fc4adc05e.png&quot; width=&quot;618&quot; /&gt;
    &lt;figcaption&gt;(Rebind keymap to Shift+Q)&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;LhQg&quot;&gt;Quick navigation&lt;/p&gt;
  &lt;figure id=&quot;IB4z&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/31/9f/319f0d90-7d08-4a24-8fa8-d25ee34a81c1.png&quot; width=&quot;746&quot; /&gt;
    &lt;figcaption&gt;Keymap &lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;V8kS&quot;&gt;Ctrl+F12 - Show structure&lt;/p&gt;
  &lt;figure id=&quot;DDLh&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/98/e2/98e23f7d-f516-48f5-a925-203460cc544f.png&quot; width=&quot;572&quot; /&gt;
    &lt;figcaption&gt;Example usage&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;zwcc&quot;&gt;Ctrl+Alt+F7 - Show usages&lt;/p&gt;
  &lt;figure id=&quot;yEwc&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/0f/e9/0fe9a248-e79e-4795-b57c-2110615c1680.png&quot; width=&quot;669&quot; /&gt;
    &lt;figcaption&gt;Example usage&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;K2cb&quot;&gt;Ctrl+Alt+Shift+T - Show refactor menu&lt;/p&gt;
  &lt;figure id=&quot;vzLQ&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/01/d4/01d415fd-baf9-4428-b048-545536256452.png&quot; width=&quot;311&quot; /&gt;
    &lt;figcaption&gt; (Rebind keymap to Ctrl+T)&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;CIjQ&quot;&gt;Alt+ins - Generate menu&lt;/p&gt;
  &lt;figure id=&quot;pcLg&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/5c/43/5c4399fc-f0fc-4e59-86a2-aec8c584c1e9.png&quot; width=&quot;201&quot; /&gt;
    &lt;figcaption&gt;Example usage&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;vAit&quot;&gt;Al+J -&amp;gt; J -&amp;gt; J -&amp;gt; etc...  - Sequential selection with cursor positioning&lt;/p&gt;
  &lt;figure id=&quot;k8br&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/cf/20/cf20c4c7-803c-4565-8afe-c88aab1d5fc2.png&quot; width=&quot;805&quot; /&gt;
    &lt;figcaption&gt;Example usage&lt;/figcaption&gt;
  &lt;/figure&gt;

</content></entry></feed>