[Программирование, Java, Разработка мобильных приложений, Разработка под Android] Как написать простое Android ToDo-приложение на Java
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
ПредисловиеЯ не являюсь профессиональным разработчиком с огромным стажем в данной области (и это даже не хобби, а лишь нужда в разработке конкретного приложения), потому данная статья, полагаю, будет полезна новичкам, таким же, как и я был в начале разработке своего приложения. Возможно, кто-то найдет что-то полезное из данной статьи, какие-то кусочки окажутся частью ваших будущих разработок.Я расскажу вам как написать простенькое ToDo-приложение на Android с тремя активностями (рабочими экранами).Ссылка на проект на Github будет в конце данной статьи.Установка и первичная настройкаДля разработки приложения я рассмотрю использование бесплатной IDE Intellij от разработчиков JetBrains - Android Studio, у меня версия 4.1.1.После успешной установки IDE и запуска нажимаем на самую первую кнопку Start a new Android Studio Project. Далее появится мастер первичной подготовки проекта:
- выберем подходящий шаблон, в моем случае это Empty Activity - он самый простой для новичков, так как при первом запуске будет всего 1 XML файл с версткой и один java файл MainActivity.
- На следующем экране придумываем имя приложению; помните, что package name, после публикации на Google Play изменить нельзя (иначе Google Play посчитает это другим приложением (поправьте меня, если я ошибаюсь). Выбираем язык Java, так как по нему данная статья, а также, по нему больше информации в Интернете, чем по Kotlin.
- Минимальный SDK выбираем под Android 5.0, так как данного API будет предостаточно для наших задач, заодно мы получим большой охват, в том числе старых устройств: планшеты, смартфоны, встроенные системы.
Скриншоты: установка и первичная настройка
Далее раскрываем вкладку Project и находим в каталоге Java><Ваш_Проект> файл MainActivity.java, в котором мы будем описывать все происходящее на главном экране.Подготовка макетов (layouts) - внешний облик приложенияПосле рассмотрим файл MainActivity.xml, для этого нам нужно найти каталог res>layout>. Откроем MainActivity.xml для создания облика первой - главной страницы и перетягивая с панели Palette необходимые нам типы объектов.Советую вам размещать объекты под ConstraintLayout, так объекты можно будет привязывать узелками к родительскому ConstraintLayout, который по умолчанию занимает всю пространство, а после привязки узелков, мы можем размещать объекты на нужном нам вертикальном и горизонтальном выравнивании. Кстати, вместо px, тут используется другая величина - dp, позволяющая на разных экранах видеть одинаковый и желаемый результат.
Кстати, также, советую названия Текст полей переназначать в String значения, чтобы в дальнейшем было проще делать перевод интерфейса - подобный функционал уже встроен в Android Studio. Для этого нажимаем на объект, далее в меню Свойств объекта находим поле text и нажимаем на маленькую плашку-кнопку справа от текста. В открывшимся окне, нажимаем на плюсик слева сверху и создаем название String-переменной и ее значение по умолчанию:
Создание String-переменнойДля перевода интерфейса, необходимо сохранить изменения и над нашим конструктором Layout нажать на кнопку Default (en-us) и выбрать Edit Translations, далее найти слева сверху значок глобуса и нажать на него для добавления нового языка:
Переводы для интерфейсовТаким образом создадим дополнительные макеты (layouts) для оставшихся двух окон:Скриншоты: еще два макета
Макет Activity_Settings.xml
Макет Activity_Advanced.xmlПрограммируем на Java под AndroidЕще раз повторюсь, что это Tutorial больше для новичков; дальше я буду комментировать практически каждую строчку. Ссылка на проект на Github будет в конце данной статьи.Открываем файл Main_Activity.java, который будет отвечать за логику наших переключателей и главного экрана в целом, а она такова:
- В самом верху должен отображаться пользовательский заголовок, если он настроен.
- На переключателях должен отображаться тот текст, который пользователь настраивает из окна с макетом Activity_Settings.xml
- Количество переключателей должно соответствовать заданному числу из окна макета Activity_Advanced.xml
- После выхода из приложения и повторного запуска все переключатели должны оставаться в том же положении, в котором пользователь их оставил
- Сброс переключателей возможен только, если переключатель Уверен/-а? включен.
- А также, должны работать оставшиеся кнопки меню.
Пишем следующее:
Код под спойлером: 156 строчек
package com.bb.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.SwitchCompat;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
//Создаем 9 переключателей с помощью массива
SwitchCompat[] switcharray = new SwitchCompat[9];
Boolean Reset; //Булев для выключения переключателя
Button NextButton;
public int[] list_of_switches = {
R.id.switch_compat1,
R.id.switch_compat2,
R.id.switch_compat3,
R.id.switch_compat4,
R.id.switch_compat5,
R.id.switch_compat6,
R.id.switch_compat7,
R.id.switch_compat8,
R.id.switch_compat10, //переключатель "Вы уверены?" //8
};
//Нажатие кнопки Сброс
public void ResetButtonClick (View view) throws IllegalAccessException {
Reset =false;
if (switcharray[8].isChecked()) { //Если переключатель "Вы уверены?" нажат, то разрешаем переключить в false остальные переключатели
SharedPreferences.Editor editor = getSharedPreferences("save"
,MODE_PRIVATE).edit();
//Сохраняем в Intent значения всех переключателей в False
for (int k=0; k<10; k++) {
editor.putBoolean("value"+k, false);
}
editor.apply();
//Устанавливаем все переключатели в значение False
for (int i=0;i<9;i++){
switcharray[i].setChecked(false);
}
//Reset background color of checked SwitchCompats
for (int i = 0; i < 9; i++) {
findViewById(list_of_switches[i]).setBackgroundColor(Color.TRANSPARENT);
}
}
}
//Создание формы / открытие приложения
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Назначаем полям значения по умолчанию и сохраняем их в Intent
String[] tsfield = new String[8];
SharedPreferences prefs = getSharedPreferences("MY_DATA", MODE_PRIVATE);
tsfield[0] = prefs.getString("KEY_F0", "Выключил газ");
tsfield[1] = prefs.getString("KEY_F1", "Выключил воду");
tsfield[2] = prefs.getString("KEY_F2", "Покормил кошек");
tsfield[3] = prefs.getString("KEY_F3", "Закрыл окна");
tsfield[4] = prefs.getString("KEY_F4", "Выключил Интернет");
tsfield[5] = prefs.getString("KEY_F5", "Закрыл дверь");
tsfield[6] = prefs.getString("KEY_F6", "Выключил везде свет");
tsfield[7] = prefs.getString("KEY_F7", "Вынес мусор");
//Получаем настройки текста заголовка
String hellotext = prefs.getString("hellotitletext", "");
switcharray[6] = findViewById(list_of_switches[6]);
switcharray[7] = findViewById(list_of_switches[7]);
//Получаем настройки количества полей
String sixfields = prefs.getString("sixfields", "true");
String sevenfields = prefs.getString("sevenfields", "false");
String eightfields = prefs.getString("eightfields", "false");
if (sixfields.equals("true")){
switcharray[6].setVisibility(View.GONE);
switcharray[7].setVisibility(View.GONE);
}
else if (sevenfields.equals("true")) {
switcharray[6].setVisibility(View.VISIBLE);
switcharray[7].setVisibility(View.GONE);
}
else if (eightfields.equals("true")) {
switcharray[6].setVisibility(View.VISIBLE);
switcharray[7].setVisibility(View.VISIBLE);
}
//Создаем массив из TextView
TextView[] textarr = new TextView[8];
//Каждому переключателю назначаем текст из итерации поля tsfield
for (int i=0; i<8;i++){
textarr[i] = (TextView) findViewById(list_of_switches[i]);
textarr[i].setText(tsfield[i]);
}
//Назначаем текст заголовка
TextView textView5 = (TextView) findViewById(R.id.textView5);
textView5.setText(hellotext);
//Отображать заголовок, если соотв. поле заполнено
if(!hellotext.matches(""))
{
textView5.setVisibility(View.VISIBLE);
}
//Создаем связь каждого элемента переключателя по id из XML с соответствующей переменной типа SwitchCompat
for (int i=0;i<9;i++) {
switcharray[i] = findViewById(list_of_switches[i]);
}
//Создаем связь кнопки по id bt_next из xml переменной NextButton
NextButton = findViewById(R.id.bt_next);
//Используем SharedPreferences = "save"
SharedPreferences sharedPreferences = getSharedPreferences("save"
, MODE_PRIVATE);
//При первом запуске - все переключатели в False
for (int k=0; k<9; k++) {
switcharray[k].setChecked(sharedPreferences.getBoolean("value"+k, false));
}
//При переключении переключателей сохраняем данные, а также, проверяем их при повторном запуске
for (int k=0; k<9; k++) {
final int finalK = k;
switcharray[k].setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (switcharray[finalK].isChecked()) {
//когда переключатель включен
Reset = true; //
switcharray[finalK].setBackgroundColor(Color.parseColor("#c8a2c6"));
SharedPreferences.Editor editor = getSharedPreferences("save"
, MODE_PRIVATE).edit();
editor.putBoolean("value" + finalK, true);
editor.apply();
switcharray[finalK].setChecked(true);
} else {
//когда переключатель выключен
SharedPreferences.Editor editor = getSharedPreferences("save"
, MODE_PRIVATE).edit();
editor.putBoolean("value" + finalK, false);
Reset = false;
switcharray[finalK].setBackgroundColor(Color.TRANSPARENT);
editor.apply();
switcharray[finalK].setChecked(false);
}
}
});
}
//Кнопка открытия страницы настроек
NextButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//Go to next activity
Intent intent2 = new Intent(MainActivity.this, Activity_settings.class);
startActivity(intent2);
}
});
}
}
Следующим этапом будет написание кода для корректной работы макета Activity_Settings.XML, а логика его такова:
- Введенные пользователь записи сохраняются даже после перезапуска приложения
- Количество полей соответствуют числу, заданному в настройках из макета Activity_Advanced.xml
- А также, должны работать оставшиеся кнопки меню.
Код по спойлером: 124 строчки
package com.bb.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class Activity_settings extends AppCompatActivity {
//Initialize Variable
Button btBack;
Button fcSubmit;
Button btAdvanced;
//Ассоциируем поля ввода с переменными с помощью массива
EditText[] InputFields = new EditText[8];
//Назначаем полям значения по умолчанию и сохраняем их в Intent
String[] tsfield = new String[8];
//Создаем массив элементов из XML по id
public int[] list_of_fields = {
R.id.inputField0,
R.id.inputField1,
R.id.inputField2,
R.id.inputField3,
R.id.inputField4,
R.id.inputField5,
R.id.inputField6,
R.id.inputField7,
};
private SharedPreferences prefs;
//Создание формы / открытие приложения
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
//Назначаем полям значения по умолчанию и сохраняем их в Intent
prefs = getSharedPreferences("MY_DATA", MODE_PRIVATE);
//Получаем данные по количеству используемых полей
String sixfields = prefs.getString("sixfields", "true");
String sevenfields = prefs.getString("sevenfields", "false");
String eightfields = prefs.getString("eightfields", "false");
EditText inputField71var = (EditText) findViewById(list_of_fields[6]);
EditText inputField81var = (EditText) findViewById(list_of_fields[7]);
if (sixfields.equals("true")){
inputField71var.setVisibility(View.INVISIBLE);
inputField81var.setVisibility(View.INVISIBLE);
}
else if (sevenfields.equals("true")) {
inputField71var.setVisibility(View.VISIBLE);
inputField81var.setVisibility(View.INVISIBLE);
}
else if (eightfields.equals("true")) {
inputField71var.setVisibility(View.VISIBLE);
inputField81var.setVisibility(View.VISIBLE);
}
tsfield[0] = prefs.getString("KEY_F0", "Выключил газ");
tsfield[1] = prefs.getString("KEY_F1", "Выключил воду");
tsfield[2] = prefs.getString("KEY_F2", "Покормил кошек");
tsfield[3] = prefs.getString("KEY_F3", "Закрыл окна");
tsfield[4] = prefs.getString("KEY_F4", "Выключил Интернет");
tsfield[5] = prefs.getString("KEY_F5", "Закрыл дверь");
tsfield[6] = prefs.getString("KEY_F6", "Выключил везде свет");
tsfield[7] = prefs.getString("KEY_F7", "Вынес мусор");
//Назначаем полям ввода текст из SharedPreferences
for (int i=0; i<8; i++) {
InputFields[i] = (EditText) findViewById(list_of_fields[i]);
InputFields[i].setText(tsfield[i]);
}
//Создаем переменные для кнопок
btBack = findViewById(R.id.bt_back);
fcSubmit = findViewById(R.id.submit_fc);
btAdvanced = findViewById(R.id.btAdvanced);
//Кнопка Назад
btBack.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//Go back
Intent intent = new Intent (
Activity_settings.this,MainActivity.class
);
startActivity(intent);
}
});
//Кнопка Расширенные настройки/Дополнительно
btAdvanced.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//Open Advanced Settings
Intent intent = new Intent (
Activity_settings.this,Activity_advanced.class
);
startActivity(intent);
}
});
}
//Ссылка-значок на внешний ресурс - ссылка на мой телеграм
public void tglink(View view){
Intent myWebLink = new Intent(android.content.Intent.ACTION_VIEW);
myWebLink.setData(Uri.parse("https://t.me/EndlessNights"));
startActivity(myWebLink);
}
//Кнопка Сохранить данные
public void SaveData(View view)
{
for (int i=0; i<8;i++) {
tsfield[i] = InputFields[i].getText().toString();
SharedPreferences.Editor editor = prefs.edit();
editor.putString("KEY_F"+i, tsfield[i]);
editor.apply();
}
// Открываем главную страницу
startActivity(new Intent(getApplicationContext(), MainActivity.class));
}
}
И наконец опишем логику работы последнего окна в приложении - с Дополнительными настройками:
- Количество полей для отображения - в данном случае выбор с помощью радиокнопок - 6, 7 или 8 полей.
- Текстовый заголовок, который пользователь может ввести и который будет отображаться на главной странице/активности.
- Также, текстовый заголовок и выбранное количество полей с помощью радиокнопок должны сохранять свое состояние даже после перезапуска приложения.
- И наконец должны работать оставшиеся кнопки меню.
Код под спойлером: 134 строчки
package com.bb.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Switch;
import android.widget.TextView;
public class Activity_advanced extends AppCompatActivity {
Button btBack;
//Назначаем радиокнопкам значения по умолчанию
Boolean sixbool = true;
Boolean sevenbool = false;
Boolean eightbool = false;
private SharedPreferences prefsadv;
//Поле ввода текста для заголовка
private EditText hellotitletext;
RadioGroup rdGroup;
//Переменные для радиокнопок
public RadioButton r1, r2, r3;
//Переменные для передачи состояния из boolean в sharedPrefs
String sixdata;
String sevendata;
String eightdata;
Switch bgswitchvar;
private SharedPreferences prefs;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_advanced);
bgswitchvar = findViewById(R.id.bgswitch);
prefsadv = getSharedPreferences("MY_DATA", MODE_PRIVATE);
rdGroup = (RadioGroup)findViewById(R.id.radioGroup);
//Поле заголовка
String hellotitletext1 = prefsadv.getString("hellotitletext","");
hellotitletext = (EditText) findViewById(R.id.hellotitletext);
hellotitletext.setText(hellotitletext1);
//Ассоциируем переменные с полями по id из xml
r1 = findViewById(R.id.sixfields);
r2 = findViewById(R.id.sevenfields);
r3 = findViewById(R.id.eightfields);
//При нажатии на радиокнопку, вызываем функцию Update с заданным ключом
r1.setChecked(Update("rbsix"));
r2.setChecked(Update("rbseven"));
r3.setChecked(Update("rbeight"));
//При нажатии первой кнопки добавляем True с ключом rbsix в RBDATA
r1.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean r1_isChecked) {
SaveIntoSharedPrefs("rbsix", r1_isChecked);
}
});
//При нажатии второй кнопки добавляем True с ключом rbsix в RBDATA
r2.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean r2_isChecked) {
SaveIntoSharedPrefs("rbseven", r2_isChecked);
}
});
//При нажатии третьей кнопки добавляем True с ключом rbsix в RBDATA
r3.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean r3_isChecked) {
SaveIntoSharedPrefs("rbeight", r3_isChecked);
}
});
//Back button
btBack = findViewById(R.id.btBackadvanced);
btBack.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//Go back
Intent intent = new Intent (
Activity_advanced.this,Activity_settings.class
);
startActivity(intent);
}
});
}
//Сохранение данных в SharedPreferences - ожидая ключ и значение булева типа
private void SaveIntoSharedPrefs(String key, boolean value){
SharedPreferences sp = getSharedPreferences("RBDATA",MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putBoolean(key,value);
editor.apply();
}
//Функция обновления значения в SharedPreferences
private boolean Update(String key){
SharedPreferences sp = getSharedPreferences("RBDATA",MODE_PRIVATE);
return sp.getBoolean(key, false);
}
//Сохраняем данные по количеству полей
public void SaveDataAdvanced(View view)
{
int checkedId = rdGroup.getCheckedRadioButtonId();
if(checkedId == R.id.sixfields) {
sixbool = true;
sevenbool = Boolean.FALSE;
eightbool = Boolean.FALSE;
}
else if (checkedId == R.id.sevenfields){
sevenbool = true;
sixbool = Boolean.FALSE;
eightbool = Boolean.FALSE;
}
else if (checkedId == R.id.eightfields){
eightbool = true;
sevenbool = Boolean.FALSE;
sixbool = Boolean.FALSE;
}
sixdata = String.valueOf(sixbool);
sevendata = String.valueOf(sevenbool);
eightdata = String.valueOf(eightbool);
String hellofield = hellotitletext.getText().toString();
SharedPreferences.Editor editor = prefsadv.edit();
editor.putString("sixfields", sixdata);
editor.putString("sevenfields", sevendata);
editor.putString("eightfields", eightdata);
editor.putString("hellotitletext", hellofield);
editor.apply();
startActivity(new Intent(getApplicationContext(), MainActivity.class));
}
}
Подготовка приложения к публикацииДля отладки и проверки работоспособности приложения советую вам использовать настоящее устройство на Android, так вы сразу сможете отследить наличие, как минимум проблем с оформлением.Здесь я приложил видео-инструкцию, как подключить свой смартфон к Android studio для отладки вашего приложения. На видео вы можете заметить первую версию данного приложения с очень плохим кодом:Извините, данный ресурс не поддреживается. :( Регистрация в Google PlayДля публикации приложения нам следует создать специальный аккаунт разработчика, вот прямая ссылка.Далее вам предстоит оплатить пошлину в $35 за возможность публиковать приложения, это почти в 3 раза дешевле, чем в Steam, при том, что Steam просит $100 за каждое публикуемое приложение/игру, даже бесплатное, а с аккаунтом разработка, в Google Play вы можете публиковать несчётное множество приложений.После оплаты и успешной авторизации в консоли разработчика, необходимо нажать на синюю кнопку "Создать приложение", далее заполнить все необходимые поля:
После создания приложения в консоли разработчика Google Play, необходимо перейти в раздел Рабочая версия и нажать на кнопку Создать новый выпуск. Вам предложат получить электронную подпись для вашего приложения с расширением *.jks, с помощью которой вам предстоит подписать свое первое приложение, а также, все дальнейшие выпуски с обновлениями.Возвращаемся в Android Studio и необходимо заполнить немного информации о нашем приложении, для этого нажимаем File>Project Structure и заполняем поля Version Code и Version Name - без них Google Play Google Play не допустит ваше приложение до публикации:
Наконец, переходим в следующий раздел: пункт меню Build>Generate Signed Bundle / APK
В открывшимся окне выбираем APK. В подразделе Key Store Path выбираем Create new, далее заполняем все поля (прямая ссылка на официальную инструкцию), далее данный ключ потребуется загрузить в консоль Google Play. Затем вернемся в Android Studio и после ввода всех необходимых данных, нажимаем Next
В следующем окне отмечаем все чекбоксы, выбираем release и нажимаем Finish - Android Studio скомпилирует подписанное приложение, которое можно опубликовать в Google Play.
ИтогПосле загрузки файла приложения APK потребуется заполнить множество форм и подготовить множество материалов: описание на разных языках (если необходимо), изображения на разных языках (надписи на изображениях я имею в виду), логотипы, иконки разных размеров, скриншоты со смартфона и планшета.Наконец отправляем приложение в публикацию. Сотрудники Google Play будут проверять ваше приложение в течении 2 недель, судя по официальным данным. Данное приложение рассматривали в течении 5 суток. Также, стоит учесть, что каждое обновление, также, будут проверять, но на обновления уходит не более 2-3 суток.Ссылка на GitHub, как обещано. Ссылка на приложение в Google Play.
===========
Источник:
habr.com
===========
Похожие новости:
- [JavaScript] Контролируем JavaScript импорты с помощью Import maps
- [Haskell, Функциональное программирование] Let vs where в Ocaml/Haskell
- [Схемотехника, Производство и разработка электроники, DIY или Сделай сам, Электроника для начинающих] Разработка источника питания от трёхфазной сети 380В
- [JavaScript, Программирование, VueJS] Сделаем худший Vue.js в мире (перевод)
- [Java] Пишем телеграм бота на Java от А до Я
- [Венчурные инвестиции, Развитие стартапа, Финансы в IT, IT-компании] Новости IT и технологий: борьба Роскомнадзора с Твиттером, оплата взглядом у Сбера
- [Информационная безопасность, Программирование, Разработка под Android] Уязвимости Android 2020
- [JavaScript, Программирование] Основы JavaScript: почему вы должны знать, как работает JS-движок (перевод)
- [Тестирование IT-систем, Java] Автоматизированное тестирование баз данных в Java с помощью JdbcTemplate (перевод)
- [JavaScript, Функциональное программирование] Сочиняя ПО: Введение (перевод)
Теги для поиска: #_programmirovanie (Программирование), #_java, #_razrabotka_mobilnyh_prilozhenij (Разработка мобильных приложений), #_razrabotka_pod_android (Разработка под Android), #_java, #_android, #_android_studio, #_google, #_google_play, #_razrabotka (разработка), #_programmirovanie (программирование), #_razrabotka_prilozhenij (разработка приложений), #_android (андроид), #_android_dlja_nachinajuschij (андроид для начинающий), #_programmirovanie (
Программирование
), #_java, #_razrabotka_mobilnyh_prilozhenij (
Разработка мобильных приложений
), #_razrabotka_pod_android (
Разработка под Android
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 14:16
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
ПредисловиеЯ не являюсь профессиональным разработчиком с огромным стажем в данной области (и это даже не хобби, а лишь нужда в разработке конкретного приложения), потому данная статья, полагаю, будет полезна новичкам, таким же, как и я был в начале разработке своего приложения. Возможно, кто-то найдет что-то полезное из данной статьи, какие-то кусочки окажутся частью ваших будущих разработок.Я расскажу вам как написать простенькое ToDo-приложение на Android с тремя активностями (рабочими экранами).Ссылка на проект на Github будет в конце данной статьи.Установка и первичная настройкаДля разработки приложения я рассмотрю использование бесплатной IDE Intellij от разработчиков JetBrains - Android Studio, у меня версия 4.1.1.После успешной установки IDE и запуска нажимаем на самую первую кнопку Start a new Android Studio Project. Далее появится мастер первичной подготовки проекта:
Далее раскрываем вкладку Project и находим в каталоге Java><Ваш_Проект> файл MainActivity.java, в котором мы будем описывать все происходящее на главном экране.Подготовка макетов (layouts) - внешний облик приложенияПосле рассмотрим файл MainActivity.xml, для этого нам нужно найти каталог res>layout>. Откроем MainActivity.xml для создания облика первой - главной страницы и перетягивая с панели Palette необходимые нам типы объектов.Советую вам размещать объекты под ConstraintLayout, так объекты можно будет привязывать узелками к родительскому ConstraintLayout, который по умолчанию занимает всю пространство, а после привязки узелков, мы можем размещать объекты на нужном нам вертикальном и горизонтальном выравнивании. Кстати, вместо px, тут используется другая величина - dp, позволяющая на разных экранах видеть одинаковый и желаемый результат. Кстати, также, советую названия Текст полей переназначать в String значения, чтобы в дальнейшем было проще делать перевод интерфейса - подобный функционал уже встроен в Android Studio. Для этого нажимаем на объект, далее в меню Свойств объекта находим поле text и нажимаем на маленькую плашку-кнопку справа от текста. В открывшимся окне, нажимаем на плюсик слева сверху и создаем название String-переменной и ее значение по умолчанию: Создание String-переменнойДля перевода интерфейса, необходимо сохранить изменения и над нашим конструктором Layout нажать на кнопку Default (en-us) и выбрать Edit Translations, далее найти слева сверху значок глобуса и нажать на него для добавления нового языка: Переводы для интерфейсовТаким образом создадим дополнительные макеты (layouts) для оставшихся двух окон:Скриншоты: еще два макета Макет Activity_Settings.xml Макет Activity_Advanced.xmlПрограммируем на Java под AndroidЕще раз повторюсь, что это Tutorial больше для новичков; дальше я буду комментировать практически каждую строчку. Ссылка на проект на Github будет в конце данной статьи.Открываем файл Main_Activity.java, который будет отвечать за логику наших переключателей и главного экрана в целом, а она такова:
package com.bb.myapplication;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.SwitchCompat; import android.content.Intent; import android.content.SharedPreferences; import android.graphics.Color; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView; public class MainActivity extends AppCompatActivity { //Создаем 9 переключателей с помощью массива SwitchCompat[] switcharray = new SwitchCompat[9]; Boolean Reset; //Булев для выключения переключателя Button NextButton; public int[] list_of_switches = { R.id.switch_compat1, R.id.switch_compat2, R.id.switch_compat3, R.id.switch_compat4, R.id.switch_compat5, R.id.switch_compat6, R.id.switch_compat7, R.id.switch_compat8, R.id.switch_compat10, //переключатель "Вы уверены?" //8 }; //Нажатие кнопки Сброс public void ResetButtonClick (View view) throws IllegalAccessException { Reset =false; if (switcharray[8].isChecked()) { //Если переключатель "Вы уверены?" нажат, то разрешаем переключить в false остальные переключатели SharedPreferences.Editor editor = getSharedPreferences("save" ,MODE_PRIVATE).edit(); //Сохраняем в Intent значения всех переключателей в False for (int k=0; k<10; k++) { editor.putBoolean("value"+k, false); } editor.apply(); //Устанавливаем все переключатели в значение False for (int i=0;i<9;i++){ switcharray[i].setChecked(false); } //Reset background color of checked SwitchCompats for (int i = 0; i < 9; i++) { findViewById(list_of_switches[i]).setBackgroundColor(Color.TRANSPARENT); } } } //Создание формы / открытие приложения @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //Назначаем полям значения по умолчанию и сохраняем их в Intent String[] tsfield = new String[8]; SharedPreferences prefs = getSharedPreferences("MY_DATA", MODE_PRIVATE); tsfield[0] = prefs.getString("KEY_F0", "Выключил газ"); tsfield[1] = prefs.getString("KEY_F1", "Выключил воду"); tsfield[2] = prefs.getString("KEY_F2", "Покормил кошек"); tsfield[3] = prefs.getString("KEY_F3", "Закрыл окна"); tsfield[4] = prefs.getString("KEY_F4", "Выключил Интернет"); tsfield[5] = prefs.getString("KEY_F5", "Закрыл дверь"); tsfield[6] = prefs.getString("KEY_F6", "Выключил везде свет"); tsfield[7] = prefs.getString("KEY_F7", "Вынес мусор"); //Получаем настройки текста заголовка String hellotext = prefs.getString("hellotitletext", ""); switcharray[6] = findViewById(list_of_switches[6]); switcharray[7] = findViewById(list_of_switches[7]); //Получаем настройки количества полей String sixfields = prefs.getString("sixfields", "true"); String sevenfields = prefs.getString("sevenfields", "false"); String eightfields = prefs.getString("eightfields", "false"); if (sixfields.equals("true")){ switcharray[6].setVisibility(View.GONE); switcharray[7].setVisibility(View.GONE); } else if (sevenfields.equals("true")) { switcharray[6].setVisibility(View.VISIBLE); switcharray[7].setVisibility(View.GONE); } else if (eightfields.equals("true")) { switcharray[6].setVisibility(View.VISIBLE); switcharray[7].setVisibility(View.VISIBLE); } //Создаем массив из TextView TextView[] textarr = new TextView[8]; //Каждому переключателю назначаем текст из итерации поля tsfield for (int i=0; i<8;i++){ textarr[i] = (TextView) findViewById(list_of_switches[i]); textarr[i].setText(tsfield[i]); } //Назначаем текст заголовка TextView textView5 = (TextView) findViewById(R.id.textView5); textView5.setText(hellotext); //Отображать заголовок, если соотв. поле заполнено if(!hellotext.matches("")) { textView5.setVisibility(View.VISIBLE); } //Создаем связь каждого элемента переключателя по id из XML с соответствующей переменной типа SwitchCompat for (int i=0;i<9;i++) { switcharray[i] = findViewById(list_of_switches[i]); } //Создаем связь кнопки по id bt_next из xml переменной NextButton NextButton = findViewById(R.id.bt_next); //Используем SharedPreferences = "save" SharedPreferences sharedPreferences = getSharedPreferences("save" , MODE_PRIVATE); //При первом запуске - все переключатели в False for (int k=0; k<9; k++) { switcharray[k].setChecked(sharedPreferences.getBoolean("value"+k, false)); } //При переключении переключателей сохраняем данные, а также, проверяем их при повторном запуске for (int k=0; k<9; k++) { final int finalK = k; switcharray[k].setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (switcharray[finalK].isChecked()) { //когда переключатель включен Reset = true; // switcharray[finalK].setBackgroundColor(Color.parseColor("#c8a2c6")); SharedPreferences.Editor editor = getSharedPreferences("save" , MODE_PRIVATE).edit(); editor.putBoolean("value" + finalK, true); editor.apply(); switcharray[finalK].setChecked(true); } else { //когда переключатель выключен SharedPreferences.Editor editor = getSharedPreferences("save" , MODE_PRIVATE).edit(); editor.putBoolean("value" + finalK, false); Reset = false; switcharray[finalK].setBackgroundColor(Color.TRANSPARENT); editor.apply(); switcharray[finalK].setChecked(false); } } }); } //Кнопка открытия страницы настроек NextButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //Go to next activity Intent intent2 = new Intent(MainActivity.this, Activity_settings.class); startActivity(intent2); } }); } }
package com.bb.myapplication;
import androidx.appcompat.app.AppCompatActivity; import android.content.Intent; import android.content.SharedPreferences; import android.net.Uri; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class Activity_settings extends AppCompatActivity { //Initialize Variable Button btBack; Button fcSubmit; Button btAdvanced; //Ассоциируем поля ввода с переменными с помощью массива EditText[] InputFields = new EditText[8]; //Назначаем полям значения по умолчанию и сохраняем их в Intent String[] tsfield = new String[8]; //Создаем массив элементов из XML по id public int[] list_of_fields = { R.id.inputField0, R.id.inputField1, R.id.inputField2, R.id.inputField3, R.id.inputField4, R.id.inputField5, R.id.inputField6, R.id.inputField7, }; private SharedPreferences prefs; //Создание формы / открытие приложения @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_settings); //Назначаем полям значения по умолчанию и сохраняем их в Intent prefs = getSharedPreferences("MY_DATA", MODE_PRIVATE); //Получаем данные по количеству используемых полей String sixfields = prefs.getString("sixfields", "true"); String sevenfields = prefs.getString("sevenfields", "false"); String eightfields = prefs.getString("eightfields", "false"); EditText inputField71var = (EditText) findViewById(list_of_fields[6]); EditText inputField81var = (EditText) findViewById(list_of_fields[7]); if (sixfields.equals("true")){ inputField71var.setVisibility(View.INVISIBLE); inputField81var.setVisibility(View.INVISIBLE); } else if (sevenfields.equals("true")) { inputField71var.setVisibility(View.VISIBLE); inputField81var.setVisibility(View.INVISIBLE); } else if (eightfields.equals("true")) { inputField71var.setVisibility(View.VISIBLE); inputField81var.setVisibility(View.VISIBLE); } tsfield[0] = prefs.getString("KEY_F0", "Выключил газ"); tsfield[1] = prefs.getString("KEY_F1", "Выключил воду"); tsfield[2] = prefs.getString("KEY_F2", "Покормил кошек"); tsfield[3] = prefs.getString("KEY_F3", "Закрыл окна"); tsfield[4] = prefs.getString("KEY_F4", "Выключил Интернет"); tsfield[5] = prefs.getString("KEY_F5", "Закрыл дверь"); tsfield[6] = prefs.getString("KEY_F6", "Выключил везде свет"); tsfield[7] = prefs.getString("KEY_F7", "Вынес мусор"); //Назначаем полям ввода текст из SharedPreferences for (int i=0; i<8; i++) { InputFields[i] = (EditText) findViewById(list_of_fields[i]); InputFields[i].setText(tsfield[i]); } //Создаем переменные для кнопок btBack = findViewById(R.id.bt_back); fcSubmit = findViewById(R.id.submit_fc); btAdvanced = findViewById(R.id.btAdvanced); //Кнопка Назад btBack.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //Go back Intent intent = new Intent ( Activity_settings.this,MainActivity.class ); startActivity(intent); } }); //Кнопка Расширенные настройки/Дополнительно btAdvanced.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //Open Advanced Settings Intent intent = new Intent ( Activity_settings.this,Activity_advanced.class ); startActivity(intent); } }); } //Ссылка-значок на внешний ресурс - ссылка на мой телеграм public void tglink(View view){ Intent myWebLink = new Intent(android.content.Intent.ACTION_VIEW); myWebLink.setData(Uri.parse("https://t.me/EndlessNights")); startActivity(myWebLink); } //Кнопка Сохранить данные public void SaveData(View view) { for (int i=0; i<8;i++) { tsfield[i] = InputFields[i].getText().toString(); SharedPreferences.Editor editor = prefs.edit(); editor.putString("KEY_F"+i, tsfield[i]); editor.apply(); } // Открываем главную страницу startActivity(new Intent(getApplicationContext(), MainActivity.class)); } }
package com.bb.myapplication;
import androidx.appcompat.app.AppCompatActivity; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.CompoundButton; import android.widget.EditText; import android.widget.RadioButton; import android.widget.RadioGroup; import android.widget.Switch; import android.widget.TextView; public class Activity_advanced extends AppCompatActivity { Button btBack; //Назначаем радиокнопкам значения по умолчанию Boolean sixbool = true; Boolean sevenbool = false; Boolean eightbool = false; private SharedPreferences prefsadv; //Поле ввода текста для заголовка private EditText hellotitletext; RadioGroup rdGroup; //Переменные для радиокнопок public RadioButton r1, r2, r3; //Переменные для передачи состояния из boolean в sharedPrefs String sixdata; String sevendata; String eightdata; Switch bgswitchvar; private SharedPreferences prefs; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_advanced); bgswitchvar = findViewById(R.id.bgswitch); prefsadv = getSharedPreferences("MY_DATA", MODE_PRIVATE); rdGroup = (RadioGroup)findViewById(R.id.radioGroup); //Поле заголовка String hellotitletext1 = prefsadv.getString("hellotitletext",""); hellotitletext = (EditText) findViewById(R.id.hellotitletext); hellotitletext.setText(hellotitletext1); //Ассоциируем переменные с полями по id из xml r1 = findViewById(R.id.sixfields); r2 = findViewById(R.id.sevenfields); r3 = findViewById(R.id.eightfields); //При нажатии на радиокнопку, вызываем функцию Update с заданным ключом r1.setChecked(Update("rbsix")); r2.setChecked(Update("rbseven")); r3.setChecked(Update("rbeight")); //При нажатии первой кнопки добавляем True с ключом rbsix в RBDATA r1.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean r1_isChecked) { SaveIntoSharedPrefs("rbsix", r1_isChecked); } }); //При нажатии второй кнопки добавляем True с ключом rbsix в RBDATA r2.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean r2_isChecked) { SaveIntoSharedPrefs("rbseven", r2_isChecked); } }); //При нажатии третьей кнопки добавляем True с ключом rbsix в RBDATA r3.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean r3_isChecked) { SaveIntoSharedPrefs("rbeight", r3_isChecked); } }); //Back button btBack = findViewById(R.id.btBackadvanced); btBack.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //Go back Intent intent = new Intent ( Activity_advanced.this,Activity_settings.class ); startActivity(intent); } }); } //Сохранение данных в SharedPreferences - ожидая ключ и значение булева типа private void SaveIntoSharedPrefs(String key, boolean value){ SharedPreferences sp = getSharedPreferences("RBDATA",MODE_PRIVATE); SharedPreferences.Editor editor = sp.edit(); editor.putBoolean(key,value); editor.apply(); } //Функция обновления значения в SharedPreferences private boolean Update(String key){ SharedPreferences sp = getSharedPreferences("RBDATA",MODE_PRIVATE); return sp.getBoolean(key, false); } //Сохраняем данные по количеству полей public void SaveDataAdvanced(View view) { int checkedId = rdGroup.getCheckedRadioButtonId(); if(checkedId == R.id.sixfields) { sixbool = true; sevenbool = Boolean.FALSE; eightbool = Boolean.FALSE; } else if (checkedId == R.id.sevenfields){ sevenbool = true; sixbool = Boolean.FALSE; eightbool = Boolean.FALSE; } else if (checkedId == R.id.eightfields){ eightbool = true; sevenbool = Boolean.FALSE; sixbool = Boolean.FALSE; } sixdata = String.valueOf(sixbool); sevendata = String.valueOf(sevenbool); eightdata = String.valueOf(eightbool); String hellofield = hellotitletext.getText().toString(); SharedPreferences.Editor editor = prefsadv.edit(); editor.putString("sixfields", sixdata); editor.putString("sevenfields", sevendata); editor.putString("eightfields", eightdata); editor.putString("hellotitletext", hellofield); editor.apply(); startActivity(new Intent(getApplicationContext(), MainActivity.class)); } } После создания приложения в консоли разработчика Google Play, необходимо перейти в раздел Рабочая версия и нажать на кнопку Создать новый выпуск. Вам предложат получить электронную подпись для вашего приложения с расширением *.jks, с помощью которой вам предстоит подписать свое первое приложение, а также, все дальнейшие выпуски с обновлениями.Возвращаемся в Android Studio и необходимо заполнить немного информации о нашем приложении, для этого нажимаем File>Project Structure и заполняем поля Version Code и Version Name - без них Google Play Google Play не допустит ваше приложение до публикации: Наконец, переходим в следующий раздел: пункт меню Build>Generate Signed Bundle / APK В открывшимся окне выбираем APK. В подразделе Key Store Path выбираем Create new, далее заполняем все поля (прямая ссылка на официальную инструкцию), далее данный ключ потребуется загрузить в консоль Google Play. Затем вернемся в Android Studio и после ввода всех необходимых данных, нажимаем Next В следующем окне отмечаем все чекбоксы, выбираем release и нажимаем Finish - Android Studio скомпилирует подписанное приложение, которое можно опубликовать в Google Play. ИтогПосле загрузки файла приложения APK потребуется заполнить множество форм и подготовить множество материалов: описание на разных языках (если необходимо), изображения на разных языках (надписи на изображениях я имею в виду), логотипы, иконки разных размеров, скриншоты со смартфона и планшета.Наконец отправляем приложение в публикацию. Сотрудники Google Play будут проверять ваше приложение в течении 2 недель, судя по официальным данным. Данное приложение рассматривали в течении 5 суток. Также, стоит учесть, что каждое обновление, также, будут проверять, но на обновления уходит не более 2-3 суток.Ссылка на GitHub, как обещано. Ссылка на приложение в Google Play. =========== Источник: habr.com =========== Похожие новости:
Программирование ), #_java, #_razrabotka_mobilnyh_prilozhenij ( Разработка мобильных приложений ), #_razrabotka_pod_android ( Разработка под Android ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 14:16
Часовой пояс: UTC + 5