Создаем простой текстовый редактор
Операции с файлами
Сохранение настроек - Флажки
Сохранение текстовых настроек
Сохранение настроек - Списки
Операции с файлами
Рассмотрим вопросы ввода/вывода, которые являются распространенными операциями в программировании. В Android можно сохранять файлы непосредственно на самом устройстве или на внешней флеш-карте. По умолчанию другие приложения не могут обращаться к этим файлам. Android использует стандартные операции ввода/вывода, принятые в Java. Например, Android реализует потоки с помощью классов из пакета java.io.
Чтобы записать данные в файл, необходимо вызвать метод Context.openFileInput() и передать в качестве параметра имя файла. Метод возвращает стандартный Java-объект FileOutputStream. Вызов метода для данного файла из другого приложения не будет работать, обратиться вы можете только к своим файлам. Например, чтобы создать файл и записать данные, пишем следующий код:
String FILENAME = "hello_file";
String mystring = "hello world!";
FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(mystring.getBytes());
fos.close();
Если имеется статический файл, который надо упаковать с вашим приложением во время компиляции проекта, можно сохранить его в каталоге res/raw/, а затем открыть его при помощи метода Resources.openRawResource(). Он возвращает объект InputStream, который можно использовать для чтения файла. После окончания работы с потоком не забудьте его закрыть, вызвав метод close().
Создадим простейший аналог Блокнота, позволяющий записывать и читать данные из файла.
На главной форме приложения разместим виджет EditText и растянем его на весь экран приложения:
Main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<EditText
android:id="@+id/editText"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:inputType="textMultiLine"
</EditText>
</LinearLayout>
В классе активности приложения определим меню из двух пунктов — Открыть и Сохранить. В методах openFiie() и saveFiie() реализуем операции по открытию и сохранению файла.
TextEditorActivity.java
package ru.alexanderklimov.notepad;
import android.app.Activity;
import android.os.Bundle;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.EditText;
import android.widget.Toast;
public class TextEditorActivity extends Activity
{
// Константы для меню
public static final int IDM_OPEN = 101;
public static final int IDM_SAVE = 102;
// имя файла
private final static String FILENAME = "sample.txt";
private EditText myEdit; // текстовое поле
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myEdit = (EditText)findViewById(R.id.editText);
}
// Создаем меню
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
menu.add(Menu.NONE, IDM_OPEN, Menu.NONE, "Открыть");
menu.add(Menu.NONE, IDM_SAVE, Menu.NONE, "Сохранить")
.setIcon(android.R.drawable.ic_menu_save);
return(super.onCreateOptionsMenu(menu));
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case IDM_OPEN:
openFile(FILENAME);
break;
case IDM_SAVE:
saveFile(FILENAME);
break;
default:
return false;
}
return true;
}
// Метод для открытия файла
private void openFile(String fileName)
{
try
{
InputStream inStream = openFileInput(FILENAME);
if(inStream != null)
{
InputStreamReader sr = new InputStreamReader(inStream);
BufferedReader reader = new BufferedReader(sr);
String str;
StringBuffer buffer = new StringBuffer();
while((str = reader.readLine()) != null)
{
buffer.append(str + "\n");
}
inStream.close();
myEdit.setText(buffer.toString());
}
}
catch(Throwable t)
{
Toast.makeText(getApplicationContext(),
"Exception: " + t.toString(), Toast.LENGTH_LONG).show();
}
}
// Метод для сохранения файла
private void saveFile(String FileName)
{
try
{
OutputStream outStream = openFileOutput(FILENAME, 0);
OutputStreamWriter sw = new OutputStreamWriter(outStream);
sw.write(myEdit.getText().toString());
sw.close();
}
catch (Throwable t)
{
Toast.makeText(getApplicationContext(),
"Exception: " + t.toString(), Toast.LENGTH_LONG)
.show();
}
}
}
В результате мы получили простой блокнотик, позволяющий сохранять записи в заданном файле. При желании вы можете усовершенствовать приложение, добавив возможность создания новых файлов и их удаления.
Сохранение настроек - Флажки
Расширим функциональность блокнота, добавив в него возможность сохранения различных настроек.
Подготовим различные настройки, которые будем хранить в файле строковых ресурсов res/values/strings.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, TextEditorActivity!</string>
<string name="app_name">Text Editor</string>
<string name="pref_openmode">Режим открытия</string>
<string name="pref_color">Цвет</string>
<string name="pref_color_black">Черный цвет</string>
<string name="pref_color_red">Красный цвет</string>
<string name="pref_color_green">Зеленый цвет</string>
<string name="pref_color_blue">Синий цвет</string>
<string name="pref__size">Размер</string>
<string name="pref_style">Стиль</string>
<string name="pref_style_regular">Нормальный</string>
<string name="pref_style_bold">Полужирный</string>
<string name="pref_style_italic">Курсив</string>
</resources>
Теперь создадим файл настроек preferences.xml (если забыли, то перечитайте статью Сохранение настроек):
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<CheckBoxPreference
android:key="@string/pref_openmode"
android:title="Открыть"
android:summary="Открывать файл при запуске приложения" />
</PreferenceScreen>
Итам, определим первую настройку под именем pref_openmode, которое будет или сразу загружать файл в поле редактирования, если установлен флажок, или открывать пустое поле, если флажок не установлен.
Создадим новую активность, которая наследует от PreferenceActivity. В классе активности для предпочтений внутри метода обратного вызова onCreate() нужно только вызвать метод addPreferencesFromResource() и загрузить XML-файл preferences.xml, содержащий наши настройки (пока одну):
package ru.alexanderklimov.notepad;
import android.os.Bundle;
import android.preference.PreferenceActivity;
public class SettingsActivity extends PreferenceActivity
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// загружаем предпочтения из ресурсов
addPreferencesFromResource(R.xml.preferences);
}
}
Не забываем добавить объявление активности SettingsActivity в файл манифеста AndroidManifest.xml:
<activity
android:name=".SettingsActivity"
android:label="@string/app_name">
</activity>
Возвращаемся в основной класс приложения и добавим новый пункт меню Настройки в методе onCreateOptionsMenu(), который будет открывать наше подготовленное окно настроек. В методе обратного вызова onOptionsItemSelected() добавим в структуру switch новый элемент case:
// Добавляем пункт меню в onCreateOptionsMenu
menu.add(Menu.NONE, IDM_PREF, Menu.NONE, "Настройки");
// в метод onOptionsItemSelected()
case IDM_PREF:
Intent intent = new Intent();
intent.setClass(this, SettingsActivity.class);
startActivity(intent);
break;
Запустите приложение и убедитесь, что в меню появился новый пункт, который открывает окно настроек.
Чтение установок предпочтений нужно проводить в методе onResume(), который вызывается системой как во время запуска приложения, так и после закрытия окна настроек и возврата главной активности на передний план:
@Override
public void onResume()
{
super.onResume();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
// читаем установленное значение из CheckBoxPreference
if (prefs.getBoolean(getString(R.string.pref_openmode), false))
{
openFile(FILENAME);
}
}
В методе getBoolean() второй параметр false означает значение по умолчанию для возвращаемого значения предпочтения, если запрос на чтение установленного значения закончится неудачей.
Мы создали первую настройку, позволяющую сразу открывать нужный файл для редактирования, если отметить галочкой нужный пункт.
Сохранение текстовых настроек
Добавим возможность устанавливать размер шрифта для текста. Откроем снова файл preferences.xml и добавим новый элемент EditTextPreference:
<EditTextPreference
android:key="@string/pref_size"
android:title="Размер шрифта"
android:summary="Устанавливает новый размер шрифта"
android:defaultValue="14"
android:dialogTitle="Введите размер шрифта (от 10 до 32)" />
В метод onResume() добавим новый код для чтения установленного значения размера шрифта:
// читаем размер шрифта из EditTextPreference
float fSize = Float.parseFloat(
prefs.getString(getString(R.string.pref_size), "20"));
// применяем настройки в текстовом поле
myEdit.setTextSize(fSize);
Запустите проект и вызовите окно настроек. Теперь у нас появилась опция установки размера шрифта с треугольником. Если щелкнуть на треугольнике, то откроется новое диалоговое окно с текстовым полем ввода.
Обращаю ваше внимание, что в нашем примере не проверяется пользовательский ввод, что может привести к ошибкам, если вместо числового значения для размера шрифта пользователь введет слово Кот или любое другое слово из трех букв. Никогда не доверяйте пользователю!
Сохранение настроек - Списки
Продолжим работу с текстовым редактором и добавим в него список для выбора стиля текста. В списке будет четыре опции: Обычный, Полужирный, Курсив, Полужирный+Курсив.
Подготовим массив строк и сохраним его в файле arrays.xml, который необходимо поместить в каталог res/values/.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="text_style">
<item>Обычный</item>
<item>Полужирный</item>
<item>Курсив</item>
<item>Полужирный+Курсив</item>
</string-array>
</resources>
В файл preferences.xml добавим дополнительный элемент <ListPreference>, в котором определим атрибуты заголовка окна, привязку к массиву значений и значение по умолчанию:
<ListPreference
android:key="@string/pref_style"
android:title="Стиль для шрифта"
android:summary="Устанавливает стиль для шрифта"
android:defaultValue="1"
android:entries="@array/text_style"
android:entryValues="@array/text_style"
android:dialogTitle="Выберите стиль для шрифта" />
Для чтения настроек из списка добавляем код в метод onResume():
// читаем стили текста из ListPreference
String regular = prefs.getString(getString(R.string.pref_style), "");
int typeface = Typeface.NORMAL;
if (regular.contains("Полужирный"))
typeface += Typeface.BOLD;
if (regular.contains("Курсив"))
typeface += Typeface.ITALIC;
// меняем настройки в EditText
//myEdit.setTextSize(fSize);
myEdit.setTypeface(null, typeface);
Запустив проект, вы теперь увидите новую настройку Стиль для шрифта, которая открывает диалоговое окно для выбора стиля из списка. Обратите внимание, что в диалоговом окне нет кнопки сохранения, только Отмена. Изменения сохраняются сразу при выборе опции списка.
В статье Сохранение настроек можно прочитать дополнительные материалы по улучшению окна настроек. Например, можно добавить новую настройку, связанную с выбором цвета для текста.

