Начало программирования вообще с нуля. Часть 1

В этой статье пойдет речь с чего начать вообще программировать, не важно на каком языке, базовые основы.

К моменту прочтения этой статьи, вам желательно иметь навыки продвинутого пользователя. Это действительно необходимо, в ином случае вы несколько спешите заниматься программированием и даже погружаться в этот мир, так как сложно объяснить что такое спидометр, если человек не знаете в чём измеряется расстояние и как выглядят часы. Однако, если вы способны самостоятельно найти и прочитать в Дзене эту статью, то будьте уверены – вы на правильном пути, и понемногу уже можно начинать)).

Компьютеры сейчас практически в любых электронных устройствах – стиральные машины, холодильники, утюги, термометры, не говоря уже о мобильниках, моноблоках и т.п. В среде информационных технологий это принято называть ёмким словом «железо», а у программистов принято называть «устройство». С точки зрения программирования, компьютер – это обычный калькулятор с расширенным набором функций. Единственное, что отличает его от калькулятора, это то, что в компьютере вы одной командой можете запустить выполнение сразу миллиарда различных действий, а в калькуляторе только одно (умножить, разделить и т.д.). Такое получается по тому, что в любом компьютере действия выполняются по программе, т.е. заранее подготовленной последовательности команд. Вы их подготовили, убедились, что всё верно, и запустили выполнение. И вот этот набор команд начал выполняться до тех пор, пока не завершится выполнение всех команд, пока их выполнение кто-то не остановит специальной командой, либо пока в коде что-то не сломается, т.е. была ошибка, её не заметили, но проявилась она не сразу, а по мере выполнения. Такое поведение в компьютерах принято соответственно называть терминами «запустить программу», «прервать выполнение программы», «ошибка выполнения программы». Часто эти термины встречаются в англоязычном представлении:

run, exec, execute – запустить выполнение
break, abort, cancel, terminate, stop, exit, kill, die – прервать выполнение
run-time error – ошибка выполнения

Вообще, если строго говорить, то англоязычного очень много в программировании, если конечно вы не хотите изучать только язык 1С и ничего больше, но как правило, это маловероятно. Однако, английский язык вам специально изучать не нужно, просто в этом нет необходимости. Во время изучения какого-либо языка программирования, вам так или иначе нужно будет запоминать команды, что они делают, а их названия достаточно отождествлены с их смыслом. Например, команда input (пер.: ввод, подвод, подводимый) в языках программирования – это ввод данных, по смыслу подходит. Но если вы обладатель хороших знаний английского языка и встречаете команду print (пер.: печатать, напечатать, печатный), то чисто английский вам мало поможет, а может даже и навредит, т.к. на самом деле никуда на бумагу печатать ничего не будет, а это просто вывод на экран строки символов. Эта команда – история программирования, идёт с тех времен, когда на клавиатуре не писали, а печатали, а на экране синхронно выводился текст; говорили не «писать текст программы», а «печатать текст программы». Также лепту внес и древний язык бейсик, где команда, если не ошибаюсь PRINT#1, как раз выводила текст на тогда ещё матричный принтер. В общем, в современном мире программирования это вывод на экран строки текста, причём на большом количестве языков программирования. Ну привыкли все к этой команде, зачем менять. По этому нужен ли английский знать, ну так, нужен, но не в этом. Пригодиться язык может только для того, чтобы читать англоязычные форумы, где публикуют большое количество решений различных проблем, как то сделать, как это, а почему у меня не работает код, который написал, а что нужно написать, чтобы это заработало. Я часто бываю на этих форумах, но пользуюсь либо Гуглом для перевода, либо Яндексом))…Но уже сейчас замечаю, что что-то стал понимать и без переводчика, причём иногда даже если пишут фразу «Wt u know about…» (What you know about… – что вы думаете о…) или «I lkn 4…» (I looking for… – я ищу…). Опять таки, по многим языкам программирования есть огромное количество и русскоязычных форумов.

Что внутри компа?

Внутри любого компьютера (компа), есть следующие основные вещи:

1. Процессор, которым часто называют ящик на столе, который на самом деле системный блок. По факту процессор – это большая микросхема внутри системного блока, в которой и происходят все вычисления и координация действий всего компьютера.
2. Оперативная память, которая работает очень быстро, но способна хранить в себе данные только пока компьютер включен (синонимы – ОЗУ. RAM, DDR).
3. Постоянная память, которая работает намного медленнее оперативной памяти, но способна хранить информацию даже если всё выключено (жесткие диски – HDD, твердотельные диски – SSD, флешки)
4. Периферия – устройства соединяющие все внешние устройства (клавиатуры, мыши, принтеры, наушники, мониторы, очки виртуальной реальности, сетевые карты и т.п.) с процессором и оперативной памятью. Функционал периферии выполнен как правило на материнских платах (возможно этот термин вам уже встречался) и устройствах размещенные непосредственно на них. Однако есть и периферия, которая выполнена вне материнских плат, например, внешние жесткие диски, внешние аудио-карты для написания музыки, внешние устройства для захвата видео изображения и т.п.
С точки зрения программирования, всё что пишет программист – это написание функционала взаимодействия между этими устройствами. И вот тут есть важный момент, о котором чуть подробнее.
Работа компьютера с точки зрения программирования сводится к следующему принципу на протяжении многих десятков лет:

1. Ваша программа загружается из постоянной памяти в оперативную при помощи другой (системной) программы.
2. В оперативной памяти системная программа (которая загружала вашу) по ряду признаков определяет, где в вашей программе просто обычные данные, например обычные слова типа «Введите логин и пароль», которые вы часто видите на экране, и где в вашей программе код из набора команд, которые будут переданы процессору на выполнение.
3. Запускает выполнение кода программы.
4. Завершает выполнение кода программы
5. Стирает из оперативной памяти программу, освобождая драгоценное место (из постоянной не стирается)

Как из предыдущего можно понять, что пока программа находится в постоянной памяти на накопителе, это просто обычные данные, но как только они загружаются в оперативную память, часть из них становиться кодом выполнения, а часть продолжают оставаться в виде обычных данных. Чтобы такое происходило безотказно и компьютер всегда знал что у вас код, который нужно выполнять, а что есть просто данные типа фразы «Введите логин и пароль», нужно предварительно правильно подготовить вашу программу для запуска. Этот процесс называет компиляцией программы. Т.е. вы написали программу на языке программирования, но в таком виде процессор компьютера её не поймет. Теперь нужно её скомпилировать чтобы компилятор (программа, которая компилирует вашу программу) преобразовал её в тот вид, в котором процессор вашего компьютера её поймет и однозначно сможет определить где в ней находится код выполнения, а где простые данные. Как можно понять из вышеперечисленного, что в современном компьютере выполняется не одна какая-то программа, а одна программа передаёт выполнение другой, которая была загружена вами ранее или была загружена автоматически, и все внутри взаимодействует как большой электронный организм. Выполнение каждых программ регламентировано и происходит по разным правилам и с разными условиям. Например, вы по экрану водите мышкой и кликаете в браузере загрузить страницу, в этот момент происходит лавинный запуск сотен программ, одни грузят страницу из сети интернет, другие программы отображают её на экране, третьи проверяют не продолжаете ли вы двигать мышью по экрану, ещё одна продолжает отображать часы в углу экрана и ещё миллионы других действий. Всё это происходит в строгой последовательности со скоростью в десятки миллиардов раз за одну секунду, по этому кажется с виду, что всё запускается одновременно.
По этому знание и понимание этого очень важно для программирования. Сначала, когда вы включаете компьютер, запускается операционная система (Windows, Linux и т.п.), с точки зрения компьютера это тоже программа, которую писали программисты операционной системы. Потом, вы как программист, хотите написать свою первую программу. Для этого вам нужно загрузить среду разработки, это тоже некая программа, написанная другими программистами. Вы её загрузили, в ней написали свою программу, после этого запускаете в среде разработки компиляцию уже вашей программы. Теперь у вас есть готовый для запуска код, который вы уже можете запустить без среды разработки или передать друзьям знакомым, опубликовать в интернете и все, кто работает на такой же операционной системе как у вас, сможет выполнить написанную вами программу. Так и происходит весь этот процесс в общих чертах от программирования до конечного пользователя.
Как я уже ранее написал, в компьютере происходит взаимодействие различных программ. Их можно разделить на несколько типов с точки зрения уровня использования.
1. Операционная система. Это программа, которая является средством согласования различных пользовательских программ с конкретным вашим устройством. Например, вы наверно замечали, что в мире множество производителей мобильных устройств, ещё больше производителей микрочипов. Общего международного стандарта никакого нет, каждый производитель чипов как считает его функционал оптимальным, выгодным и конкуретноспособным, так и выпускает его. Получается так, что он определил какие команды будет этот процессор обрабатывать, а какие нет. При этом доминирующие операционные системы для мобильных устройств только две iOS и Android. Например, для Андроид зарегистрировано более 10 тысяч моделей различных телефонов на разных процессорах. И вот вы скачиваете на Samsung например приложение от Сбера, а ваш знакомый на Xiaomi скачивает это же приложение. И там и там оно работает. Как может быть такое чудо, ведь процессоры разные, команды делали их производители под то, как им удобно, а приложение выполняется и там и там. Это всё заслуга программистов операционных систем. Они написали специальные программы-драйверы для каждого процессора и каждого из 10 тысяч устройств. Эти драйверы являются частью операционных систем и являются промежуточным звеном к той же программе от Сбера, которые говорят, например «Слушай, Сбер, скажи пользователю, что я не могу оплатить покупку телефоном, т.к. в нем нет устройства NFC». А другой драйвер говорит, «Слушай, приложение камеры, предложи пользователю вариант включить свет на вспышке, т.к. уже темно в помещении». И это всё для каждого типа устройств писали программисты. Теперь понимаете, держа в руках телефон, какая титаническая работа десятков тысяч программистов была проделана, что бы каждый из нас мог пользоваться тем устройством, какое подходит под наш типаж, мировоззрение и комфорт? С точки зрения персональных компьютеров, всё примерно также как и в мобильных устройствах.
2. Драйвер устройства. Как уже упомянул, это программа часть операционной системы, но выделяет её в отдельную категорию лишь то, что поставляться драйвер устройства может отдельно от операционной системы. Такое раньше можно было часто встретить, например, при покупке новой мыши прилагался компакт диск с драйверами. В современных операционных системах большинство драйверов устройств уже есть изначально, но иногда их всё же нужно устанавливать. Правда, сейчас они чаще идут не на компакт-дисках, а находятся на официальных сайтах производителей оборудования. Например, купили видео карту, но операционная система поняла, что это видео карта и монитор показывает изображение, но производитель уже успел внести в её схему дополнения повышающее её производительность и возможности, но операционная система может об этом ещё не знать. По этому нужно этот драйвер скачать с официального сайта, установить и он станет частью операционной системы и откроет все возможности вашей видео карты.
3. Пользовательские программы. Это те программы, которые мы используем в повседневной жизни – текстовый редактор, калькулятор, бухгалтерские программы, компьютерные игры и т.п.

Первые два пункта – это стезя системных программистов. Здесь нужны глубокие знания в узкоспециализированной информации. Часто это информация скрыта и доступна только производителям оборудования или операционных систем. По этому стать программистом-системщиком (так их иногда называют) сидя за домашним компом попивая чаёк, крайне сложно, и всё потому, что документации найти сложно, а спрос на такие программы примерно равен нулю – никто не будет пользоваться вашими написанными драйверами, если есть драйвера производителя. Причины две – производитель лучше знает как должно правильно работать его устройство, информационная безопасность сильно страдает, так как часто драйвера обладают уровнем привилегий и прав больше обычных, и в случае неправильной работы могут навредить либо информации, находящейся на компьютере, либо самому компьютеру. Эта работа только для тех, кто работает непосредственно в организации по производству оборудования, либо у производителя операционных систем. Вопрос философский, куда пойдет программист-системщик, если уволится, ведь у него большие знания только в области одного типа/производителя оборудования? Сколько будет искать новую работу? Как на новом месте сможет адаптировать свои знания к новой структуре, может мгновенно, а может придётся с нуля приобретать новый опыт. Но, чаще всего, зарплаты там очень крутые, и увольняться обычно никого не тянет, кто-то наверно всю жизнь и работает на одной работе.


Что внутри программы?

Как я уже говорил ранее, программа – это набор команд. Программа выполняется сверху (сначала) вниз (в конец).
Все команды программы (любого языка программирования) делятся на несколько типов.

1. Присвоение значения переменной. Нужно чтобы потом удобно было работать с формулами – вы меняете значение только вначале, а дальше в формуле оно будет вычислено автоматически. Иначе нужно будет менять число далее во всех формулах, где встречается, и можно тут где-то случайно пропустить или ошибиться. Грубо говоря – это аналог математической переменной (кто в школе учил математику в 5 классе). Присвоение значения переменной принято называть инициализацией переменной. В некоторых языка программирования это обязательное условие компиляции, т.е. компилятор не позволяет как-то использовать переменную, пока вы дадите ей какое-то начальное значение.

a = 1

Как правило имя переменной может быть различным:

result = 0

Есть некоторые негласные правила имен переменных. Они выработаны в долгих поисках и чтении чужого когда, да и своего тоже, и придуманы не мной, а огромной командой программистов всех времен.
Во многих языках программирования переменные можно писать только латинскими буквами с цифрами и знаками _ (подчеркивание). Другие символы запрещены. Если это правило есть и в том языке, который вы будете изучать, то тогда сами переменные называйте английскими словами.

MoiResultat = 0; // НЕПРАВИЛЬНО – тут человек может взгляд сломать. Возми гугл, переведи и дай название переменной на английском, что ли…

MyResult = 0; // ПРАВИЛЬНО – название переменной латинскими буквами на английском языке

МойРезультат = 0; // ПРАВИЛЬНО – если язык программирования позволяет вводить кириллицей (например язык 1С), то так будет правильно

МайРизалт = 0; // НЕПРАВИЛЬНО – ты что бюргер что ли?

Иногда в название переменной закладывают сразу несколько слов, чтобы наделить её сразу смыслом. Если название переменной состоит из нескольких слов, то начинайте каждое слово с большой буквы.

myresultwhenigotinthemyfunctionfactorial = 1; // НЕПРАВИЛЬНО – Нормальный человек в здравом уме такое не прочитает…и не напишет…и представьте, что весь код такой и его сотни страниц…

MyResultWhenIGotInTheMyFunctionFactorial = 1; // ПРАВИЛЬНО – ну согласитесь, такое читать куда легче

myResultWhenIGotInTheMyFunctionFactorial = 1; // ПРАВИЛЬНО – первую букву иногда заглавной не делают, т.к. например в языке C и Java принято с заглавной буквы называть объекты, а с маленькой – их переменные.

ТаблицаВыгрузкиСальдоБухгалтерскихСчетовБезАналитикиСводноПоМесяцамКромеЗабалансовых = Неопределено; // ПРАВИЛЬНО – это 1С, товарищ, не хиханьки и не хаханьки! (это всё название переменной, без этого в 1С была бы засада)

В некоторых языках программировании при первой инициализации переменной необходимо обязательно указать тип данных, которые она будет хранить:

int a = 1; // Переменная a будет хранить только целые числа. Попытка запихнуть туда что-то другое, вызовет сначала недоумение компилятора и он попробует преобразовать это в целое число, например, 1.1922324 будет всё равно 1, либо просто начнет ругаться
string b = “Hello, world!”; // Норм! Так пойдёт! строку хранит переменная с типом строки
int a = “Hello, world!”; // СОВСЕМ НЕ НОРМ! – что за бодяга? как эта строка может быть целым числом??? С точки зрения компилятора – никак.


Разных типов может быть бесчисленное множество, так как программист может создавать свои собственные, но есть всё таки базовый набор простых типов, такие как:
Булево (bool) – тип переменной, которая может принять только одно из двух значений – истина или ложь
Целое число (byte, int, long, word, dword) – переменная может хранить только целые числа. Типов целого числа много, тут всё зависит от того до какого предельного значения вы хотите хранить целое число и нужен ли будет математический знак минуса (иногда необходимо хранить только положительные числа), это и определяет вариант.
Вещественное число (float, double) – числа, где нужно хранить дробную часть. Иногда их называют числа с плавающей точкой или плавающей запятой (оттуда и название float). Также их несколько и определяют точность дробной части.
Символ (char) – хранит символ
Строка (string) – хранит множество символов. В мире программирования постоянно происходят метания что при случае выбрать массив char или переменную string (см.далее массивы). Эти метания в основном связаны со спецификой работы каждого типа и функциональными особенностями языка, но по здравому смыслу это одно и тоже.

Переменная может быть массивом (о чем только что писал):

int p[100];

Это значит, что будет создано 100 переменных p, но доступ каждой из них будет по индексу, т.е. p[0], p[1] и т.д. Это удобно, когда нужно выполнить действия сразу над множеством значений одной смысловой группы, например, вы производили 10 замеров температуры на кухне до и после приготовления жаркого, и у вас есть 10 значений. Но вам нужно среднее, чтобы понять превышало ли это среднюю норму домашнего труда или нет. Можно конечно задать так:
a = 23;
b = 25;
c = 27;
d = 28;
….
j = 24;

и потом посчитать по формуле:
Tc = (a + b + c +…+ j) / 10;

а можно сделать так:

int temp[10];

temp [0] = 23;
temp [1] = 25;
temp [2] = 27;
temp [3] = 28;

temp [9] = 24;

Tc = 0; // Так надо, мы не начали ещё считать температуру, значение полинома равно нулю
for (i = 0; i < 10; i++) { // Перебирает от 0 до 9 значения i, а потом использует их как индексы массива для расчета среднего
Tc += temp [i] ;
}
Tc /= 10; // Взять из Tc значение и поделить на 10, а потом запихнуть обратно в Tc

Когда речь идет о сотнях или миллионах чисел, то массив – это единственное решение. Лично я, если чего-то такого больше двух, то как правило делаю массив. Процесс выбора правильного алгоритма, в каком случае взять массив, а в каком создать пару отдельных переменных, как назвать их чтобы потом было понятно, называется творчеством, по этому кто говорит, что программирование – это конвейерная рутинная работа – неправ!

2. Выражение. Иными словами, это формула с числами, переменными или иными величинами.

b = a+2

или

с = sin(alfa)

3. Условие. Когда при соблюдении какого-то условия нужно выполнить один код, а в ином случае его не выполнять. Например, для синтаксиса языка типа Си, это выглядит так

If (b == 2) {
// Что-то выполнить здесь, если вдруг окажется, что благодаря каким-то действиям компьютера это значение станет равным 2, то выполнить нужно код заключенный в эти фигурные скобки, в ином случае просто проигнорировать этот код и перейти дальше
}

Для языка 1С тоже самое:

Если Б = 2 Тогда
// Что-то тут
КонецЕсли;

Для Бейсика:

if b = 2 then
// ???
end

4. Циклы. Чтобы не быть как в анекдоте про нового русского, когда он летит в самолете, а стюардесса объявляет «Наш самолет летит в Баден-Баден», новый русский её останавливает и говорит «Слыш, тут чё лохи летят, зачем Баден два раза повторять?». Так вот чтобы не быть лохом, в программировании придумали циклы, т.е. конструкцию, которая позволяет выполнять одинаковую часть кода несколько раз.

Если делать неправильно, новый русский лохом бы назвал:

print(‘Мы летим в’);
print(‘Баден’);
print(‘Баден’);

А так правильно, новый русский бы оценил:

print(‘Мы летим в’);
for( i = 1; i < 3; i = i+1) { // Перебирать от 1 пока i будет меньше 3, т.е. только значения 1 и 2
print(‘Баден’);
}

Но как бы не делали, в результате на экране будет всё равно одно и то же:
Мы летим в
Баден
Баден

Всё как в анекдоте)))…ну, или не летим…))

5. Создание функций. Иногда они называются методами, иногда процедурами возвращающими значение, иногда подпрограммами, всё зависит от конкретного языка программирования. Это конструкции, которые позволяют делать что-то, что после некоторых манипуляций и алгоритмов будет возвращать результат какого-то выражения.

a = sin(alfa); // это стандартная функция вычисления синуса

function mySin(alfa) {
// Тут, если владеете математикой, раскладываете расчет синуса в ряд Тейлора-Маклорена, и пишите код, который будет вычислять его по вашему алгоритму. Например, если вам нужна бОльшая точность, чем вычисляет это стандартная функция
}

a = mySin(alfa); // А теперь можно наслаждаться результатом

6. Класс. Современные языки позволяют делать иерархию методов (см.п.5), когда несколько методов и/или переменных объединяются по смыслу в один объект – класс. Например, вы делаете приложение чем кормить ваших питомцев. Вам нужно по каждому из них хранить информацию, мол как зовут, что хавает, когда кормил последний раз, где нас***, да вообще как он чувствует себя после этого. Мы делаем класс и называем его ёмким словом «Питомец» (Pet)

class Pet {
string name = “???”
string type = “???”
string eat = “???”

function ThrowASlipperAtItBecauseItMadeAMess() {
// Тут какой-то код
}

function GiveCookies () {
// Тут какой-то код
}
}

Пока мы объявили только этот класс как иерархию, но чтобы каждого нашего питомца отразить нужно будет создать на каждого из них экземпляр этого питомца.

Pet pet1 = new Pet();

pet1.name = ‘Петроний’;
pet1.type = ‘Кот’;
pet1.eat = ‘Захавал мою сметану – не поплохело’;

pet1. ThrowASlipperAtItBecauseItMadeAMess(); // Выполнить код, запускающий в него тапок

Pet pet2 = new Pet();

pet2.name = ‘Барбос;
pet2.type = ‘Пёс’;
pet2.eat = ‘Принёс назад тапок для запуска его в кота, дал печеньку’;

pet2. GiveCookies (); // Этот код даёт питомцу печеньку


В класса есть такая штука как расширение одного класс другим. Например, для кота Петрония и пса Барбоса есть общие переменные, такие как имя, тип и еда, но вот давать печеньки коту глупо, а пулять тапком в собаку не безопасно. Т.е. для пса выполнить метод ThrowASlipperAtItBecauseItMadeAMess() (переводится как «запустить тапком, так как съел сметану») можно только в шаговой недоступности. По этому эти методы по идее должны быть уникальными для каждого типа. Это можно делать так:

class Pet() {
string name = “???”
string type = “???”
string eat = “???”
}

class PetCat() extends Pet {
function ThrowASlipperAtItBecauseItMadeAMess() {
// Тут какой-то код
}
}

class PetDog() extends Pet {
function GiveCookies () {
// Тут какой-то код
}
}

Объявление их тоже будет немного по другому:

PetCat pet1 = new PetCat();

pet1.name = ‘Петроний’;
pet1.type = ‘Кот’;
pet1.eat = ‘Захавал мою сметану – не поплохело’;

pet1. ThrowASlipperAtItBecauseItMadeAMess();


PetDog pet2 = new PetDog();

pet2.name = ‘Барбос;
pet2.type = ‘Пёс’;
pet2.eat = ‘Принёс назад тапок для запуска его в кота, дать печеньку’;

pet2. GiveCookies (); // Этот код даёт питомцу печеньку

Но никто не мешает делать, конечно, и так:

Pet pet1 = new PetCat(); // Всё внимание на тип вначале! Найдите отличия.
Pet pet2 = new PetDog(); // pet2 тоже с тем же типом, хотя создаётся экземпляр другого объекта (уже расширенного)

Но тогда перед тем как вызвать функцию, нужно сначала убедиться в типе этого объекта, т.к тип Pet ничего не знает и не ведает о том, что его где-то кто-то стал расширять.

Теперь уже не получится запульнуть в пса тапком и дать коту печеньку, т.е. например, так не выйдет – pet1. GiveCookies (); – этот метод теперь только для объекта PetDog(), компилятор скажет, что у этого объекта нет такого метода.

Как вы заметили, переменные объявляются только один раз в родительском классе (классе, функционал которого мы расширяем).

Этот способ позволяет делать библиотеки кода, когда вы компилируете свой класс, хотите поделиться им с кем-то, но не хотите чтобы кто-то узнал по какой формуле будет лететь тапок, и из какой химической гадости будут сделаны даваемые псу печеньки. Так вот, вы компилируете класс, создаете библиотеку, но позволяете другим программистам расширять ваш класс своими функциями, например общую для них – погладить по голове, или индивидуальные – почесать за ухом, дать ещё сметаны))). И если они сочтут, что ваш тапок летит в кота недостаточно быстро, то могут написать даже свой аналог функции ThrowASlipperAtItBecauseItMadeAMess(). Их компилятор увидит, что такая функция есть в вашей библиотеке, программист её расширяет, но у него тоже есть такая же функция, тут его компилятор и принимает решение, что код этого программиста всё-таки важнее вашего и даст ему расширить класс своим методом на замену.

7. Комментарии. Это те части кода, которые просто нужны чтобы программист сделал какие-то заметки для себя или других программистов, которые могут работать с этим кодом. Компилятор будет их полностью игнорировать.


Философия “Hello World!”

Когда-то в далёком эээ…уже не помню каком году, мы с одноклассниками сидели на табуретках с электрогитарами в руках и спорили нужно ли для хорошей игры учить пассажи известных музыкантов, таких как Джо Сатриани или Ван Халена. Мне говорили обязательно нужно, иначе не будешь знать основ и не сможешь нормально играть, а я говорил, что если я буду учить других, то мне сложно будет придумать своё, а в музыке это означает потерять индивидуальность. И как показала жизнь, у каждого была тогда своя правда. В программировании так же. Здесь нужно всего в меру, меньше неё будет недостаточно для написания рационального и лаконичного кода, а если будет слишком много – разрушит элементы творчества, ты просто превращаешься в великого комбинатора – взял там кусок кода, взял тут готовый метод…хотя, это тоже в некотором роде творчество. Приведу пример. Некогда я писал много и для души на ассемблере. Часто приходилось обнулять 32-битный регистр, т.е. записывать в него значение ноль. Я делал это таким способом, кстати, строго по умной книжке:

MOV EAX, 0

Эта команда занимала, если не соврать, 5 байт в режиме 32 битного режима процессора по умолчанию. Но потом дизассемблируя чей-то код из игрухи типа «Принц оф Персия», я увидел интересную конструкцию:

XOR EAX, EAX

которая занимала уже только 1 байт. Результат тот же, но логическое действие совершенно не очевидное, эта команда не помещает ноль в регистр, она берёт то, что там уже есть и исключает само себя. Согласитесь, это красиво как любимая женщина (с мужской стороны, как для милых дам написать, я не знаю, что для вас сравнимо по красоте)) ). Тут то я и понял, насколько важно всё-таки иногда заглядывать на то, как делают другие, и о чём в книгах могут не написать.
При изучении нового языка программирования, уже так повелось, люди первым делом пишут вывод фразы «Hello, world!», ну или «Привет, мир!» (кому как удобнее). И вот какой в этом смысл:
1. Вы понимаете, что у вас работает среда разработки
2. Вы понимаете, что у вас правильно настроен и работает компилятор
3. Вы понимаете какой именно код заставил миллиарды транзисторов вашего устройства выстроить такую последовательность сигналов, что это привело к написании на вашем устройстве этой фразы, и на этом этапе всё, что вы делали правильно, и это работает…кстати, иногда пишут и такую фразу «It’s work!» (это работает).
Моя рекомендация – начинайте всегда изучать языки программирования с этой фразы. Она даёт дозу того самого волшебного пинка – психологически, если сразу что-то начинает работать, хотя ты только начал изучать, сильно бодрит, внушает чувство власти тебя над вычислительной системой, она выполняет команды, которые ты вводишь как верный пёс)), как любовь с первого взгляда.

Соблюдайте следующие принципы программирования

1. Пишите правильные комментарии
Это значит, что вы их должны писать тогда и только тогда, когда это действительно нужно или требуется, и не пишите их для всего подряд.


Не делайте избыточные комментарии:

a = 0; // Поместить в a ноль чтобы проверить как на него делить – ПРАВИЛЬНО

b = 1 / a; // Поделить 1 на a, которое содержит ноль – НЕПРАВИЛЬНО (избыточно), и так ясно, что здесь 1 делиться на a, которое содержит ноль, что тоже указано в предыдущем комментарии


Не делайте код совсем без комментариев. Часто бывает, что текущий проект нужно отложить на время. Потом, когда вы сможете к нему возвратиться, вам точно будет сложно понимать некоторые вещи, особенно если проект большой. Если вы ведете командную разработку, то это может быть иногда даже обязательным условием – уважайте время других программистов, напишите почему вы делаете этот алгоритм именно таким, хотя бы вначале, вкратце.


Пишите комментарии в строгом стиле, не используйте личные окончания глаголов:

a = 0; // Поместим в a ноль и проверим как на него делить – НЕПРАВИЛЬНО – вы может и помещаете, а лично Мы – нет.

a = 0; // Помещаю в a ноль чтобы проверить как на него делить – НЕПРАВИЛЬНО – ну и хорошо, помещай дальше что хочешь, я тут при чём? Мне что за тобой следить нужно? И давай уже решайся быстрее что туда помещать!

a = 0; // Помещаем в a ноль чтобы проверить как на него делить –
НЕПРАВИЛЬНО – я уже ответил про вас, мы не помещаем ничего никуда, тем более в перманентном процессе, да, это будет, но только один раз…и без вас

a = 0; // Помести в a ноль и проверь как на него делить –
НЕПРАВИЛЬНО – как ты груб с компом, фу!

a = 0; // Поместить в a ноль чтобы проверить как на него делить – ПРАВИЛЬНО – да, нужно поместить, а уж пометит ли он на самом деле и определяет что ты за программист и на каком железе работаешь)).

Кстати, в математике нельзя поделить число на ноль, но в компьютерных процессорах – можно. Результат будет «не число». Но большинство программ отрабатывают этот результат деления как ошибку «Деление на ноль», ну чтобы не вводить в заблуждение рядового пользователя)).


2. На каком бы языке вы не программировали, делайте код таким, чтобы он был наиболее удобно читаемым.

ЕслИ а = 1 ТОгДА ЧтоТоОБъЯвляюЗдесьПотомВыход = Истина; КонЕцЕсли; // НЕПРАВИЛЬНО – буквы скачут, всё условие в одну строку. Это всё равно что программиста, который будет этот код читать, обматерить в грубой форме

// ПРАВИЛЬНО – удобно читать код, код аккуратен.
Если а = 1 Тогда
ЧтоТоОбъявляюЗдесьПотомВыход = Истина;
КонецЕсли;

Например, я когда пишу, могу для удобства даже разделять смысловые методы пустой строкой, так читать удобнее и искать нужное гораздо быстрее, когда часами проводишь за компом…или перед компом…

Так пишу я:

В этой статье пойдет речь с чего начать вообще программировать, не важно на каком языке, базовые основы.

К моменту прочтения этой статьи, вам желательно иметь навыки продвинутого пользователя.

Хотя никто не запрещает писать так:

В этой статье пойдет речь с чего начать вообще программировать, не важно на каком языке, базовые основы.

К моменту прочтения этой статьи, вам желательно иметь навыки продвинутого пользователя.-2

Но согласитесь, в первом варианте читать намного легче и при этом код не загромождается. Очень быстро визуально искать нужное.

3. Сам язык программирования (любой) выучить не сложно, имеется ввиду его синтаксис, потому что выучить все методы современного языка физически невозможно, их десятки тысяч, да и кому это нужно. Например, зачем вам глубоко погружаться в специфику программирования для работы с устройствами Bluetooth, если вы никогда не будете их программировать в обозримом будущем, а только по этим классам сотни методов. С другой стороны, знание только языка вряд ли сможет закрыть вопросы решения современных задач. Так или иначе нужно изучать смежные технологии. Например, если вы решили сделать программу, которая передаёт файл по сети в другую такую же программу, то вам как минимум нужно будет понимать как работает сеть, чтобы знать логику и порядок выполнения тех или иных команд, их значения. Например, невозможно это сделать в ряде случаев, если вы не знаете что такое IP адрес, доменное имя или что такое сокет, не знаете, что сокет нужно открывать, а после использования закрывать. Даже не знание простых вещей иногда приводит к неверной работе программы. Например, вы в своей программе выделяете место в оперативной памяти, и как это сделать вам даст изучение языка, но нужно ли потом принудительно освобождать память и в каких случаях это нужно делать принудительно, а в каких система сама разберется с этим лучше, чем кто либо, знание только языка программирования вам не даст. Там например будет просто описание функции free() – освобождает память, а зачем она это делает, а зачем вообще это нужно, ни одно описание языка программирования вам это не скажет. Многие описания предполагают принцип «Вы конкретно знаете что хотите сделать, но определенно не знаете как это сделать».

Итог

Теперь остается только хорошенько всё обдумать, выбрать нужный язык программирования и приступить к созданию своей первой программы.

Начало программирования вообще с нуля. Часть 2

Для любого программиста знание что такое биты и байты, что такое системы счисления, является обязательным даже в современном мире. И значимость этого не меньше, чем много лет назад.

Элементарной единицей информации является бит, который может принимать одно из двух состояний – истина и ложь. В электронных схемах истина выражается в виде напряжения 5 вольт, либо 3.3 вольта, либо ещё как-то больше нуля (всё зависит от параметров электронной схемы), а значение ложь в виде отсутствии напряжения. В цифровом виде истина представляется значением 1 (единица), а ложь значением 0 (ноль).

Биты принято объединять в группы. Элементарной группой является байт, который равен восьми битам. Почему именно 8 бит, а не 10 и не 100, станет понятно позже, а если не станет, то я расскажу.

Как мы обычно привыкли записывать число? Ну как? – Вот так:

123 – сто двадцать три

Но на самом деле, с точки зрения математики, это выглядит вот так:

123 = 1 * 100 + 2 * 10 + 3 * 1

где * (звездочка) – так обозначается знак умножения.

Т.е. цифры в своих разрядах, дают нам конечное число именно по такой формуле. Однако и это не полностью адекватная запись, по тому что ещё более правильно было записать так:

123 = 1 * 10 ^ 2 + 2 * 10 ^ 1 + 3 * 10 ^ 0

где ^ (галка) – степень числа

Вспоминаем математику, что любое число в степени ноль – это единица, и 10 ^ 0 – не исключение

Тут видим, что именно степень числа и определяет полностью разряд числа (за плюсом 1). Т.е. в школе учили нас, что справа стоит первый разряд числа, но в программировании это нулевой разряд. Заметьте, каждый разряд содержит основание 10, меняется только множитель и его степень, но степень зависит только от разряда. По этому наше число для наглядности выглядит так:

123 = ( 1 ) * 10 ^ 2 + ( 2 ) * 10 ^ 1 + ( 3 ) * 10 ^ 0

– наши цифры 1, 2 и 3 от числа 123 показаны в скобках, 10 – постоянный в каждом разряде, а степени 2, 1 и 0 – это просто номера разрядов числа (справа налево). Вот и всё – это наше число так выглядит. Теперь важный момент. За счет того, что везде основание стоит 10, эта наша система счисления, который мы пользуемся в повседневной жизни, называется десятичная; вот как раз по тому, что основание 10. Это означает, что цифры, которыми мы ведем счет (значения в скобках) могут быть только от 0 (нуля) до 9 (девять). Цифры 10 нет в нашей системе счисления, т.к. запись числа 10 уже не простая. 10 – это:

10 = 1 * 10 ^ 1 + 0 * 10 ^ 0

Вот по тому цифры 10 и нет в нашей десятичной системе счисления, потому что иначе бы запись стала не упрощённой.

Всё это хорошо, только для повседневной жизни, потому что мы к этому привыкли, нас с детства начинают учить считать до 10 (по числу пальцев на руках), но в мире информационных технологий хранение информации в десятичном представлении расточительно. Почему так – далее.

Как понимаете, если есть десятичное представление числа, то есть наверно и ещё какое либо. Что будет, если мы вместо 10 в основание поставим 2. Как будет выглядеть, например, число 6?

6 = 1 * 2 ^ 2 + 1 * 2

а теперь запишем по всем предыдущим правилам:

6 = ( 1 ) * 2^2 + ( 1 ) * 2^1 + ( 0 ) * 2^0

получается, что это число 110, но только в двоичной системе счисления, т.к. основание здесь 2, а не 10. Т.е. для записи используется только две цифры – ноль и один (по тому и система двоичная).

ВНИМАНИЕ! Число 110 в двоичной системе – это НЕ(!) сто десять(!!!),- это число один один ноль!

Чтобы как-то понимать, что это в двоичной системе, принято записывать это так:

Для любого программиста знание что такое биты и байты, что такое системы счисления, является обязательным даже в современном мире. И значимость этого не меньше, чем много лет назад.

Однако, в двоичной системе не всегда удобно записывать числа, особенно большие. Например, обычное для нас число 700120 (семьсот тысяч сто двадцать) в двоичной системе выглядит так:

10101010111011011000b

Ну, тут и без объяснения понятно, что сложно работать с числом в таком виде, и такая запись используется только в определенных случаях. По этому чаще числа представляются в другой системе счисления, в шестнадцатиричной. Т.е. системе, где счет цифр идёт от нуля до 15. Ну, подождите!- скажите вы. Что это за цифра такая 15, это число такое 15, а цифры такой нет; да и 14 такой цифры тоже нет, и вообще цифр больше 9 цивилизации не известно! Так то оно так, и вы в чём-то правы, но вы наверно не знали, что цивилизация уже придумала такие цифры, но только для программистов)). Откройте стандартный калькулятор в Windows и переключите его в режим “Программист”:

Для любого программиста знание что такое биты и байты, что такое системы счисления, является обязательным даже в современном мире. И значимость этого не меньше, чем много лет назад.-2

Получится так:

Для любого программиста знание что такое биты и байты, что такое системы счисления, является обязательным даже в современном мире. И значимость этого не меньше, чем много лет назад.-3

Введем число 700120:

Для любого программиста знание что такое биты и байты, что такое системы счисления, является обязательным даже в современном мире. И значимость этого не меньше, чем много лет назад.-4

А теперь переключим режим представления числа на Hex (шестнадцатиричную систему счисления, от слова Hexadecimal):

Для любого программиста знание что такое биты и байты, что такое системы счисления, является обязательным даже в современном мире. И значимость этого не меньше, чем много лет назад.-5

Вот так и выглядит это число. Правильные записи этого числа (понятные другим программистам) будут такие:

Для любого программиста знание что такое биты и байты, что такое системы счисления, является обязательным даже в современном мире. И значимость этого не меньше, чем много лет назад.-6

Часто шрифтом написать подстрочный текст 16 бывает невозможно, особенно в редакторах типа Блокнота, по этому предпочитают линейным текстом, т.е. AAED8hex, AAED8h (маленькими буквами признак системы счисления), но чаще всего выглядит так – 0xAAED8 (ноль икс перед числом).

Кто-то может догадался, что эти буквы означают, а кто-то нет. Ответ вот:

A – это цифра 10

B – это цифра 11

C – это цифра 12

D – это цифра 13

E – это цифра 14

F – это цифра 15

Получается, что наше число 700120 будет выглядеть при правильной записи так:

700120 = ( A ) * 16 ^ 4 + ( A ) * 16 ^ 3 + ( E ) * 16 ^ 2 + ( D ) * 16 ^ 1 + ( 8 ) * 16 ^ 0

Теперь возвращаемся к вопросу расточительности, запишем число 255 (двести пятьдесят пять) сразу в трех системах счисления:

Для любого программиста знание что такое биты и байты, что такое системы счисления, является обязательным даже в современном мире. И значимость этого не меньше, чем много лет назад.-7

В десятичной системе число занимает три разряда (разряды 0, 1, 2), в шестнадцатиричной системе – два разряда, а в двоичной 8 разрядов. Наиболее компактная запись получилась как раз в шестнадцатиричной системе счисления.

Но погодите! Вы же внимательно читали этут статью с самого начала! Я как раз писал, что бит имеет только два состояния 1 или 0 (истина или ложь), а в двоичной системе как раз тоже используется только две цифры 0 и 1, так может быть биты записывать было бы удобно в двоичной системе? О да! Это так, для этого и используют двоичную систему счисления, как раз в тех случаях, когда и нужно работать с какими-то данными именно в битовом представлении, т.е. когда сама информация важна с точки зрения отдельных битов, а числа целиком. Но что с нашим числом 255? Если вы были ещё более внимательны, то увидите, что число 255 – это как раз максимальное число, которое можно представить восемью битами, т.е. одним байтом. Мало того – это максимальное число которое можно представить двумя разрядами шестнадцатиричного числа, а именно – FF. Именно по этому, когда речь идет о каких-то хранящихся внутри системы данных, которые иногда называют бинарными данными, их принято представлять либо в шестнадцатиричном исполнении двумя разрядами, либо в двоичной системе, если важна именно битовая составляющая. Так наше число 700120 (0xAAED8) в виде бинарных данных по два разряда в каждом выглядело бы так:

0A AE D8

Заметьте, к левому разряду пришлось слева подставить ноль, который как вы понимаете, никак не влияет на результат ( 0xAAED8 = 0x0AAED8 ), а сами байты разделить пробелом для лучшего визуального восприятия. Теперь, глядя на эту запись стало понятно, что для хранения числа 700120 компьютеру потребуется выделить три байта памяти (как понимаете, все числа от нуля до 700120 в три байта тоже запихнуть получится). Теперь наоборот, а интересно какое максимальное число можно поместить в три байта? Конечно же это число FF FF FF, а “по-нашему” – 16 777 215. Т.е. любое число от 0 до 16777215 включительно можно сохранить в компьютере используя не более трех байт.

Вот для чего по прежнему используются системы счисления в современном мире – чтобы иметь полное представление сколько памяти нужно выделить для хранения той или иной информации, чтобы это было и не расточительно и перекрывало все необходимые требования (и забегая вперед – не только для этого). Вы скажите может быть,- Да что такое один байт в современном мире, его никто не будет считать?! А вот и нет. Все мы наверно часто работаем в сети интернет, читаем тексты, смотрим картинки, видео. Каждая картинка или один кадр видео – это набор пикселов, каждый представленный чаще всего тремя байтами – по одному байту на каждую компоненту цвета (красный, зеленый, синий). Если вы вместо трех байт выделите четыре, то это увеличит объём необходимых накопителей для хранения картинок и видео на 1/3, что примерно также увеличит и стоимость и обслуживание. Мало того, любое расточительное использование памяти, не вызовет уважение у ваших коллег, если они это заметят, т.к. каждый понимает, что в программировании расточительство ресурсов – это признак дурного тона, непрофессионализм, безалаберность, качества несолидного человека, разгельдяя. Делайте хороший код, старайтесь беречь ресурсы, демонстрируйте этим свой профессионализм!

Java Android. Урок 1 (“Студия”)

Сегодня я традиционно отмечаю день программиста. Потому что именно 5 сентября я первый раз оказался за ЭВМ ))…По этому поводу я решил отметить этот день выпуском первого урока программирования под Android. Прежде чем начать, вынужден сказать, что крайне желательно чтобы ваш компьютер был на базе процессора Intel. Дело в том, что виртуальная среда, где будут происходить запуски приложения, оптимизирована именно под эти процессоры. Информации о том, что процессоры AMD тоже оптимизированы, у меня нет (раньше такого не было). Как это произойдет, я уберу эту ремарку из этого урока. Если же у вас AMD процессор, то самым оптимальным будет использовать для тестов непосредственно ваш мобильный телефон, который необходимо переключить в режим откладки, подключить кабель к компу, и Android Studio должно успешно понять его. Некоторые телефоны и планшеты не могут быть опознаны, в этом случае нормальная комфортная разработка невозможна, нужно что-то делать с вашим железом. Дальнейшая настройка и уроки будут идти исключительно в контексте виртуальной среды.

Всё начинается с простого скачивания Android Studio на свой ПК по этой ссылке:

Download Android Studio & App Tools – Android Developers

developer.android.com

где кликаем по кнопке “Download Android Studio”.

Через некоторое время, когда файл будет скачан, браузер запустит его сам, либо вы должны его запустить вручную (тут всё зависит от ваших персональных настроек безопасности). Установка особо ничем не примечательна, по этому все некстим (ставим программу кликанием по кнопкам “Next” и “ОК”). На этом этапе нам нужно как можно быстрее всё поставить и попробовать сделать наше первое самое простое приложение. Когда всё завершится, мы окажемся перед выбором, что будем создавать.

При первом запуске студио у вас список будет пуст (это всё мои проекты).

Теперь нужно кликнуть кнопку “New Project” (Новый проект). Да, привыкайте, студио на английском, но особых неразрешимых трудностей это не вызовет, если хотя бы несколько раз ходили в школе на занятие иностранного языка. Откроется окно, которое будет уточнять у вас, что за проект вы хотите сделать. Но не торопитесь!

Это не тот выбор, который предлагается сначала, нужен другой.

Необходимо выбрать “Empty Views Activity”:

Это правильный выбор, который сейчас нужен

Всё дело в том, что эта среда разработки поддерживает два языка программирования Java и Kotlin. Мы будем делать проекты на Java. Google постоянно старается продвигать именно Kotlin, хотя лично я к этому не стремлюсь – просто не хочу делать в голове кашу из разного числа языков программирования. Дело в том, что Java Android, Javascript, Java Tomcat, C, PHP – это похожие по своему синтаксису языки, а Kotlin не похож на них. Не охота вводить диссонанс в голове. В общем, выбираем вариант указанный на картинке. Далее в новом окне даём название нашему приложению. Будем делать свою первую игруху на Android с названием “Быки и коровы”, но написать это нужно латинскими буквами. По этому чтобы не изобретать ещё один “Олбанский” язык, пишем название “Bulls And Cows App”, и убеждаемся, что проект будет на языке Java (поле Language):

По прошествии некоторого времени, когда комп прошуршит жёстким диском и выместит на экран все сообщения пользователю, которые он хотел сказать, появится окно похожее на это. Если что-то будет лишнее справа или слева, или снизу, то это пока можно будет скрыть:

А вот полезное окно слева с названием Structure лучше сразу открыть:

Кликая дважды мышью по элементам структуры, удобно переходить сразу на начало объявления соответствующих элементов кода. Когда проект большой, это удобно.

Одна из основных заповедей в работе на компьютере это “Не навреди!”. По этому первое время правильным будет примерно такой подход к кликанию мышью в Android Studio (это я утрирую):

Т.е. серьёзность понимаете? )).

Ну, шутки шутками, а всё-таки пока лучше в незнакомые опции не заходить. Сейчас задача запустить своё первое приложение. Как раз именно сейчас для этого уже всё и готово. Да, Android Studio сделал для нас Empty проект, т.е. пустой, с самым минимумом того чтобы создать приложение. Давайте сразу же и посмотрим что получилось от ничего не программирования. По этому нужно кликнуть в меню Tools->Device Manager:

Справа появится панель управления виртуальными устройствами (эмуляторы мобильного телефона и иных устройств):

При первом запуске панели список устройств будет пуст (это мой список устройств)

Теперь нужно создать новое устройство кнопкой “Create Device”, которая находится над этим списком. Далее опять всё некстим и океем не вдаваясь в подробности, просто проследив, что создаётся именно Phone (мобильный телефон), а не Андроид ТВ, планшет или ещё что. Другие параметры сейчас не так важны.

Далее посмотрите, что с выбором операционной системы:

Список операционных систем

Если кнопка “Next” доступна, то жмём на неё; это значит образ операционной системы уже установлен вместе со Studio, если не доступна, то слева будет значок скачивания. Посмотрите внимательно на этот список, который на скрине – у Pie (активная строка) нет такого значка потому что она уже скачана и кнопка “Next” доступна, а у других есть – они ещё не скачаны. Качать все сразу смысла нет, они занимают достаточно много места, а использоваться будут в работе только несколько. По мере надобности можно потом скачать. В следующем окне тоже особо ничего пока не нужно и нужно нажать “Finish”.

Будет создано ваше первое виртуальное устройство.

Теперь необходимо убедиться, что устройство с этим именем находится в выборе запуска, и если не так, то сделать этот выбор (возможно у вас будет другое название):

Выбор конфигурации виртуального устройства для запуска

После выбора нужно кликнуть по кнопке с зеленой стрелкой вправо, находящейся сразу справа от списка. Среда разработки какое-то время подумает, поделает всякие действия и в результате справа должно появиться что-то вроде этого:

Нижнее окно и окно менеджера устройств можно теперь свернуть и тогда это будет выглядеть так:

Вот ваш виртуальный мобильник, который практически тот же, что и был бы реальный, тоже с установленной системой Android (помните версии образов на скачивание, у меня была Pie – Android 9). И да, вот о чём я писал в этой статье

Начало программирования вообще с нуля

El Vinto1 сентября

про философию “”Hello, world!”. Благодаря этой надписи на экране вашего виртуального мобильника мы хорошо теперь знаем, что виртуальная среда настроена правильно, среда разработки настроена правильно, программа написана без ошибок (конечно же, мы ведь в ней ничего не меняли ещё), и вообще всё круто,- вы всё сделали правильно!

Теперь нужно перейти вот сюда (развернуть) и кликнуть двойным кликом по MainActivity.xml (если вы вдруг случайно закрыли эту вкладку):

После этого смените подвкладку на “Code” (скорее всего изначально будет открыта “Design”):

Замените надпись “Hello, world!” на “Привет, мир!” и снова перезапустите своё приложение кнопкой с зеленой стрелкой (кнопкой “Run”), которая может теперь быть завёрнутой стрелкой (см.далее):

Завернутая стрелка кнопки Run. Означает не запустить приложение, а перезапустить приложение. Фактически тоже самое, только в обновленном виде.

Должно получиться вот так:

Поздравляю! Теперь вы стали программистом под Android. И хотя программа ваша слишком проста, вы уже программист, просто находитесь с самом начале профессионального пути. Насколько написанный вами дальше код будет сложен и многогранен, зависит только от вашей фантазии, творчества и желания!

Задание по уроку:

1. Попробуйте самостоятельно найти в иерархии проекта (Панель слева “Project”) место, где хранится название вашего приложения. Замените его на название на русском “Быки и коровы”

2. В виртуальном мобильном телефоне удалите установленное это ваше приложение и переустановите заново с новым именем. Добавьте на этом виртуальном устройстве в интерфейсе системы русский язык чтобы всё было так, как-будто язык Андроида русский (это делается через обычные стандартные настройки языка). Это скорее больше задания как для пользователя мобильного телефона, но умение этого будет необходимо в дальнейшем.

Если всё получилось как нужно – молодцы! Если нет, давайте разберёмся что не так.

Java Android. Урок 2 (“Frontend”)

Как помните, в прошлом уроке мы стали создавать наше первое приложение “Быки и коровы”. В готовом виде это приложение есть в моём аккаунте по этой ссылке (чтобы понимать что мы хотим делать):

Быки и коровы в каталоге RuStore

apps.rustore.ru

В этом уроке вы будете создавать среду взаимодействия с пользователем, которую часто называют “интерфейс пользователя”, а креативные специалисты предпочитают название Frontend. Если простыми словами – это то, что видит на экране пользователь. Как понимаете, есть и то, что тоже является работой программы, но что пользователь не видит, но об этом позже.

Смысл этой детской игры достаточно прост. Играют двое (в данном случае одним из игроков будет вычислительная среда мобильного телефона, а вторым – человек / пользователь). Один загадывает число из 4-х знаков, все цифры которого различные, второй игрок, пользуясь подсказками должен угадать узнать это число. Загадывать будет компьютер, отгадывать человек, компьютер/мобильник/планшет будет давать подсказки. Подсказки даются следующим образом. Если в называемом числе есть цифра в загаданном и находится в своём разряде (на таком же месте), то это “бык”, а если есть такая цифра, но не находится на своём месте, то это “корова”. Если угаданных цифр несколько, то соответствующее число будет быков и коров. Как понимаете название игры весьма условно, т.к. реальных быков и коров вы в этой игре не увидите. Игра эта тренирует логическое мышление у детей, а также память, способность целостно представлять решение задачи, искать рациональные логические решения. Связано это с тем, что любое число можно отгадать за определенное минимальное число вопросов. Поясню подробно. Например:

Компьютер загадал число

4678

Мы пытаемся отгадать и называем первое придуманное число

2684

Компьютер должен нам сообщить, что в нашем числе 1 бык и 2 коровы:

бык – это цифра 6, она есть в загаданном числе и находится в 3-м разряде (разряды считаются справа-налево).

коровы две – это цифры 4 и 8, т.к. они тоже есть в числе, но стоят не в строгом соответствии разрядов.

Сложность тут в том, что компьютер нам не скажет, что именно является быком, а что коровами. Просто сообщает что они есть и сколько их. Теперь мы уже точно знаем, что какая-то из цифр нашего придуманного числа точно стоит на своём месте, а ещё есть две, но не на своём. По этому мы используя эту информацию должны снова придумать число и сказать его компьютеру, например мы говорим

2184

Компьютер нам сообщит после этого, что в этом числе только 2 коровы. По этому мы теперь точно знаем, что 6 была быком. Т.е. одну цифру мы знаем точно и где она находится в угадываемом числе. Однако, мы могли и не угадать с первого раза, а назвать число, например 1874 – это было бы тоже 1 бык и 2 коровы, мы бы от этого только запутались. В этом и заключается интерес – как правильно мы используем каждую очередную подсказку, как правильно называем вариант и как быстро сможем узнать загаданное компьютером число. Помню нас школьников эта игра очень увлекала в 3-м классе.

Итак, задача поставлена, теперь нужно создать пользовательский интерфейс, который будет отображать на экране телефона текущее состояние, уже введенные нами варианты, сколько в каждом было быков и коров и ещё должно быть поле ввода цифр, которое и будет принимать от нас каждый новый вариант числа. В последствии алгоритм будет его сравнивать с загаданным числом и выдавать результат сравнения.

Рассмотрим подробнее как выглядит файл MainActivity.xml, в котором на прошлом уроке вы меняли “Hello, world!” на “Привет, мир!”.

Файл выполнен в формате XML, об этом свидетельствует надпись вначале

<?xml”

Тут придётся немного рассказать вкратце о его структуре, тем более что формат очень популярен и используется не только в Андроид Студии. Файл состоит из контейнеров, которые образно выглядят вот так (его границы, а также внутренности – тело):

<ИмяКонтейнера Атрибут1=”значение1″ Атрибут2=”значение2″ ещё атрибуты…>

…тут что-то находится внутри и называется телом…

</ИмяКонтейнера>

Т.е. контейнер состоит из открывающего элемента и закрывающего элемента, а внутри – тело. Эти элементы начала и конца называются открывающий тэг и закрывающий тэг. Конец контейнера определяется почти также как и его начало, у него имя точно такое же, но нет атрибутов и перед именем стоит косая черта (правый слеш /). Контейнеры нужны чтобы внутрь переменной ИмяКонтейнера запихнуть большую кучу всякой информации.

Название контейнеров, атрибутов в данном файле строго регламентировано и должно называться строго определенными названиями. Значение атрибутов должны быть только определенного для них типа и в строго определенном диапазоне значений, если такой диапазон предусмотрен.

Вторая конструкция xml файла – это просто тэги. Это тот же контейнер, только без тела внутри (у него нет закрывающего тэга). Но открывающий выглядит чуть по другому:

<ИмяТэга Атрибут1=”значение1″ />

т.е. правый слэш стоит в конце в тэге, атрибутов тоже любое количество, закрывающего нет и тела тоже нет.

Сами тэги, как наверно уже поняли – это то, что находится между угловыми скобками (они же знаки меньше-больше) :

<тут всё, что относится к тэгу вместе с атрибутами>

Атрибуты – это некая характеристика тэга, его параметр, иная информация относящаяся непосредственно только к этому тэгу.

В таких файлах xml и находится как раз полное описание того, что находится на экране…но это не точно)))…но об этом гораздо позже. Сейчас должны знать, что какой файл MainActivity вы сделаете, то это на экране и будет. Вопрос, а что конкретно можно описать там?

Если вы держите в руках мобильный телефон на Android не впервые в жизни (если это не так, то уже настало время это поделать), то наверно видели, что на экране могут быть:

  • обычный текст
  • поля для ввода какого-то текста
  • картинки
  • кнопки
  • различные переключатели тип вкл/выкл
  • различные выборы из списков
  • перечни
  • так называемые радиокнопки (несколько кружочков с текстом, где можно выбрать только один из нескольких вариантов)
  • чекбоксы (где можно поставить галочку)
  • географические карты
  • и т.п.

Это всё можно и нужно описать в этом MainActivity.xml

По этому, чтобы далеко не ходить, разработчики Android так и решили называть тэги и контейнеры по типу того объекта, которые пользователю нужно показать. Например, взгляните на наш этот файл и посмотрите внимательно в каком тэге какой атрибут мы поменяли, когда изменили текст “Hello, world!” на “Привет, мир!”. Это атрибут “android:text” тэга TextView. Т.е. тэга, который выводит на экран просто обычный текст. Посмотрите, какие ещё у этого тэга атрибуты:

android:layout_width – это ширина этой текстовой области

android:layout_height – это высота этой текстовой области

есть и ещё другие атрибуты, которые мы будем рассматривать в следующих уроках, пока рано.

Ещё заметьте, что ширина и высота заданы не цифрами, а служебным словом “wrap_content”. Всё дело в том, что разработка под Android идёт с учетом различных устройств, а если быть более точным – более 10 тыс. различных устройств. Все эти устройства имеют разные характеристики, и что важно – разные размеры экранов. Работа программиста заключается в том, чтобы ни на каком из этих экранов интерфейс пользователя не отобразился криво, чтобы всё влезло по ширине и высоте, чтобы слова правильно переносились, чтобы текст не выходил за пределы экрана и т.п. Это называет адаптивный интерфейс (или адаптивный дизайн), т.е. интерфейс, который будет пытаться подстроиться под каждый размер экрана каждого устройства. Если, например, вы укажете точную ширину в пикселях, то на крохотных экранах часть текста может оказаться либо не видна, либо переноситься по середине слова, а на больших экранах окажется много свободного неиспользуемого места справа. По этому стараются делать так, чтобы приложение автоматически попробовало по ширине нужной области, а если уж это не получится, то и стало бы переносить. Но все бы так и делали, если бы в дизайне иногда не требовалось разместить несколько объектов слева направо, например фраза “Введите логин:” и справа от него поле ввода логина. Если бы они оба были по ширине экрана или оба имели бы фиксированную ширину, то см. выше, что я только что написал – дизайн бы съехал. По этому придумано много различных вариантов задания ширины и высоты, а именно:

  • в условных единицах, например, 50dp, 125dp
  • по ширине содержимого текста, wrap_content. Т.е. какой ширины отображаемый текст, таким и будет ширина этого объекта. Удобно как раз для текста “Введите логин:”
  • по ширине вышестоящего контейнера, а если его нет – экрана, match_parent

Всё тоже касается и высоты. Каждый из этих вариантов выбирается под конкретную задачу по мере необходимости.

Теперь, после того как вы немного сориентировались с тэгом TextView, обратите внимание в каком контейнере он сам располагается. Это контейнер с именем androidx.constraintlayout.widget.ConstraintLayout. Не нужно запоминать такое длинное название, это просто контейнер ConstraintLayout. Длинный путь нужен среде разработки чтобы она сама не запуталась где его внутри своих библиотек кода искать. Если вам потом придётся вводить его вручную, то среда разработки сама подскажет откуда она его будет брать, как только начнете набирать слова ConstraintLayout (без пробелов), тут обычно никаких ошибок не возникает. Теперь заметьте какую ширину и высоту этот контейнер имеет – match_parent, т.е. учитывая что над ним нет уже никакого контейнера, этот значит, что он будет во весь экран по ширине и высоте. ConstraintLayout – это специальный контейнер, который на экран ничего не выводит, он просто позволяет выстраивать на экране те элементы, которые у него внутри в определенном порядке и по определенным правилам. О нём позже.

С размером элемента TextView всё понятно, а как же поменять цвет текста, цвет фона, сделать текст более жирным или наклонным?- возможно спросите вы. Давайте теперь сменим подвкладку на эту (“Design”):

Как помните, в прошлом уроке мы стали создавать наше первое приложение "Быки и коровы".

Теперь нужно кликнуть на компонент TextView:

Как помните, в прошлом уроке мы стали создавать наше первое приложение "Быки и коровы".-2

После этого справа отобразятся все его свойства, также обратите внимание на ползунок Scroll, который означает, что это лишь часть атрибутов, а есть ещё, если протащить ползунок вниз:

Как помните, в прошлом уроке мы стали создавать наше первое приложение "Быки и коровы".-3

Видно поле text со значением “Привет, мир!”, видны layout_width и layout_height и ещё много чего. Далее вниз будут и жирность и наклон и т.п., находятся в группе textStyle:

Как помните, в прошлом уроке мы стали создавать наше первое приложение "Быки и коровы".-4

Цвет текста – это textColor, а цвет фона – background

ОЧЕНЬ ВАЖНО! Заметьте как написан атрибут textColor – буква С – заглавная. В языке Java, а также и ещё во многих языках, textcolor и textColor воспринимаются как совершенно разные переменные и атрибуты, т.е. мы имеем дело с регистр чувствительным синтаксисом.

Задание по уроку:

1. Установите текст поля вместо “Привет, мир!” на текст “МОИ ХОДЫ”

2. Разберитесь самостоятельно, используя поисковик Гугл или Яндекс (это в будущем придётся делать вам часто, лучше сразу привыкать) как задаётся цвет текста в HTML, как правильно записывается цвет в цифровом виде RGB (красный, зеленый, синий). Как примерно происходит смешение трех цветов формата RGB. Установите на текст “МОИ ХОДЫ” цвет текста темно-сиреневый (насколько тёмно и сиреневый – на ваш вкус). Пришлите в коммент скриншот что получилось.

3. Попробуйте установить цвет фона для всего отображаемого экрана на бирюзовый

Если всё получилось как нужно – молодцы! Если нет, давайте разберёмся что не так.

Java Android. Урок 3 (“Элементы”)

На прошлом уроке мы начали рисовать пользовательский интерфейс, а на этом его закончим и приступим нажимать на клавиши в редакторе кода Java.

Цель этого занятия будет сделать как-то вот так:

На прошлом уроке мы начали рисовать пользовательский интерфейс, а на этом его закончим и приступим нажимать на клавиши в редакторе кода Java.

Что на экране нам видно? Вверху системная область с часами и значками, внизу тоже системная область с кнопками возврата, выхода из приложения и смены активного приложения, а между ними наш пользовательский интерфейс. Этот интерфейс состоит из следующих элементов:

  • Текстовое поле с надписью “МОИ ХОДЫ”
  • Слегка зеленоватое пустое поле, где будет список этих ходов
  • Четыре разряда вводимого нами угадываемого числа
  • 10 кнопок с цифрами от 0 до 9 для ввода угадываемого нами числа
  • кнопка стереть цифру, если пользователь ошибся с вводом
  • кнопка помощи для отображения пользователю правил игры
  • кнопка ввода числа (её видно на следующем рисунке)

После ввода последней четвертой цифры, появляется ещё одна кнопка ввода (нельзя ввести число, которое меньше 4 разрядов):

На прошлом уроке мы начали рисовать пользовательский интерфейс, а на этом его закончим и приступим нажимать на клавиши в редакторе кода Java.-2

При вводе очередной цифры, нужно отметить пользователю, что эту цифру в этом ходе больше использовать нельзя, т.к. по правилам игры все цифры числа должны быть разными.

В домашнем задании прошлого урока была одна из задач, изменить текст поля TextView на текст “МОИ ХОДЫ”. Это как раз первый элемент нашего интерфейса. Вторым элементом должен быть список, который будет содержать историю наших ходов/попыток угадать число, загаданное компьютером. Делается это при помощи тэга RecyclerView. Его можно начать писать вручную (я часто делаю так) в подвкладке “Code”, а можно потянуть из набора элементов в подвкладке “Design”. Второй вариант делается так, как показано далее. Находим элемент в панели (Common->RecyclerView):

На прошлом уроке мы начали рисовать пользовательский интерфейс, а на этом его закончим и приступим нажимать на клавиши в редакторе кода Java.-3

Далее хватаем левой кнопкой мыши и тянем на панель ниже после TextView (метод Drag-and-Drop). Должно получиться так:

На прошлом уроке мы начали рисовать пользовательский интерфейс, а на этом его закончим и приступим нажимать на клавиши в редакторе кода Java.-4

Теперь снова откройте подвкладку “Code”. Там должно быть примерно так:

На прошлом уроке мы начали рисовать пользовательский интерфейс, а на этом его закончим и приступим нажимать на клавиши в редакторе кода Java.-5

Укажите цвет фона для списка как бледно-салатовый. С точки зрения распределения цветов это F0FFF0. В результате в коде должно получиться так:

На прошлом уроке мы начали рисовать пользовательский интерфейс, а на этом его закончим и приступим нажимать на клавиши в редакторе кода Java.-6

Что означают эти буквы и нули и как это влияет на цвет было в домашнем задании прошлого урока. Для кого незнакомо само понятие шестнадцатиричной системы чисел (в которой и задаётся этот цвет), то рекомендую прочитать мою статью “Начало программирования вообще с нуля. Часть 2”. Обратите внимание на знак решетки # перед числом, он необходим, сообщает среде разработки, что вы указываете цвет числовым методом в формате RGB (красный, зеленый, синий).

Перезапустите ваше приложение и посмотрите какая бодяга получается:

На прошлом уроке мы начали рисовать пользовательский интерфейс, а на этом его закончим и приступим нажимать на клавиши в редакторе кода Java.-7

Надпись куда-то исчезла, а зелёный список стал на весь экран. Возвращаемся к коду. Пришло время познакомиться с контейнером ConstraintLayout, о котором я рассказывал на прошлом уроке. В этом контейнере сейчас находятся два элемента – TextView и RecyclerView. Теперь понимаете зачем нужны контейнеры вообще? Правильно, чтобы туда накидать разных элементов и среда разработки понимала, что всё что внутри контейнера (его тела) относится непосредственно к этому контейнеру, и так вкладывать друг в друга можно как матрешки настолько много раз, насколько это позволительно в данном контексте.

Так вот, контейнер ConstraintLayout как раз и нужен чтобы правильно размещать элементы друг по отношению к другу методом привязки. Это метод, в котором мы, например, говорим так: “Сделай так, чтобы левая граница элемента RecyclerView зависела от положения левой границы экрана (которая всегда будет сама по себе постоянной), а верхняя граница элемента RecyclerView пусть зависит от положения нижней границы текстового поля, где надпись “МОИ ХОДЫ”. При такой зависимости как бы не крутили экраном (портретный режим или альбомный как на планшете), левая граница RecyclerView начнёт подтягиваться к левой части экрана (в том положении, в котором сейчас он находится), а верхняя граница всегда будет подтягиваться к “МОИ ХОДЫ”, таким образом RecyclerView всегда будет ниже этого текстового поля и вплотную к нему примыкать. Это как раз нам и надо, но прежде нужно привести всё в порядок. Посмотрите куда сейчас тянется поле TextView, это выполняется атрибутами типа layout_constraintBottom_toBottomOf. Слегка английского:

  • Top – верх
  • Bottom – низ
  • Start – начало
  • End – конец

constraintBottom_toBottomOf переводится как “привязать низ к низу…чего-то там” и чего-то там указывается в кавычках. Там сейчас указано “parent” (родитель). Т.е. ситуация сейчас такая – левая граница TextView тянется к левой части родительского контейнера, правая к правой, верхняя к верхней, а нижняя к нижней. Родительским контейнером для TextView является ConstraintLayout (потому что он и располагается в его теле), а родительский для самого контейнера ConstraintLayout является уже экран, т.к. он ни в чём другом не располагается (он корневой контейнер). По этой причине мы и видели, если кто заметил, что надпись “МОИ ХОДЫ” была расположена прямо по центру. Тут как в басне Крылова “Лебедь, рак и щука”, каждый стал тянуть на себя со всех сторон и надпись зависла посередине – а воз и ныне там. Но нам сейчас такое не надо, нам надо так, что Бог с ним с лево-право, пусть тянут каждый на себя, а вот тянуть вниз не надо, нужно чтобы надпись притянулась вверх к краю экрана. По этому лишний атрибут layout_constraintBottom_toBottomOf убираем вообще, должно получиться так:

На прошлом уроке мы начали рисовать пользовательский интерфейс, а на этом его закончим и приступим нажимать на клавиши в редакторе кода Java.-8

RecyclerView наоборот – сейчас не имеет никаких привязок, при такой ширине и высоте, как у него,- match_parent – совпадает с родительским, т.е. в данном случае весь экран, они и не нужны. Именно по этому он и занял весь экран. Сделайте ему тоже привязки, только верх его нужно притянуть к низу TextView. И вот тут резонный вопрос был бы такой: “А как это сказать системе разработки? Когда parent – это понятно, но TextView как указать? Их наверно в интерфейсе может быть не один и не два, я же не могу просто TextView указать, мне нужно как-то идентифицировать, что я хочу привязать именно к этому TextView!” Да действительно, когда на экране должно быть что-то больше, чем “Hello, world!”, то элементы придётся уже идентифицировать, и разработчики среды разработки уже придумали как это делать,- нужно просто добавить к элементам их идентификатор, который будет уникален для каждого (т.е. не будет ни у кого повторяться). Делается это специальным атрибутом, в результате чего должно получиться как-то так:

На прошлом уроке мы начали рисовать пользовательский интерфейс, а на этом его закончим и приступим нажимать на клавиши в редакторе кода Java.-9

Т.е. TextView мы дали идентификатор textViewTitle, а для RecyclerView мы дали идентификатор rvSteps. Как понимаете, придумать можно и что-то своё, но делать этого сейчас не нужно, т.к. потом мы будем к ним ещё обращаться по идентификаторам, и может возникнуть путаница. Будете делать что-то своё потом, называйте как хотите, лишь бы потом сами не запутались. В моих названиях есть закономерность – сначала идет признак типа самого элемента (textView или rv – RecyclerView), а затем смысловое значение,- Title – заголовок, Steps – шаги/ходы и т.д. Для RecyclerView мы дали идентификатор потому что возможно его само придётся к чему-то привязывать, а может и нет, пока не знаем. Вообще, хорошая практика, что всё что внутри контейнера ConstraintLayout обязательно должно содержать id, а я так вообще могу давать id на любой элемент интерфейса, не усматриваю в этом ничего плохого, пусть среда разработки сама разбирается что ей потребуется для расположения элементов, а что она проигнорирует.

Теперь приступим делать привязки. Тут можно наверно интуитивно догадаться, что есть наверно какая-то привязка, которая выглядит по принципу “Привяжи верх к низу”, а не “Низ к низу” или “Верх к верху”. Так и есть, и выглядит она соответствующе. Кстати, если вы будете их вводить в коде, например начнете набирать слово Constraint, то развитая система подсказок начнет постепенно понимать что же вы хотите ввести, тут останется только в нужный момент на Enter на клавиатуре нажимать:

На прошлом уроке мы начали рисовать пользовательский интерфейс, а на этом его закончим и приступим нажимать на клавиши в редакторе кода Java.-10

Привязки налево и направо тоже нужно дать. Дело в том, что если вы не растягиваете элемент по родительскому контейнеру, то вы как минимум должны сообщить куда по горизонтали и вертикали нужно вообще привязать ваш элемент, ну это и понятно, иначе что он вообще делает в этом контейнере. В результате будет как-то так:

На прошлом уроке мы начали рисовать пользовательский интерфейс, а на этом его закончим и приступим нажимать на клавиши в редакторе кода Java.-11

Сами понимаете, горизонтальные привязки у RecyclerView точно такие же как и у TextView, по этому я их просто выделил и скопировал (откопипастил) )).

Следующее поле за RecyclerView тоже будет TextView, как это ни странно, ведь это такой же простой текст выводимый на экран, как и “МОИ ХОДЫ”, только, если заметить, отличается размером шрифта и самим шрифтом:

На прошлом уроке мы начали рисовать пользовательский интерфейс, а на этом его закончим и приступим нажимать на клавиши в редакторе кода Java.-12

Да, совершенно верно, наверно есть у этого тэга TextView атрибуты, которые отвечают и за размер и за сам шрифт, добавьте теперь такой элемент и дайте ему соответствующие привязки:

На прошлом уроке мы начали рисовать пользовательский интерфейс, а на этом его закончим и приступим нажимать на клавиши в редакторе кода Java.-13

textSize – размер шрифта

text – текст по умолчанию, т.е. начальный текст, который особо здесь не нужен, т.к. это будет у нас управляемое поле – мы будет менять в нем текст программным путём причём сразу при загрузке приложения. Но для вида пусть будет.

fontFamily – сам шрифт, в данном случае не стандартный Android. Этот шрифт нужно подгрузить в среду разработки. С этим придётся немного заморочиться, но тоже решаемо. Сейчас расскажу как.

Для начала создайте в своем проекте ещё один каталог внутри каталога res. Делается это так:

Тут правой кнопкой мыши

Тут правой кнопкой мыши

На прошлом уроке мы начали рисовать пользовательский интерфейс, а на этом его закончим и приступим нажимать на клавиши в редакторе кода Java.-15

Дайте имя нового каталога “font” и обязательно укажите в списке выбора тип ресурса тоже как font:

На прошлом уроке мы начали рисовать пользовательский интерфейс, а на этом его закончим и приступим нажимать на клавиши в редакторе кода Java.-16

После этого скачайте файл шрифта с моего ресурса:

https://elvinto.ru/javalessons/digital7.ttf

и перетащите этот файл в Андроид Студио в эту свежесозданную папку font. После всех манипуляций сначала получиться так, где среда разработки предложит разместить этот шрифт внутри папки:

На прошлом уроке мы начали рисовать пользовательский интерфейс, а на этом его закончим и приступим нажимать на клавиши в редакторе кода Java.-17

А после нажатие на Refactor так:

На прошлом уроке мы начали рисовать пользовательский интерфейс, а на этом его закончим и приступим нажимать на клавиши в редакторе кода Java.-18

Теперь при указании шрифта, студия разработки будет сама подсказывать какой шрифт взять:

На прошлом уроке мы начали рисовать пользовательский интерфейс, а на этом его закончим и приступим нажимать на клавиши в редакторе кода Java.-19

А теперь взглянем ещё раз что получается, а получается какая-то проблема:

На прошлом уроке мы начали рисовать пользовательский интерфейс, а на этом его закончим и приступим нажимать на клавиши в редакторе кода Java.-20

Что это я такой за элемент написал textView0, к верху которого мы привязываем низ textViewNumber? И да, система разработки сообщает красным цветом, что возникла проблема с привязкой.

В действительности так получилось потому что мы проектируем быстрее, чем понимает это система. Это поле кнопки “0” из серии кнопок от 0 до 9. Но вы тут наверно скажите,- Э-э-э, автор, стой! Не логично получается! Ты писал, что название элементов у тебя называются по типу элемента, а мы уже успели полазить по иерархии элементов и там кнопка – это не textView, а Button:

На прошлом уроке мы начали рисовать пользовательский интерфейс, а на этом его закончим и приступим нажимать на клавиши в редакторе кода Java.-21

Тогда, спрашивается, почему ты делаешь название будущего элемента со слов “textView…”, а не со слова “button…”?

– Да,- отвечу я,- вы меня хорошо поймали на этом, респект! Но я ожидал ваш вопрос, вы не застали меня врасплох! )))

Всё дело в том, что некогда я понял, что мне не очень нравится как выглядит кнопка в Android с её границами, с тем, что весь текст она туда встраивает в верхнем регистре (заглавными буквами) и ещё много чего. По этому я решил, а что если я попробую вместо элемента Button использовать TextView, а потом сделаю так, что он будет отрабатывать нажатие на него как это делает кнопка. И это прошло на ура! И не удивительно. Если кто читал мою эту статью:

Начало программирования вообще с нуля. Часть 1

El Vinto1 сентября

, где я рассказывал что такое в современном программирование классы, то вспомнит, что один класс может функционально расширять другой класс, который делали другие программисты или вы сами. И что тут неудивительно, внутри среды разработки TextView и Button, и еще много других – это тоже классы, которые расширяют класс View. Этот класс View и обладает методом обработки нажатия на него, когда пользователь кликает пальцем, а потом по логике и все расширяющие его классы тоже по идее должны обрабатывать. По этому Button это или TextView – это всё классы расширяющие класс View, только нужно правильно подтолкнуть его в нужном направлении.

Если бы разработчики среды разработки сделали метод обрабатывающий нажатие кнопки закрытым (private) для TextView и не сделали интерфейс метода для работы с нажатием, такой фокус бы не удался. Но об этом, когда более подробно будете изучать Java Android.

Хотите, сделайте кнопки 0-9 через Button, хотите как я через TextView, только имя давайте аналогичные моим, опять-таки для того чтобы потом не запутаться. Кстати, и картинки я часто делаю тоже через TextView, где картинка – это background. Да, именно так, в этот атрибут можно поставить не только цвет фона, но и картинку фона. Выглядит это так:

На прошлом уроке мы начали рисовать пользовательский интерфейс, а на этом его закончим и приступим нажимать на клавиши в редакторе кода Java.-22

Однако тут нужно провести ряд подготовительных операций, почти как со шрифтом, но только проще. Дело в том, что в Android есть базовый набор картинок специально для общих случаев, чтобы настройки приложений различных разработчиков были однотипны, ну типа шестеренка – это настройка, фотоаппарат, значит сделать фото и т.д. Мы в этот раз используем как раз эти картинки. Сделать нужно следующее. Кликнуть по каталогу drawable в иерархии проекта правой кнопкой мыши:

На прошлом уроке мы начали рисовать пользовательский интерфейс, а на этом его закончим и приступим нажимать на клавиши в редакторе кода Java.-23

Укажите тип ассета “Clip Art” и кликните по самой кнопке “Clip Art”

На прошлом уроке мы начали рисовать пользовательский интерфейс, а на этом его закончим и приступим нажимать на клавиши в редакторе кода Java.-24

Откроется окно выбора:

На прошлом уроке мы начали рисовать пользовательский интерфейс, а на этом его закончим и приступим нажимать на клавиши в редакторе кода Java.-25

Выбираем любое, что подходит по смыслу. Далее “некстим”. По результату должно получиться примерно такое:

На прошлом уроке мы начали рисовать пользовательский интерфейс, а на этом его закончим и приступим нажимать на клавиши в редакторе кода Java.-26

В каталоге drawable появится новый элемент с именем, которое Студио сама дала (его мы просто не меняли, хотя могли), и если мы по нему дважды кликнем откроется описание и образец этой картинки. Теперь мы можем ссылку на неё подкинуть как background, не забывая поставить путь как на скриншоте (разве что имя поставьте то, которое у вас по факту будет):

На прошлом уроке мы начали рисовать пользовательский интерфейс, а на этом его закончим и приступим нажимать на клавиши в редакторе кода Java.-27

Задание по уроку:

1. Разместите оставшиеся элементы – кнопки с цифрами и кнопки-картинки, картинке подберите по смыслу или визуально как у меня, можно похожие. Дайте идентификаторы кнопкам 0-9 соответственно textView0, textView1,…,textView9. Укажите идентификаторы для кнопок “стереть символ”, “правила” и “ввод числа” соответственно textViewBackspace, textViewRules и textViewEnter.

2. Самостоятельно прогуглите тему, чем отличается векторная картинка от растровой в общих чертах.

Если всё получилось как нужно – молодцы! Если нет, давайте разберёмся что не так.

Java Android. Урок 4 (“Первый код”)

После того как вы разместили элементы отображения, задали им необходимый порядок на экране, давайте снова запустим приложение посмотреть его в двух режимах, в портретном и альбомном. Делается это при помощи кнопок поворота виртуального устройства:

После того как вы разместили элементы отображения, задали им необходимый порядок на экране, давайте снова запустим приложение посмотреть его в двух режимах, в портретном и альбомном.

В результате должно получиться как-то так:

Портретный режим:

После того как вы разместили элементы отображения, задали им необходимый порядок на экране, давайте снова запустим приложение посмотреть его в двух режимах, в портретном и альбомном.-2

Альбомный режим:

После того как вы разместили элементы отображения, задали им необходимый порядок на экране, давайте снова запустим приложение посмотреть его в двух режимах, в портретном и альбомном.-3

После этого хорошо стало видно, что игра очень плохо смотрится при такой настройке в альбомном режиме, по этому проще будет вообще такую возможность сразу отключить. Если вы замечали, некоторые приложения так и построены, как ни верти телефон, интерфейс не поворачивается. Ничего в этом плохого нет, особенно когда понимаешь, что в таком расположении будет просто не удобно при каждом повороте адаптироваться. Тут в альбомном режиме придётся часть интерфейса преносить вправо или влево и нарушается восприятие логики игры. Хотя, при желании можно и попробовать, но не сейчас. По этому познакомимся еще с одним файлом проекта под названием AndroidManifest.xml. Это файл описания структуры нашего приложения, его названия и еще много чего, что потом будет передано в итоговый файл для публикации приложения. Именно в этом файле также располагаются и все требования прав, например, такие как разрешение на доступ к дискам, доступ в интернет, доступ к камере устройства и т.д. Файл также оформлен в формате XML, с которым мы начали знакомиться на прошлом уроке, но только он описывает другие данные, но по аналогичному принципу. Сейчас в этом файле вам нужно найти контейнер, отвечающий за окно, которое делали в прошлом уроке, и добавьте новый атрибут с необходимым значением:

После того как вы разместили элементы отображения, задали им необходимый порядок на экране, давайте снова запустим приложение посмотреть его в двух режимах, в портретном и альбомном.-4

После этого как экран не вертите, окно будет в режиме портрета:

После того как вы разместили элементы отображения, задали им необходимый порядок на экране, давайте снова запустим приложение посмотреть его в двух режимах, в портретном и альбомном.-5

Верните положение виртуального телефона обратно в привычное:

После того как вы разместили элементы отображения, задали им необходимый порядок на экране, давайте снова запустим приложение посмотреть его в двух режимах, в портретном и альбомном.-6

Отройте вкладку с кодом, должен он выглядеть примерно так:

После того как вы разместили элементы отображения, задали им необходимый порядок на экране, давайте снова запустим приложение посмотреть его в двух режимах, в портретном и альбомном.-7

Начинаем разбираться. Весь основной код этого файла размещается внутри объекта “public class MainActivity…” между его фигурными скобками. Кто не читал мою статью:

Начало программирования вообще с нуля. Часть 1

El Vinto1 сентября

крайне рекомендую. Я в этой статье объяснял что такое классы и для чего нужны. Язык Java не исключение, он тоже позволяет описывать такие объекты, как классы. Наш класс называется MainActivity и расширяет класс AppCompatActivity. Как всё происходит. При нажатии на иконку приложения в вашем мобильном телефоне для его запуска, или запуске приложения через виртуальную среду по кнопке “Run” (как вы уже это несколько раз делали), происходит сначала анализ файла AndroidManifest.xml, который мы только что смотрели и указывали там на портретное представление. Однако, там есть ещё один контейнер, который указывает, какой объект нужно активировать при запуске приложения:

После того как вы разместили элементы отображения, задали им необходимый порядок на экране, давайте снова запустим приложение посмотреть его в двух режимах, в портретном и альбомном.-8

Находится он внутри контейнера activity с атрибутом имени “.MainActivity”. Как мы уже знаем, что всё что находится внутри какого-то контейнера XML, относится именно к этому контейнеру. Следовательно выделенный контейнер intent-filter со всем его содержимым, относится именно к “.MainActivity”. Эти данные как раз и будут сообщать системе Android, что при запуске нужно создать объект класса MainActivity. Вы наверно спросите,- А зачем ему об этом сообщать, если ничего другого больше тут запустить нельзя?- Да, здесь действительно нельзя, но чаще всего можно. Например, вы наверно замечали, что при работе в каком-нибудь приложение вы переходите из одного окна в другое, а потом можете возвратиться назад, затем снова кликаете куда-нибудь, и текущее окно опять сменяется на другое, из которого тоже потом можно вернуться назад. Может показаться, что у нас есть один некий код, который по разным условиям просто отображает на экране новый интерфейс. Так, например, было до изобретения Андроида. Был один огромный код, который отвечал за всю программу что в ней отображается на каждом этапе (картинка входа, начальные настройки, может реклама какая, и т.д.) Пользователь кликал всё время “Далее” или “ОК”, но код был один единый на все. В Андроиде всё не так. Каждое окно принято разделять на отдельный структурный объект приложения, называемый Активити. Весь фокус в том, что когда вы перемещаетесь по приложению и открываются разные окна, это происходит приостановка работы одного Активити и запуск другого, который также помнит с какого другого Активити на него перешли. Потом вы нажимаете на кнопку “Возврат”, текущий Активити закрывается, а предыдущему снова передаётся управление. Например, рекламная заставка перед запуском приложения у многих разработчиков это тоже отдельный Активити. Как раз он и указан в манифесте как запускаемый. Например, у меня манифест приложения “Быки и коровы” выглядит так:

После того как вы разместили элементы отображения, задали им необходимый порядок на экране, давайте снова запустим приложение посмотреть его в двух режимах, в портретном и альбомном.-9

Сначала запускается PreActivity, где оставлена возможность показать рекламное сообщение. Оно несколько секунд его покажет, а затем при помощи специального кода автоматически откроет MainActivity. Класс RulesActivity – это Активити, которые вы тоже будете делать, в нём будут отображаться правила игры, если пользователь захочет их почитать. Вот по этому, возвращаясь к нашему вопросу, зачем указывать какой Активити нужно запускать при старте приложения, и нужно строго указать. Если этого не сделать, система не будет разбираться есть ли ещё какие Активити или их нет, сколько их,- не указали что запускать – вообще не запустит никакой Активити.

Вернемся к коду. Что происходит дальше. Система прочитала файл манифеста, узнала, что для запуска ей нужен класс MainActivity, она создает объект этого класса и вызывает метод этого класса onCreate():

После того как вы разместили элементы отображения, задали им необходимый порядок на экране, давайте снова запустим приложение посмотреть его в двух режимах, в портретном и альбомном.-10

Обратите внимание, что перед началом метода стоит аннотация @Override. Так делается чтобы не запутать компилятор и самому не запутаться. Это слово означает, что мы хотим в этом классе воспроизвести такой же метод, который есть в родительском классе AppCompatActivity или где-то ещё выше по уровню.

Вызов super.onCreate() необходим для правильной инициализации Активити.

Вызов setContentView передаёт Активити наш файл activity_main.xml для того чтобы система проанализировала его и на основании его данных создало интерфейс нашего Активити. Если вы закомментируете эту команду, то после запуска будет просто пустой экран:

После того как вы разместили элементы отображения, задали им необходимый порядок на экране, давайте снова запустим приложение посмотреть его в двух режимах, в портретном и альбомном.-11

По этому пока не будем так делать и вернём как было.

Попробуем теперь как-то получить доступ к нашему интерфейсу программным способом. Напишите следующий код внутрь метода onCreate:

После того как вы разместили элементы отображения, задали им необходимый порядок на экране, давайте снова запустим приложение посмотреть его в двух режимах, в портретном и альбомном.-12

После перезапуска должно получиться вот так:

После того как вы разместили элементы отображения, задали им необходимый порядок на экране, давайте снова запустим приложение посмотреть его в двух режимах, в портретном и альбомном.-13

Как вы поняли, таким образом мы получаем доступ к элементам интерфейса. Функция findViewById() пытается найти по идентификатору элемент нашего Активити. Однако, как я говорил уже на прошлом уроке, все элементы интерфейса – это классы, которые расширяют класс View, или как ещё часто говорят наследует класс. По этому findViewById() возвращает не именно класс, того элемента, который закреплен за этим идентификатором, а их родительский класс. Так делается исходя из рационального подхода, иначе пришлось делать на каждый поиск по ID отдельный метод со своим типом возвращаемого значения. Гораздо проще сделать одну, возвращающую родительский тип класса, а программист сам разберется к какому типу определенного элемента ему привести. Так и происходит в коде выше:

(TextView) findViewById(R.id.textViewNumber)

здесь (TextView) как раз и означает – привести к типу класса TextView. Это нам нужно для того чтобы мы смогли выполнить следующий метод setText(), применимый уже к объекту TextView, который устанавливает нужный текст. Т.е. у класса View нет такого метода, например, нельзя установить текст на контейнер ConstraintLayout, т.к. я говорил, что этот контейнер ничего не отображает, а просто расставляет элементы в нужном порядке; при этом он тоже наследуется от View. Иными словами, компилятор не даст нам сделать вот так:

Красная надпись говорит, что в таком виде скомпилирован код не будет, это ошибка

Красная надпись говорит, что в таком виде скомпилирован код не будет, это ошибка

Если вы неправильно укажите приводимый тип, то скорее всего это вызовет ошибку выполнения уже во время выполнения этого кода в приложении (про ошибку выполнения я так же писал в статье о программировании с нуля).

Ошибка выполнения может также произойти, если findViewById не нашёл такой идентификатор в вашем файле activity_main.xml (тогда результат будет null), например, если такой же идентификатор был в файле другого Активити. Да, компилятор не анализирует, откуда вы тянете этот идентификатор, из этого Активити или другого, всё дело в том, что никто не запрещает менять интерфейс “на ходу”, по этому что вы делаете находится на вашей совести. Подсунуть вообще нигде несуществующий идентификатор не получится, Студио это хорошо отследит:

После того как вы разместили элементы отображения, задали им необходимый порядок на экране, давайте снова запустим приложение посмотреть его в двух режимах, в портретном и альбомном.-15

С текстовым полем и некоторыми особенностями немного разобрались. Теперь давайте посмотрим, как нам отработать нажатие на кнопки 0-9, чтобы нужные цифры появлялись в текстовом поле. С этим немного сложнее, но тоже разберёмся, это основы без которых нельзя:

Кнопки мы обозначали идентификаторами textView0…textView9. И вот следующее, если вы делали как я, и для кнопок использовали тоже TextView, то тогда получить объект кнопки вам нужно абсолютно аналогичным путём, например:

(TextView) findViewById(R.id.textView0)

Если же вы пошли своим путём и использовали для кнопок класс Button, то…правильно – нужно просто поменять приводимый вид:

(Button) findViewById(R.id.textView0)

Теперь нужно это всё заключить в отдельные круглые скобки чтобы сказать, что дальше мы будем обращаться не объекту View, который даёт findViewById, а к объекту TextView / Button, например:

((TextView) findViewById(R.id.textView0))

а вот теперь вызываем для этого приведенного класса вот такой метод:

((TextView) findViewById(R.id.textView0)).setOnClickListener(this);

Этот метод есть как и у TextView, так и у Button, и вообще он есть у родительского View, по тому является наследованным у всех элементов интерфейса. В данном примере, этот метод сообщает элементу textView0 (наша кнопка с цифрой “0”), что теперь это не просто элемент-кнопка с текстом “0”, а элемент, который будет отслеживать, не кликнул ли кто по нему пальцем, и если это так, то передать управление в этот наш Активити (ключевое слова this). По этому как только мы добавим этот метод, компилятор нас любезно попросит указать реализацию метода, который и примет на себя нажатие кнопки, а иначе будет проблема с компиляцией:

После того как вы разместили элементы отображения, задали им необходимый порядок на экране, давайте снова запустим приложение посмотреть его в двух режимах, в портретном и альбомном.-16

Слева видим, что появилась кнопка с выпадающим списком, в котором предлагается несколько решений проблемы. Нас интересует тот, который предлагает организовать реализацию требуемого метода. Далее среда разработки предложит более подробно пояснить реализацию чего мы хотим организовать. Тут обычно курсор сразу стоит там, где надо и остаётся только нажать ОК:

После того как вы разместили элементы отображения, задали им необходимый порядок на экране, давайте снова запустим приложение посмотреть его в двух режимах, в портретном и альбомном.-17

Кликнув на ОК, автоматически получим некоторые изменения в коде, но теперь появилась другая проблема, которую также можно решить автоматически:

После того как вы разместили элементы отображения, задали им необходимый порядок на экране, давайте снова запустим приложение посмотреть его в двух режимах, в портретном и альбомном.-18

Эта проблема говорит о том, что как бы ты – программист, решил реализовать интерфейс (это не тот интерфейс, который мы видим, это термин такой же, но смысл у него совершенно другой, это вносит небольшую путаницу, далее поясню) View.OnClickListener. Но для реализации нужно теперь выбрать методы этого интерфейса, которые ты хочешь прямо сейчас реализовать. Ни завтра, ни послезавтра, ни когда чаю попьёшь в раздумьях, а именно прямо сейчас, но реализовать их всех придётся по любому, теперь без этого никак. Благо что у этого интерфейса View.OnClickListener только один метод, требуемый для реализации:

После того как вы разместили элементы отображения, задали им необходимый порядок на экране, давайте снова запустим приложение посмотреть его в двух режимах, в портретном и альбомном.-19

Да, верно! Опять такое же окно. Океем и его тоже и опять наблюдаем автоматическое изменение кода:

После того как вы разместили элементы отображения, задали им необходимый порядок на экране, давайте снова запустим приложение посмотреть его в двух режимах, в портретном и альбомном.-20

В коде появился новый метод и все предупреждения об ошибках исчезли. Теперь рассказываю что всё это означает и что конкретно мы сделали.

Пока мы не стали вызывать метод setOnClickListener с параметром this, всё было хорошо. Но после его вызова мы сказали среде разработки следующую фразу:

Среда разработки, я знаю, что элемент экрана textView0 может отслеживать нажатие на него пальцем пользователя и вызывать метод onClick(). Сделай так, чтобы этот метод вызывался не просто где-то там внутри этой кнопки textView0, а ещё и вызывался у меня в моём классе тоже…ну заодно, не жалко же тебе?! У себя вызывал, сделал что-то, ну и мне тоже передай, я у себя тоже сделаю чего-нибудь теперь.

Такой подход называется имплементаций или по-русски – реализацией методов. Это работает только по тому, что когда разработчики Андроид делали классы TextView, Button и ещё много других, то они заранее предусмотрели, что программисту делающему приложение, явно понадобится по нажатию на эти элементы выполнять какие-нибудь полезные действия. Но программисты Андроида конечно же не могли знать заранее что это будут за действия у каждого программиста, по этому сделали лазейку и сказали, вот вам метод onClick(), если хотите, я буду его вызывать для вас после нажатия, но как вы будете использовать его, решайте сами в своём коде.

Интерфейсом в имплементации называется специальная конструкция кода, которую программисты класса View объявили в своём коде; как её делать я опять-таки буду рассказывать немного позже, когда наглядно смогу продемонстрировать его эффективность.

Возможно вы спросите, а почему система разработки сразу не создала все реализации на все элементы? Функцию onCreate она же создала сама, так почему на другие не сделала. Ответ прост – это не рационально. Зачем, например, мне отслеживать нажатие на надпись “МОИ ХОДЫ” или на текстовое поле с введенным числом..и самое главное – интерфейс View.OnClickListener не единственный у элементов. Элементы могут отслеживать не только событие нажатие на него пальцем. Есть событие длинного нажатия пальцем, у полей ввода есть события изменения текста, событие непосредственно перед изменением текста, есть события у списков, у скроллов, когда пролистывается экран, их сотни. Представляете как был бы загружен мусором код, сколько было бы в нем объявлено методов, которые в большинстве мы бы даже и не думали реализовывать и были бы нам не нужны.

Давайте вернёмся к коду. Перенесите теперь код отображения числа “1234” следующим образом:

После того как вы разместили элементы отображения, задали им необходимый порядок на экране, давайте снова запустим приложение посмотреть его в двух режимах, в портретном и альбомном.-21

Теперь перезапустите приложение. Число 1234 на экране не отобразилось. Теперь кликните мышкой в виртуальном устройстве по кнопке “0”. Теперь это число появилось только после нажатия на кнопку. На этом примере мы теперь можем понять как происходит взаимодействие в пользовательском интерфейсе – пользователь что-т нажимает, автоматически запускается определенный метод, мы его отрабатывает, возможно что-то отображаем на экране и т.д.

Для того чтобы все кнопки начали реагировать на нажатие, нужно у каждой вызвать метод setOnClickListener(this), однако реализация метода будет по прежнему одна, вам нужно будет только правильно определить какая именно нажата кнопка. Делается это вот по такому принципу:

После того как вы разместили элементы отображения, задали им необходимый порядок на экране, давайте снова запустим приложение посмотреть его в двух режимах, в портретном и альбомном.-22

Т.е. в методе onClick(), когда пользователь нажал на кнопку, определяем идентификатор той кнопки, на которую нажали, а затем командой if сравниваем с теми идентификаторами, которые мы давали этим кнопкам. Таким образом определяем какая же именно кнопка была нажата.

Но нам для нашего проекта потребуется сделать как-то так:

После того как вы разместили элементы отображения, задали им необходимый порядок на экране, давайте снова запустим приложение посмотреть его в двух режимах, в портретном и альбомном.-23

Вы наверно догадались, что такой код при каждом нажатии на кнопки, будет прибавлять справа к строке textNumber очередной символ с цифрой числа, а затем отображать его в поле textViewNumber. Обратите внимание как я прибавляю цифру “2”; это упрощённая запись, компилятор так позволяет делать. Обратите ещё внимание на то, что хотя мы в нашей игре говорим “загадать число”, по факту, мы работаем не с числом, а со строками, содержащими цифры. Это принципиальный факт.

Задание по уроку:

1. Добавьте код для обработки нажатия для всех кнопок

2. Самостоятельно найти в поисковых системах, как в Java Android уменьшить строку на один символ (стереть один символ справа), как узнать длину строки, как взять символ из середины строки, например, взять второй символ из строки, узнайте как правильно сравнить одну строку с другой.

Если всё получилось как нужно – молодцы! Если нет, давайте разберёмся что не так.

Урок 3

El Vinto, 2023 (Copyright)

Java Android. Урок 5 (“Второй код”)

На прошлом уроке вы сделали обработку нажатия пользователем на кнопку для каждой кнопки пользовательского интерфейса. Однако, код стал быстро расти в объёме. Давайте посмотрим вот на что:

На прошлом уроке вы сделали обработку нажатия пользователем на кнопку для каждой кнопки пользовательского интерфейса. Однако, код стал быстро расти в объёме.

Кто читал мою статью о программировании с нуля (Часть 1), то помнит, что обычно принято повторяющиеся команды помещать внутрь цикла. Это делает код рациональным и более близким к восприятию (программист, читающий код, будет понимать, что внутри цикла всё тоже самое, только как-то зависит от самого цикла). В нашем примере (а у вас должна быть уже написана обработка на каждую клавишу), мы должны объявить инициализацию реализации нажатия на каждую кнопку. Давайте теперь мы попробуем сделать так. Сначала создадим массив целых чисел и сразу же заполним его значениями:

На прошлом уроке вы сделали обработку нажатия пользователем на кнопку для каждой кнопки пользовательского интерфейса. Однако, код стал быстро расти в объёме.-2

Т.е. мы просто в массив перенесли идентификаторы всех наших цифровых(!) кнопок. Обратите внимание, что идентификатор – это целое число (иначе бы среда разработки начала “ругаться”).

Теперь внутри onCreate() поменяйте код инициализации на такой:

На прошлом уроке вы сделали обработку нажатия пользователем на кнопку для каждой кнопки пользовательского интерфейса. Однако, код стал быстро расти в объёме.-3

Согласитесь, так выглядит намного компактнее. Почему я не внёс три служебные кнопки в массив, по аналогии, будет понятно далее.

Теперь, конечно, хотело бы также оптимизировать и обработку нажатия. И тут появляется несколько возможных решений. Если бы у нас массив содержал сразу соответствие с цифрой числа и содержал бы только кнопки цифр 0-9 мы могли бы как-то это представить циклом. Можно конечно расписать каждую кнопку отдельно. Я так тоже часто делаю, чтобы легко было искать нужное с точки зрения программирования. Хотя если проявить творчество, то можно сделать и по третьему варианту, давайте его рассмотрим (но все варианты одинаково возможны); заодно сразу сделаем заготовки для служебных кнопок:

На прошлом уроке вы сделали обработку нажатия пользователем на кнопку для каждой кнопки пользовательского интерфейса. Однако, код стал быстро расти в объёме.-4

Рассмотрим какие изменения произошли. Первое, что мы сделали – это вынесли получение идентификатора кнопки в отдельную переменную id. Благодаря этому вызов функции getId() будет происходить только один раз. Это мы оптимизировали с точки зрения скорости выполнения. Далее определяем, если переменная textNumber, которая накапливает нажатия на цифровые кнопки, по длине меньше 4, то можно добавить ещё одну, ведь по правилам игрок должен загадать именно 4-х значное число. Далее запускаем цикл, в котором перебираем весь массив идентификаторов наших кнопок и сравнивает, идентификатор нажатой кнопки не равен ли идентификатору из массива. Если это так, то прибавим к textNumber индекс элемента массива.

Тут хочу обратить внимание вот на что – индексы массивов считаются от нуля (самый первый элемент массива с индексом ноль), и значения этого массива – это идентификаторы элементов наших кнопок тоже от кнопки с цифрой ноль. По этому значение идентификаторов цифровых кнопок, соответствует индексу массива. По этому-то и в сам массив мы отправили только цифровые кнопки, и не стали мешать служебные кнопки. В теории, конечно можно было бы сделать так:

На прошлом уроке вы сделали обработку нажатия пользователем на кнопку для каждой кнопки пользовательского интерфейса. Однако, код стал быстро расти в объёме.-5

Однако, это очень плохой вариант. Мы бы стали строить идеологию проекта исходя из того, что массив кроме цифровых содержит и другие кнопки, а потом, по прошествии какого-то времени, забыли бы, что мы должны использовать первые 10 элементов только(!) для цифровых кнопок и сделали бы, например, вот так:

На прошлом уроке вы сделали обработку нажатия пользователем на кнопку для каждой кнопки пользовательского интерфейса. Однако, код стал быстро расти в объёме.-6

По этому будем делать так, чтобы исключить из программирования пагубные привычки. Дело в том, что если это интерфейс пользователя, то ошибку такую мы сразу найдём (у нас по цифре ноль начнёт появляться на экране единица, а по единице – двойка). А вот если это какой-то другой массив, который например формирует какие-то расчетные данные, то заметить это можно будет только по прошествии многих часов поиска проблемы, ну или например, когда…Луна-XX вдруг полетит по другой траектории и накроет труд тысяч людей медным тазом…

Идем по анализу кода далее. Внимательный слушатель курса заметит один момент. У нас индекс массива – это целое число, а переменная textNumber – это строка, но при этом я делаю так:

На прошлом уроке вы сделали обработку нажатия пользователем на кнопку для каждой кнопки пользовательского интерфейса. Однако, код стал быстро расти в объёме.-7

Да, компилятор позволяет так делать, хотя по всем канонам вообще правильным было бы так:

На прошлом уроке вы сделали обработку нажатия пользователем на кнопку для каждой кнопки пользовательского интерфейса. Однако, код стал быстро расти в объёме.-8

Но такое делать компилятор умеет не всегда правильно. Например, если вы сделаете как-то так:

На прошлом уроке вы сделали обработку нажатия пользователем на кнопку для каждой кнопки пользовательского интерфейса. Однако, код стал быстро расти в объёме.-9

это приведёт к крэшу приложения (остановка работы по фатальной ошибке с принудительным выходом из приложения) . Вся проблема тут была в том, что компилятор подумал, что в качестве целочисленного значения вы передаёте ему не число 34, а идентификатор ресурса (кто разобрался как делать домашнее задание одного из прошлых уроков, понял о чём это я), который как раз тоже является целым числом. Поскольку идентификатора ресурса с ID=34 в приложении не существует, это вызвало ошибку выполнения. Т.е. вот следующий код прошел бы на “Ура!”:

На прошлом уроке вы сделали обработку нажатия пользователем на кнопку для каждой кнопки пользовательского интерфейса. Однако, код стал быстро расти в объёме.-10

Так, слишком отвлеклись…В нашем примере textNumber += i компилятор понял, что мы конечно же хотим именно число привести к типу String (просто здесь наиболее вероятным было бы ожидать от программиста, что он поставит сюда именно число, а не идентификатор ресурса, потому разработчики компилятора и сделали так), а потом произвести конкатенацию (сложение строк, когда к одной строке присоединяется другая строка справа или слева).

Если условие поиска цифровой кнопки отработало, то значит нажата была именно цифровая кнопка, мы выполнили конкатенацию, теперь должны обновить на экране пользователя это число и выйти из метода (больше там сравнивать вообще не чего).

Если пользователь нажал кнопку Backspace (стереть последний символ), т.е. кнопку с идентификатором textViewBackspace и при этом текущая длина строки больше нуля (ну, когда там вообще есть что стирать), то выполняем выражение, которое стирает последний символ строки. Кто по честному выполняет домашние задания, уже знает, что функция substring() получает часть строки. В качестве первого параметра указывается позиция в строке, с которой нужно взять эту часть, а в качестве второго параметра указывается позиция до которой взять (НЕ включительно).

Теперь измените значение по-умолчанию для поля (кто этого ещё не сделал):

На прошлом уроке вы сделали обработку нажатия пользователем на кнопку для каждой кнопки пользовательского интерфейса. Однако, код стал быстро расти в объёме.-11

и перезапустите приложение. Проверьте ввод цифр и возможность их стирания. Всё должно работать.

Что мне не особо нравится в работе этого кода, так это отображение знаков “_”. Сначала они есть и это смотрится красиво, но по мере набора и стирания они пропадают, а по идее хорошо бы, если они выглядели как-то так (да и хорошо бы введенные цифры блокировались, а при стирании разблокировались):

На прошлом уроке вы сделали обработку нажатия пользователем на кнопку для каждой кнопки пользовательского интерфейса. Однако, код стал быстро расти в объёме.-12

Для начала немного изменим код обработки нажатия:

На прошлом уроке вы сделали обработку нажатия пользователем на кнопку для каждой кнопки пользовательского интерфейса. Однако, код стал быстро расти в объёме.-13

Тут среда разработки начнёт подсказывать, типа “А что это такая за странная функция? Я её не знаю”. Конечно же не знает, мы её ещё только сейчас начнём писать. По этому добавьте её ниже метода onClick() и сделайте её сразу правильно:

На прошлом уроке вы сделали обработку нажатия пользователем на кнопку для каждой кнопки пользовательского интерфейса. Однако, код стал быстро расти в объёме.-14

В этом методе мы должны сначала создать отдельную переменную numberAsText, которая будет хранить число вместе со знаками подчеркивания “_”. Так же сразу выполним цикл, который отметит все кнопки доступными для нажатия setEnabled(true) и укажем для них зеленоватый цвет. Далее выполним цикл от 1 до 4 в котором будем делать следующее. Если индекс цикла больше длины строки введенного уже нами числа, то заполнить это знаком подчеркивания (эти знаки в конце после цифр), в ином случае взять цифру из нашего числа по этому индексу (в виде целого числа) и поместить в эту нашу новую переменную numberAsText, после чего взять по этому числу как по индексу идентификатор элемента пользовательского интерфейса и отметить кнопку как недоступную для нажатия и установить на неё серый цвет фона. Далее выполняется заодно код, который определяет длину строки (длина строки по логике – это как раз число разрядов числа), и если эта длина равна 4, то отобразить кнопку “Enter”, в ином случае скрыть её. Обязательно разберитесь с этой частью кода чтобы хорошо понимать каждое действие, что мы делаем каждым выражением. Обращаю внимание, ранее мы представляли из целого числа строку и компилятор это смог сделать самостоятельно, а вот наоборот из строки сделать число он уже не может, по этому необходимо выполнить соответствующую функцию Integer.parseInt(). Это нужно нам как число, т.к. дальше нам нужно обратиться к элементу массива digButtons, где аргументом не может быть строка.

Мы с вами уже познакомились с некоторыми инициализациями переменных, пора бы теперь поговорить о них немного подробнее. Давайте сначала разберемся какие вообще могут быть переменные.

String a = “”; // это строка, мы уже несколько раз такое делали в нашем коде

int b = 0; // что-то похожее делали буквально только что, когда преобразовывали из строки в целое число

boolean c = false; // Это булева переменная, которая может принимать значение только истина или ложь (true / false)

long d = 123; // длинная целая переменная, позволяет хранить максимальное целое число в два раза большее, чем int.

float e = 12.3; // позволяет хранить нецелые числа (дробная часть отделяется точкой)

double f = 12.34353453; // Позволяет хранить нецелые числа, но в два раза с большей точностью, чем float

ClassVariable g = null; // Переменная, которая хранит ссылку на какой-то класс. Например, вот так:

На прошлом уроке вы сделали обработку нажатия пользователем на кнопку для каждой кнопки пользовательского интерфейса. Однако, код стал быстро расти в объёме.-15

Есть и ещё, но пока этих достаточно.

Теперь пришло время поговорить об области видимости переменных. У нас есть уже переменная textNumber, которую я объявил вне какого-либо метода, но внутри класса:

На прошлом уроке вы сделали обработку нажатия пользователем на кнопку для каждой кнопки пользовательского интерфейса. Однако, код стал быстро расти в объёме.-16

Такая переменная называется переменной класса и видна из любого метода класса (к ней можно обратиться из любого метода, мы так и делаем, то из onClick(), то из setNumber() ).

Есть переменные метода, например int id в методе onClick() или String numberAsText в методе setNumber(). Они видны только из того метода, где объявлены. Т.е. я, например, не могу обратиться к numberAsText из метода onClick(), среда разработки не даст это сделать.

Переменные, которые объявлены внутри объявления цикла видны в этом объявлении и везде внутри этого цикла, снаружи уже не видны. Например, int i в цикле:

for (int i = 0; i < digButtons.length; i++ /* да, тут видна i */) {

/* где-то тут тоже видна i */

}

/* а тут уже i не видна, здесь её использовать не получится */ .

Переменные, которые объявлены внутри условия, видны везде внутри этого условия, например, int num внутри else:

if (i > textNumber.length()) {

/* тут вообще не знает что такое num */

} else {

/* кстати, если что, и тут не известно что такое num */

int num;

/* тут видна num */

}

Идем теперь далее. Перед началом каждого раунда, игра должна сгенерировать 4-х значное случайное число. Это будет то самое число, которое загадал компьютер и которое предстоит узнать человеку в процессе определенного числа попыток. Функционал Java позволяет сгенерировать целое случайное число. Делается это в два этапа. Сначала объявляется переменная класса Random, а затем выполняется один из её методов, отвечающих за генерацию числа в определенном диапазоне:

Random random = new Random();
int rndNum = random.nextInt(10);

В данном примере rndNum будет содержать случайное значение в диапазоне от 0 до 9, т.е. как раз одну случайную цифру. Однако, тут вы возможно воскликните,- Э-э-э, автор, у тебя что-то с математикой не в порядке! Нам надо 4-х разрядное число, а это тогда диапазон не до 10, а до 10 000. )))…Но я наверно сделал так тоже не спроста, наверно потому что задача не так тривиальна. Помимо того, что нам нужно сгенерировать 4-х значное число, нам нужно ещё и чтобы все цифры были в нём разные)). По этому объективных решения здесь минимум два, я просто выбрал одно из них, которое счет наиболее простым в реализации…В домашнем задании попробуйте разные способы.

Иногда возникает ситуация, когда в процессе разработки нужно посмотреть значение какой-либо переменной, но выводить это на экран телефона не всегда удобно – для этого придётся создавать какой-то элемент textView для отображения, а это вносит сумятицу в разработку. По этому разработчиками был придуман метод логгирования. Давайте, например, проверим какие числа будут сгенерированы случайным методом, описанным только что, например, с 10 попыток. Делается это примерно так:

На прошлом уроке вы сделали обработку нажатия пользователем на кнопку для каждой кнопки пользовательского интерфейса. Однако, код стал быстро расти в объёме.-17

Кстати, тут может возникнуть ещё вот такая ситуация:

На прошлом уроке вы сделали обработку нажатия пользователем на кнопку для каждой кнопки пользовательского интерфейса. Однако, код стал быстро расти в объёме.-18

Т.е. среда разработки не находит функцию Log. Наведите на это слово курсор мыши, в результате появится знакомая кнопка решения проблемы:

На прошлом уроке вы сделали обработку нажатия пользователем на кнопку для каждой кнопки пользовательского интерфейса. Однако, код стал быстро расти в объёме.-19

Нужно импортировать класс. Вся проблема тут в том, что изначально в приложение на загружаются весь функционал Андроида, т.е. например, зачем загружать в приложения огромный пласт кода для работе с трехмерной графикой, если вы делаете обычный калькулятор. Также и тут, изначально среда разработки не включила функционал логгирования в ваше приложение, но уж коли вы хотите его использовать, то скажите об этом наверняка. Иногда может получиться так, что библиотека импорта на выбор будет не одна (например, если эта функция с таким именем встречается сразу в нескольких различных библиотеках и выполняет несколько разные по смыслу действия), то в этом случае придётся разбираться и возможно гуглить, откуда же её тянуть. В данном случае, библиотека для импорта только одна: android.util.Log.

Может получиться и ещё одна ситуация, когда при наведении куда-то мышью, вдруг система разработки внезапно очнётся и увидит, что решение есть, но пользовательский контекст другой:

На прошлом уроке вы сделали обработку нажатия пользователем на кнопку для каждой кнопки пользовательского интерфейса. Однако, код стал быстро расти в объёме.-20

Тут спрашивает, мол это из android.util.Log? Тогда жми одновременно на клавиши Alt+Enter!

В действительности, будет добавлена библиотека импорта (в самом верху кода):

На прошлом уроке вы сделали обработку нажатия пользователем на кнопку для каждой кнопки пользовательского интерфейса. Однако, код стал быстро расти в объёме.-21

Перезапускаем приложение, но смотрим не виртуальный мобильник, а на экран разработки. В результате получится вот так:

На прошлом уроке вы сделали обработку нажатия пользователем на кнопку для каждой кнопки пользовательского интерфейса. Однако, код стал быстро расти в объёме.-22

Ещё давайте рассмотрим небольшую конструкцию, которую я использовал, это вот такое выражение:

i++

На самом деле – это упрощённая запись i = i+1 (до этого вы могли и догадаться), т.е. взять переменную i, прибавить к ней 1, а результат снова поместить в переменную i. Например, если до этого выражения в переменной i было значение 4, то после будет значение 5.

Нельзя пройти стороной и похожую конструкцию:

++i

Которая делает абсолютно тоже самое, но только как чесать левой рукой правое ухо.

Сделайте так чтобы посмотреть разницу и перезапустите приложение (мы немного отвлеклись и поиспользуем наше приложение для некоторых тестов):

На прошлом уроке вы сделали обработку нажатия пользователем на кнопку для каждой кнопки пользовательского интерфейса. Однако, код стал быстро расти в объёме.-23

Нет, здесь нет признаков корпускулярно-волнового дуализма, когда присутствие наблюдателя меняет результат. Возможно вы догадались, почему так произошло. Правильно! num1++ прибавило к num1 значение после выполнения всего выражения, которым был в конечном счете вывод лога, а выражение ++num2 сделало инкремент (увеличение на единицу) до того как начало выполнять выражение. В этом и вся разница. Если мы сделаем так:

На прошлом уроке вы сделали обработку нажатия пользователем на кнопку для каждой кнопки пользовательского интерфейса. Однако, код стал быстро расти в объёме.-24

То результат будет абсолютно одинаковый:

На прошлом уроке вы сделали обработку нажатия пользователем на кнопку для каждой кнопки пользовательского интерфейса. Однако, код стал быстро расти в объёме.-25

По этому я часто выношу p++ или ++p за пределы выражения как самостоятельные выражения…но не всегда)). Например, добавлять значения какого-нибудь массива удобно вот так:

ar[i++] = 5;

ar[i++] = 6;

ar[i++] = 7;

А брать значение с последнего вот так:

int len = ar.length;

while (len > 0) {

value = ar[–len];

// …

}

Задание по уроку:

1. Попробуйте самостоятельно сделать метод для генерации 4-х значного числа. Для его хранения сделайте строковую переменную класса compNumber.

2. Сделайте так, чтобы при нажатии на кнопку Enter программа считала число “Быков” в угадываемом числе. Проверьте метод логгирования в разных вариантах.

3. Ответьте, какое значение p будет после выполнения следующих действий, после этого проверьте своё решение при помощи метода логгирования:

p = 3;

p = p+++p;

Если всё получилось как нужно – молодцы! Если нет, давайте разберёмся что не так.

Урок 4 Урок 6

El Vinto, 2023 (Copyright)

Java Android. Урок 6 (“Третий код”)

Вернемся к разработке нашего первого приложения под Андроид. На прошлом уроке мы начали делать функционал (набор исполняемого кода и данных необходимых для выполнения определенных вычислительных операций) генерации числа, которое компьютер по правилом игры должен “загадать”. Напоминаю, нам нужны следующие условия для такого числа:

  • Число должно состоять только из 4-х цифр
  • Все цифры числа должны быть разными

Методов решения этой задачи несколько, по этому нужно просто какой-то выбрать. Заранее скажу как я буду это делать. Сначала я получу 4 цифры числа случайным образом таким образом, чтобы каждое следующее случайное число – значение цифры загадываемого числа, отличалось от уже всех ранее сгенерированных. Это даст выполнение правила, что все цифры числа должны быть разными. С первым условием всё просто, мы просто будем генерировать от 1 до 4-х.

Вернемся к разработке нашего первого приложения под Андроид.

Однако, прежде чем разбираться как же тут получается число со всеми необходимыми условиями, необходимо отвлечься и познакомиться с некоторыми конструкциями кода. В Java есть 3 вида циклов, т.е. конструкций кода, позволяющих несколько раз выполнять один и тот же код (циклическое выполнение).

Первый из них мы уже много раз встречали – это обычный цикл for. В области параметров этого цикла есть три части кода, разделенные точкой с запятой. Первая часть инициализирует переменную (задаёт ей начальное значение), вторая часть проверяет соблюдается ли условие (будет ли результат этого условия равен значению true), третья часть – выражение, которое должно выполняться после каждой итерации (этап прохождения по циклу). Пока значение второй части true, цикл будет совершать итерации (хоть до бесконечности). Давайте это рассмотрим прямо из нашего нового метода:

for (int i = 1; i < 5; i++) {}

Сначала объявляем и инициализируем переменную i значением 1. Во второй части будем сравнивать – значение переменной i для выполнения итерации должно быть меньше 5. В третьей части производим инкремент этой переменной (тема прошлого урока). Таким образом, каждую итерацию i будет увеличиваться на единицу и в конечном итоге достигнет значения 5. Условие i < 5 перестанет выполняться, цикл завершится и управление будет передано первому выражению следующему за циклом (за закрывающей скобкой этого цикла).

Вторая конструкция цикла у нас тоже в этом методе есть и выглядит так:

do {

} while (isNoOk);

Тут цикл начнёт выполняться без всяких условий сразу же, но вот будет ли выполнен повторно определяется условием после завершения этого цикла, что не скажешь о предыдущем, где чтобы начать выполнение цикла (вхождение в цикл) нам требовалось условие i < 5, это же условие требовалось и для продолжения его выполнения. Тут, как понимаете, по логике получается немного по другому. Тут стоит обратить внимание, что если переменная i в цикле for (который ещё иногда называют по-старинке “цикл for…next”) видима как в объявлении цикла, так и внутри него, то в цикле “do…while” нет инициализации, а все используемые там переменный должны быть либо объявлены где-то перед этим циклом, либо иметь более глобальную видимость, например, быть переменными класса (один из прошлых уроков). В связи с этим получается, что переменная isNoOK должна быть объявлена перед этим циклом. Если посмотрите на код метода generateComNumber(), я именно так и сделал. Итак, подытожим. Цикл do…while начинает выполняться без всяких условий и будет выполняться до тех пор, пока значение внутри while будет true, т.е. например, цикл

do { }

while(true);

будет выполняться “вечно” и никогда не завершиться, пока работа приложения не будет прервана извне этого приложения (действиями пользователя или действиями операционной системы). По этому задача программиста сделать так, чтобы внутри этого цикла было что-то, что может поменять условия для выхода из цикла. Для этого я выполняю действия влияющие на это:

do {
num = random.nextInt(10);

isNoOK = compNumber.indexOf(“” + num) > -1;
} while (isNoOK);

Сначала я получаю случайное число num в диапазоне 0…9, затем преобразовываю его в строку и пытаюсь найти в уже сформированной итоговой строке compNumber. Функция indexOf как раз это и делает. Если искомая строка не найдена, результат будет равен минус 1, а если найдена, то позиции искомой строки и строке поиска. Сама позиция нам не нужна, тут нам просто нужно проверить есть ли это в строке. Обратите внимание как я получаю из числа строку. На одном из прошлых уроков я говорил, что иногда компилятор правильно делает такое преобразование если ничего не указывать, но по всем правилам преобразование нужно делать через String.valueOf(). Но есть и ещё метод – это прибавить число к пустой строке:

“”+num

Компилятор видит перед знаком плюс строку (пусть она и пустая) и понимает, что нужно производить конкатенацию строк, а значит число справа скорее всего не какой-то там идентификатор ресурса, а обычное число.

Стоит сразу же сказать и о ещё одном виде цикла, который используется наравне с этими двумя. Это цикл

while(условие) {

}

Он является почти аналогом цикла do…while, но отличается только тем, что для первого вхождения в цикл нужно выполнения условия (для do…while этого не требовалось).

Из любого цикла можно выйти и не дожидаясь пока итерация закончится и наступит момент проверки условий. На примере цикла while делается это примерно так:

while (true) {
if (какое-то условие) {
break;
}

/* ничего этого выполнено не будет, если сработает break */
}
/* сюда будете передано управление после выполнения break */

В этом примере казалось бы условие цикла всегда будет true и цикл будет выполняться “вечно”, но это не так, т.к. внутри цикла встроена конструкция из условия, по истинному результату которой, будет выполнена команда break. Это команда прерывает цикл, выходит из него прямо с этой команды.

ВАЖНО! Команда break выходит только из текущего цикла. Если один цикл вложен в другой, выход будет осуществлён только из текущего цикла, но НЕ(!) из вышестоящего.

Все циклы имеют команду принудительной итерации. Это команда continue. Она работает похоже как break, только не прерывает цикл, а делает так, что цикл переходит на следующую итерацию, конечно же, если условия цикла, требуемые для этого, выполняются:

while (true) {
if (какое-то условие) {
continue;
}

/* ничего этого выполнено не будет, если сработает continue */
}
/* в данном примере здесь никогда управление не окажется, т.к. нет ничего чтобы прервало цикл. Это “вечный” цикл */

В следующем примере:

Вернемся к разработке нашего первого приложения под Андроид.-2

Цикл станет “вечным”, т.к. выход по break будет только из внутреннего цикла, но внешний продолжит выполнение. Это касается циклов всех типов.

Теперь, основываясь на наших новых знаниях о циклах, рассмотрим более подробно мой метод генерации числа. Сначала я объявил экземпляр класса Random и поместил его в переменную random. Этот класс позволяет программисту работать с генератором случайных чисел. Далее следует сброс compNumber – это строкова переменная класса, которую вы должны были добавить в домашнем задании. Далее делаем цикл от 1 до 4, а внутрь этого цикла помещаем ещё один, который будет выполняться до тех пор, пока не сгенерирует цифру числа, которой ещё нет в загадываемом числе. Когда функционал находит такую цифру, он конкатенирует её к compNumber и процесс повторяется 4 раза. Таким образом, в результате будет необходимое число. Посмотрите внимательно каждую команду этого метода generateComNumber(). Вы должны хорошо понимать какое действие будет выполняться в каждом выражении. Попробуйте мысленно или на бумаге воспроизвести как будет меняться значение compNumber при каждой итерации каждого цикла; мысленно воспроизведите как будет осуществляться вхождение в цикл do…while и выход из него при каких словиях.

Сделайте теперь так, чтобы этот метод запускался сразу при загрузке приложения, т.к. именно в этот момент игра уже должна быть готова принять первый вариант пользователя, желающего угадать число (чтобы было что отгадывать):

Вернемся к разработке нашего первого приложения под Андроид.-3

Теперь осталось дело за малым – при вводе варианта пользователя просто посчитать число быков и коров, и если количество быков равно 4, то значит пользователь отгадал число, в ином случае сказать пользователю каков результат его попытки.

Для начала напишем две эти функции, одна будет находить число быков, а вторая – число коров.

Вернемся к разработке нашего первого приложения под Андроид.-4

В домашнем задании вы должны были хорошо познакомиться с функцией substring() и что она делает в этом функционале, вы наверно уже поняли. Да, одна функция берет один символ из строки по индексу i из строки textNumber, другая тоже самое из строки compNumber. Первая переменная содержит число, которое ввел пользователь, а второе – которое “загадал” компьютер. Обратите внимание как происходит сравнение двух строк:

Строка1.equals(Строка2)

значение выражения истина, если Строка1 содержит тот же набор символов в той же последовательности, что и Строка2. В данном случае строки содержат по одному символу.

При расчете коров потребовалось выполнить цикл в цикле для того чтобы исключить из подсчета количество быков, которые бы неминуемо туда тоже попали, а по правилам игры корова – это совпадающая цифра числа находящаяся в другом разряде, но не в том же.

Очень внимательно посмотрите функцию подсчета коров. Вам должны быть понятно все от начала и до конца что там происходит. Если что-то оказывается неясным, лучше задать вопрос и разобраться в этом сейчас.

Осталось теперь только выполнить проверку после ввода числа, по этому допишите код для обработки события нажатия на соответствующую кнопку:

Вернемся к разработке нашего первого приложения под Андроид.-5

Проверьте выполнение кода, должно получиться как-то так:

Вернемся к разработке нашего первого приложения под Андроид.-6

Обратите внимание на всплывающее сообщение Toast. Как правильно его использовать в коде и какой будет результат. Такие сообщения вы наверно иногда встречаете в приложениях, когда на несколько секунд появляется информация поверх экрана, а потом сама исчезает. Для тестирования в данном случае такое подойти может, а вот для нашего игрового процесса нет. Нам нужно чтобы каждый вариант с результатом хранился в списке, и мы всегда могли посмотреть его, проанализировать и принять решение для следующего хода. Однако, список требует свежего восприятия, по этому начнём им заниматься на следующем уроке.

Задание по уроку:

1. Ответьте на вопрос, в функции подсчета коров сколько раз будет выполнена проверка условия “if (number.substring…”?

2. Чему будет равна сумма p+q после выполнения следующего кода:

Вернемся к разработке нашего первого приложения под Андроид.-7

3. Самостоятельно разберитесь с тем, как правильно сделать выход из двух вложенных циклов, если во внутреннем цикле наступает такое требование.

Если всё получилось как нужно – молодцы! Если нет, давайте разберёмся что не так.

Урок 5 Урок 7

El Vinto, 2023 (Copyright)