Эта статья была обновлена в апреле 2016 года, чтобы отразить изменения в Android
Несмотря на множество статей, касающихся Android, в SitePoint, прошло много времени с тех пор, как у нас были настоящие учебники для начинающих. Как лучше восполнить этот пробел, чем с помощью основного учебника для начинающих, приложение «To Do».
Необходимое программное обеспечение
Ингредиенты, которые нужны каждому разработчику Android:
- Android Studio , официальная Android IDE (интегрированная среда разработки). Возможно, еще есть разработчики, использующие старый плагин ADT для Eclipse, но он больше не поддерживается. IntelliJ IDEA также поддерживает разработку под Android, так что вы можете использовать это тоже.
- Android SDK — это набор инструментов, который управляет всем необходимым для создания приложения для Android. Он поставляется вместе с Android Studio, но если вы решите использовать другую IDE, вам придется скачать ее.
Полезно иметь устройство Android, чтобы вы могли протестировать приложение во время разработки. Если вы не можете заполучить устройство Android, вы можете использовать эмулятор по умолчанию или Genymotion .
Примечание . Самым большим плюсом и недостатком Android является его гибкость. Я буду использовать конкретную версию IDE и SDK. Если ваши настройки отличаются, то настройки, код и снимки экрана также могут отличаться.
Вам понадобятся базовые знания Java, чтобы следовать этому руководству.
Начиная
Вы можете найти окончательный код этого проекта на GitHub .
Чтобы создать новый проект, откройте Android Studio и нажмите « Начать новый проект Android Studio» . Назовите приложение «TodoList» и добавьте домен вашей компании, который будет пакетом приложения. В магазине Play Store не может быть двух приложений с одинаковым именем пакета или именем «com.example». Я назову мой ком.азифлай.тодолист .
Затем выберите платформы, для которых вы хотите разработать. Я рекомендую установить минимальный SDK для поддержки API уровня 15 и выше. Это означает, что приложение будет поддерживать каждый смартфон с Android 4.0.3 или более поздней версии.
На следующем экране выберите « Пустое действие» и оставьте имя MainActivity .
Когда Android Studio завершит создание проекта, у вас будет приложение «Hello, World» по умолчанию.
Построение Представления
В MainActivity.java у вас должен быть код, подобный приведенному ниже:
package com.aziflaj.todolist; // This will refelect your package name import android.support.v7.app.AppCompatActivity; import android.os.Bundle; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }
В строке 11 вы устанавливаете представление этого действия на R.layout.activity_main
, который указывает на файл с именем activity_main.xml в каталоге / res / layout проекта. Представление управляет макетом интерфейса Android и выглядит следующим образом:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.aziflaj.todolist.MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" /> </RelativeLayout>
На главном экране вы добавите ListView
, который будет содержать элемент ToDo в каждой строке. Для этого замените элемент TextView
кодом:
<ListView android:id="@+id/list_todo" android:layout_width="wrap_content" android:layout_height="wrap_content" />
Теперь вы определите элемент списка, который будет представлять задачу в интерфейсе.
Создайте новый файл макета в папке / res / layout с именем item_todo.xml . В этот файл вы добавите два элемента: TextView
для отображения задачи и Button
«Done» для удаления задачи. Добавьте этот код в item_todo.xml , заменив все, что уже есть.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center_vertical"> <TextView android:id="@+id/task_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:text="Hello" android:textSize="20sp" /> <Button android:id="@+id/task_delete" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentEnd="true" android:layout_alignParentRight="true" android:text="Done" /> </RelativeLayout>
Приложению необходим пункт меню, позволяющий пользователю добавлять больше задач. Добавьте файл main_menu.xml в каталог / res / menu со следующим кодом:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/action_add_task" android:icon="@android:drawable/ic_menu_add" android:title="Add Task" app:showAsAction="always" /> </menu>
Добавьте следующий код в файл MainActivity.java после метода onCreate
:
@Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main_menu, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_add_task: Log.d(TAG, "Add a new task"); return true; default: return super.onOptionsItemSelected(item); } }
Разработчики Android часто создают константу TAG
с именем класса для ведения журнала. Добавьте это в начало класса MainActivity
:
public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; ...
Метод onCreateOptionsMenu()
раздувает (отображает) меню в основном onOptionsItemSelected()
и использует метод onOptionsItemSelected()
для реагирования на различные взаимодействия пользователя с onOptionsItemSelected()
меню. Если вы запустите приложение, оно должно выглядеть примерно так:
Если вы нажмете кнопку «Добавить», вы увидите нечто подобное в журнале Android Studio:
03-26 22:12:50.327 2549-2549/? D/MainActivity: Add a new task
Затем вы добавите AlertDialog
чтобы получить задачу от пользователя при нажатии кнопки добавления элемента. Вы уже знаете, куда добавить код, реагирующий на пользователя, поэтому замените оператор регистрации следующим:
final EditText taskEditText = new EditText(this); AlertDialog dialog = new AlertDialog.Builder(this) .setTitle("Add a new task") .setMessage("What do you want to do next?") .setView(taskEditText) .setPositiveButton("Add", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { String task = String.valueOf(taskEditText.getText()); Log.d(TAG, "Task to add: " + task); } }) .setNegativeButton("Cancel", null) .create(); dialog.show();
Теперь, нажав кнопку «плюс», вы получите следующее:
Введите текст, и когда вы нажмете кнопку « Добавить» , журнал Android Studio («logcat») покажет что-то вроде этого:
03-26 23:32:18.294 12549-12549/? D/MainActivity: Task to add: I want to learn Android Development
Хранение и получение данных
Android поставляется со встроенной базой данных SQLite . База данных нуждается в таблице, прежде чем она сможет хранить какие-либо задачи, называемые «TaskTable». Создайте новую папку базы данных в том же месте, что и MainActivity.java . Затем создайте новый класс с именем TaskContract
с именем файла TaskContract.java :
Добавьте этот код в TaskContract.java , соответствующим образом изменив два имени пакета.
package com.aziflaj.todolist.db; import android.provider.BaseColumns; public class TaskContract { public static final String DB_NAME = "com.aziflaj.todolist.db"; public static final int DB_VERSION = 1; public class TaskEntry implements BaseColumns { public static final String TABLE = "tasks"; public static final String COL_TASK_TITLE = "title"; } }
Класс TaskContract
определяет константы, которые используются для доступа к данным в базе данных. Вам также нужен вспомогательный класс TaskDbHelper
для открытия базы данных. Создайте этот класс в пакете db
и добавьте следующий код:
package com.aziflaj.todolist.db; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; public class TaskDbHelper extends SQLiteOpenHelper { public TaskDbHelper(Context context) { super(context, TaskContract.DB_NAME, null, TaskContract.DB_VERSION); } @Override public void onCreate(SQLiteDatabase db) { String createTable = "CREATE TABLE " + TaskContract.TaskEntry.TABLE + " ( " + TaskContract.TaskEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + TaskContract.TaskEntry.COL_TASK_TITLE + " TEXT NOT NULL);"; db.execSQL(createTable); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("DROP TABLE IF EXISTS " + TaskContract.TaskEntry.TABLE); onCreate(db); } }
В строках с 15 по 17 этот SQL-запрос:
CREATE TABLE tasks ( _id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL );
Теперь вам нужно MainActivity
для хранения данных в базе данных. Добавьте этот код, где вы определили DialogInterface.OnClickListener()
для AlertDialog
добавления AlertDialog
, заменив:
String task = String.valueOf(taskEditText.getText()); Log.d(TAG, "Task to add: " + task);
с:
String task = String.valueOf(taskEditText.getText()); SQLiteDatabase db = mHelper.getWritableDatabase(); ContentValues values = new ContentValues(); values.put(TaskContract.TaskEntry.COL_TASK_TITLE, task); db.insertWithOnConflict(TaskContract.TaskEntry.TABLE, null, values, SQLiteDatabase.CONFLICT_REPLACE); db.close();
Это делает весь onOptionsItemSelected()
следующим образом:
@Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_add_task: final EditText taskEditText = new EditText(this); AlertDialog dialog = new AlertDialog.Builder(this) .setTitle("Add a new task") .setMessage("What do you want to do next?") .setView(taskEditText) .setPositiveButton("Add", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { String task = String.valueOf(taskEditText.getText()); SQLiteDatabase db = mHelper.getWritableDatabase(); ContentValues values = new ContentValues(); values.put(TaskContract.TaskEntry.COL_TASK_TITLE, task); db.insertWithOnConflict(TaskContract.TaskEntry.TABLE, null, values, SQLiteDatabase.CONFLICT_REPLACE); db.close(); } }) .setNegativeButton("Cancel", null) .create(); dialog.show(); return true; default: return super.onOptionsItemSelected(item); } }
Добавьте частный экземпляр TaskDbHelper
в класс MainActivity
:
private TaskDbHelper mHelper;
И инициализируйте его в onCreate()
:
mHelper = new TaskDbHelper(this);
Если вы запустите приложение, вы не увидите никаких отличий в пользовательском интерфейсе, но вы можете проверить, работает ли база данных, выполнив следующие команды на терминале:
[local] $ adb shell [android] $ run-as com.aziflaj.todolist [android] $ cd databases [android] $ sqlite3 com.aziflaj.todolist.db sqlite3> .dump
Примечание . Если две последние команды не работают, утилита SQLite3 не включена в большинство производственных устройств, но вы можете установить ее самостоятельно.
Теперь вам нужно получить все данные из базы данных и показать их в главном окне.
Замените ваш MainActivity.onCreate()
следующим:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mHelper = new TaskDbHelper(this); SQLiteDatabase db = mHelper.getReadableDatabase(); Cursor cursor = db.query(TaskContract.TaskEntry.TABLE, new String[]{TaskContract.TaskEntry._ID, TaskContract.TaskEntry.COL_TASK_TITLE}, null, null, null, null, null); while(cursor.moveToNext()) { int idx = cursor.getColumnIndex(TaskContract.TaskEntry.COL_TASK_TITLE); Log.d(TAG, "Task: " + cursor.getString(idx)); } cursor.close(); db.close(); }
Когда вы запустите приложение, LogCat покажет список всех задач, хранящихся в базе данных. Далее вы будете отображать данные на главном экране с помощью Adapter
.
Получите ссылку на ListView
созданный в файле activity_main.xml , добавив экземпляр ListView
:
private ListView mTaskListView;
Инициализируйте ссылку, добавив эту строку кода в метод onCreate()
сразу после создания mHelper
:
mTaskListView = (ListView) findViewById(R.id.list_todo);
Переместите код (с некоторыми изменениями), который регистрировал задачи, в закрытый метод updateUI()
:
private void updateUI() { ArrayList<String> taskList = new ArrayList<>(); SQLiteDatabase db = mHelper.getReadableDatabase(); Cursor cursor = db.query(TaskContract.TaskEntry.TABLE, new String[]{TaskContract.TaskEntry._ID, TaskContract.TaskEntry.COL_TASK_TITLE}, null, null, null, null, null); while (cursor.moveToNext()) { int idx = cursor.getColumnIndex(TaskContract.TaskEntry.COL_TASK_TITLE); taskList.add(cursor.getString(idx)); } if (mAdapter == null) { mAdapter = new ArrayAdapter<>(this, R.layout.item_todo, R.id.task_title, taskList); mTaskListView.setAdapter(mAdapter); } else { mAdapter.clear(); mAdapter.addAll(taskList); mAdapter.notifyDataSetChanged(); } cursor.close(); db.close(); }
Добавьте это приватное поле в класс MainActivity
:
private ArrayAdapter<String> mAdapter;
Этот ArrayAdapter
поможет заполнить ListView
данными.
Если вы не понимаете метод updateUI()
, это нормально. Вместо того, чтобы регистрировать задачи, добавьте их в ArrayList
of Strings. Затем проверьте, создан ли mAdapter
или нет. Если это не так, а mAdapter
имеет значение null, создайте и установите его в качестве адаптера ListView
:
mAdapter = new ArrayAdapter<>(this, R.layout.item_todo, // what view to use for the items R.id.task_title, // where to put the String of data taskList); // where to get all the data mTaskListView.setAdapter(mAdapter); // set it as the adapter of the ListView instance
Если адаптер уже создан (что означает, что он назначен для ListView
), очистите его, повторно заполните и уведомите представление об изменении данных. Это означает, что вид будет перекрашиваться на экране с новыми данными.
Чтобы увидеть обновленные данные, необходимо вызывать метод updateUI()
каждый раз, когда меняются базовые данные приложения. Итак, добавьте его в двух местах:
- В
onCreate()
, который изначально показывает все данные - После добавления новой задачи с помощью
AlertDialog
Удаление задач
После завершения задачи ее следует удалить из списка.
Откройте макет item_todo.xml и добавьте эту строку в тег Button
:
android:onClick="deleteTask"
Когда кнопка нажата, она вызывает этот метод deleteTask()
в классе MainActivity
:
public void deleteTask(View view) { View parent = (View) view.getParent(); TextView taskTextView = (TextView) parent.findViewById(R.id.task_title); String task = String.valueOf(taskTextView.getText()); SQLiteDatabase db = mHelper.getWritableDatabase(); db.delete(TaskContract.TaskEntry.TABLE, TaskContract.TaskEntry.COL_TASK_TITLE + " = ?", new String[]{task}); db.close(); updateUI(); }
Теперь, нажав кнопку « Done
, вы удалите задачу из списка и базу данных SQLite.
Заключительные слова
После написания всего этого кода у вас есть простое приложение TodoList, созданное на Java для Android. Если это руководство заинтересовало вас в получении дополнительной информации, то следующим шагом будет просмотр остальной части содержимого SitePoint для Android . Наслаждайтесь!