Статьи

Создание редактора ASCII Art: сохранение и удаление изображений ASCII

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

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

Эта серия учебных пособий по созданию простого ASCII-редактора состоит из четырех частей:


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

1
2
3
4
5
6
import java.text.SimpleDateFormat;
import java.util.Calendar;
 
import android.app.AlertDialog;
import android.content.ContentValues;
import android.content.DialogInterface;

Мы будем обрабатывать нажатия на кнопки « Сохранить» , « Удалить» и « Новые» . В вашем основном методе onCreate установите класс для обработки кликов:

1
2
3
4
5
6
Button saveASCIIBtn = (Button)findViewById(R.id.save_btn);
saveASCIIBtn.setOnClickListener(this);
Button newBtn = (Button)findViewById(R.id.new_btn);
newBtn.setOnClickListener(this);
Button deleteBtn = (Button)findViewById(R.id.delete_btn);
deleteBtn.setOnClickListener(this);

Мы добавили эти кнопки в файлы макетов ранее в серии. В методе onClick после существующего кода добавьте в цепочку условных блоков следующие три дополнительные кнопки:

01
02
03
04
05
06
07
08
09
10
11
12
//user has clicked new button
else if(v.getId()==R.id.new_btn) {
         
}
//user has clicked save button
else if(v.getId()==R.id.save_btn) {
 
}
//user has clicked delete button
else if(v.getId()==R.id.delete_btn) {
             
}

Мы добавим код в каждый из этих блоков для реализации функциональности.


Начнем с самой простой функции, пользователи нажимают новую кнопку. В условном блоке в onClick для новой кнопки сбросьте текстовое поле в пустую строку, готовую для ввода пользователем:

1
textArea.setText(«»);

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

1
currentPic=-1;

Давайте обратимся к условному блоку в onClick для кнопки сохранения . Когда пользователь нажимает кнопку сохранения , есть две возможности. Либо они сохраняют новое изображение, еще не сохраненное в базе данных, либо сохраняют изображение, загруженное из базы данных, а затем отредактированное. Если пользователь сохраняет изображение, загруженное из базы данных, а не сохраняет новую запись в базе данных, мы обновим существующую запись.

Сначала получите содержимое редактируемого текста:

1
String enteredTxt = textArea.getText().toString();

Чтобы смоделировать данные, которые мы хотим зафиксировать в базе данных, либо как вставка для нового изображения, либо как обновление для существующего, мы создаем объект Content Values:

1
ContentValues picValues = new ContentValues();

Новые данные будут включать текст из текстового поля, поэтому добавьте его в объект Content Values, используя имя столбца таблицы, которое мы определили в прошлый раз, и сохраните его как открытую переменную в классе помощника базы данных:

1
picValues.put(ImageDataHelper.ASCII_COL, enteredTxt);

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

1
2
3
Date theDate = Calendar.getInstance().getTime();
SimpleDateFormat dateFormat = new SimpleDateFormat(«yyyy-MM-dd_hh.mm.ss»);
String fileName = dateFormat.format(theDate);

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

1
picValues.put(ImageDataHelper.CREATED_COL, fileName);

Получить ссылку на базу данных:

1
SQLiteDatabase savedPicsDB = imgData.getWritableDatabase();

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

1
2
3
4
5
6
if(currentPic<0){
                 
}
else{
                 
}

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

1
long insertNum = savedPicsDB.insert(«pics», null, picValues);

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

1
currentPic=(int)insertNum;

Теперь выведите подтверждающее сообщение пользователю, если вставка прошла успешно:

1
2
3
if(insertNum>=0)
    Toast.makeText(getApplicationContext(), «Image saved to database!»,
        Toast.LENGTH_SHORT).show();

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

1
2
3
4
int savedNum = savedPicsDB.update(«pics»,
    picValues,
    ImageDataHelper.ID_COL+»=?»,
    new String[]{«»+currentPic});

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

1
2
3
if(savedNum>0)
    Toast.makeText(getApplicationContext(), «Image saved to database!»,
        Toast.LENGTH_SHORT).show();

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

1
2
savedPicsDB.close();
imgData.close();
Картинка сохранена

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

1
2
3
4
5
6
7
8
if(currentPic>=0){
//picture has been loaded from the database — get user to confirm
             
}
else{
//picture has not been loaded from database
             
}

В разделе if мы удалим из базы данных. Сначала попросите пользователя подтвердить с помощью Alert Dialog:

1
AlertDialog.Builder confirmBuilder = new AlertDialog.Builder(this);
Удалить диалог

Установите диалоговое сообщение и статус отмены:

1
2
confirmBuilder.setMessage(«Delete the saved picture?»);
confirmBuilder.setCancelable(false);

Теперь нам нужно указать, что должно произойти, когда пользователь решит продолжить удаление, определив положительную кнопку:

1
2
3
4
5
confirmBuilder.setPositiveButton(«Yes», new DialogInterface.OnClickListener() {
    public void onClick(DialogInterface dialog, int id) {
                     
    }
});

Здесь мы определяем новый прослушиватель кликов вместе с его методом onClick . Внутри метода onClick мы можем удалить сохраненную картинку — получить соединение с базой данных:

1
SQLiteDatabase savedPicsDB = imgData.getWritableDatabase();

Теперь выполните удаление:

1
2
3
int deleteResult = savedPicsDB.delete(«pics»,
    ImageDataHelper.ID_COL+»=?»,
    new String[]{«»+currentPic});

Мы указываем имя таблицы, столбец ID и значение для сопоставления в нем, чтобы удалить правильную запись. Если удаление прошло успешно, подтвердите пользователю:

1
2
3
if(deleteResult>0)
    Toast.makeText(getApplicationContext(), «Picture deleted»,
        Toast.LENGTH_SHORT).show();

По-прежнему в диалоговом интерфейсе щелкните метод прослушивания onClick , сбросьте переменную ID изображения, очистите текстовое поле и закройте соединения с базой данных:

1
2
3
4
currentPic=-1;
textArea.setText(«»);
savedPicsDB.close();
imgData.close();

Теперь после блока, в котором вы установили положительную кнопку, установите отрицательную кнопку:

1
2
3
4
5
confirmBuilder.setNegativeButton(«No», new DialogInterface.OnClickListener() {
    public void onClick(DialogInterface dialog, int id) {
        dialog.cancel();
    }
});

В этом случае мы просто отменяем диалог. Теперь мы можем пойти дальше и показать это:

1
2
AlertDialog alert = confirmBuilder.create();
alert.show();
Картинка удалена

Теперь, чтобы завершить раздел удаления метода Activity onClick , перейдите к оператору else для случая , когда текущее изображение не было загружено из базы данных. В этом случае мы просто очистим текст редактирования:

1
textArea.setText(«»);

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

1
2
3
4
@Override
public void onDestroy() {
 
}

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

1
2
imgData.close();
super.onDestroy();

Теперь вы можете проверить свое приложение! Убедитесь, что он правильно сохраняет новые изображения, обновляет существующие изображения и удаляет изображения по запросу пользователя, сохранив несколько, а затем поэкспериментируя с ними.

Рабочее приложение

Простое приложение ASCII Art Editor теперь готово. При запуске приложения вы сможете вводить текстовые символы, сохранять изображения, экспортировать их в виде файлов изображений, загружать, редактировать и удалять ранее сохраненные изображения, а также настраивать цвета дисплея. Загрузка исходного кода содержит все файлы Java и XML, над которыми мы работали в течение серии.

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

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