410013796724260
• Webmoney
R335386147728
Z369087728698
Вернуться к описанию Хранение данных и файлов в Android
Пример использования хранилища файловНа странице представлен пример использование локального и внешнего хранилищ файлов. Описание методов сохранения и чтения файлов в приложениях Android описано на странице Хранение данных, файлов в Android. Чтобы было легче связать отдельные фрагменты описания кода примера с конечной целью начнем с интерфейса представления. Интерфейс представленияНа следующем скриншоте представлен интерфейс примера после старта в Android Studio. В верхней части формы в виде белого прямоугольника располагается компонент ввода текстового значения, после которого размещается компонент в виде закрашенного прямоугольника для отображения текста файла при его извлечении из файла. В самом низу располагаются радио-кнопки выбора хранилища и кнопки выполнения транзакции (Чтение, Сохранение). ![]() Бизнес-логика функционирования примера интуитивно понятна и примитивна. Необходимо ввести текст, выбрать хранилище и нажать кнопку Сохранение. После этого можно прочитать сохраненный текст. В разные файлы хранилищ можно записать различный текст. При сохранении текста в качестве преамбулы в него добавляется путь к файлу и его наименование (myFile); первые три строки текста представленного на скриншоте примера. Описание кодаНиже представлен проект/модуль store-file в IDE Android Studio. ![]() В проекте определены следующие объекты :
Интерфейс примера на уровне среды разработки (IDE) определяет главный ресурсный файл activity_main.xml. В режиме исполнения примера главный модуль активности MainActivity.java формирует интерфейс и определяет бизнес-логику управления компонентами. Остальные ресурсные файлы играют вспомогательную роль для представления интерфейса компонентов (цвет, фон, текст). Листинг colors.xmlРесурсный файл colors.xml создается автоматически средой Android Studio при формировании нового модуля/проекта. В контект файла добавлен цвет gray_light для подкраски фона прямоугольника. <?xml version="1.0" encoding="utf-8"?> <resources> <color name="purple_200">#FFBB86FC</color> <color name="purple_500">#FF6200EE</color> <color name="purple_700">#FF3700B3</color> <color name="teal_200">#FF03DAC5</color> <color name="teal_700">#FF018786</color> <color name="black">#FF000000</color> <color name="white">#FFFFFFFF</color> <color name="gray_light">#FFEEEEEE</color> </resources> Листинг strings.xmlРесурсный файл strings.xml, также как и colors.xml, создается автоматически средой Android Studio при формировании нового модуля/проекта. В модуле переопределен заголок (app_name) и добавлены строки определения текста меток и кнопок интерфейса. В теге <string> с атрибутом name="multiple_text" определен двустрочный текст, который при старте записывается в верхний компонент/прямоугольник. <resources> <string name="app_name">Хранилище файлов</string> <string name="tv_editor">Редактирование текста</string> <string name="tv_viewer">Просмотр файла</string> <string name="location">Расположение</string> <string name="radio_inner">Внутреннее</string> <string name="radio_cd">Внешнее (CD)</string> <string name="btn_save">Сохранение</string> <string name="btn_read">Чтение</string> <string name="multiple_text">"This is a TextView \n With multiple lines</string> </resources> border_gray.xmlРесурсный файл border_gray.xml создан для формирования интерфейса компонента TextView в виде закрашенного прямоугольника. Располагается файл в разделе res/drawable. Главная секция XML-файла имеет тег shape. Внутреннее содержимое файла определяет цвет фона, цвет обрамляющего прямоугольника и радиус скругления углов прямоугольника. Ниже представлен листинг файла border_gray.xml (в свернутом виде). Листинг border_gray.xml <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <!-- View background color --> <solid android:color="@color/gray_light" > </solid> <!-- View border color and width --> <stroke android:width="1dp" android:color="@color/black" > </stroke> <!-- The radius makes the corners rounded --> <corners android:radius="3dp" > </corners> </shape> Для создания ресурсного файла border_gray.xml с помощью IDE Android Studio необходимо выделить в проекте запись res/drawable и в контекстном меню выбрать пункт New/Drawable Resource File. В открывшемся диалоговом окне, как это представлено на следующем скриншоте, необходимо определить File name, наименование корневого элемента Root name и нажать ОК. После того, как файл будет создан, его можно открыть и отредактировать. Ресурсный файл border_white.xml отличается только цветом фона. ![]() activity_main.xmlНа следующем скриншоте представлен ресурсный файл activity_main.xml в режиме Design. Данный ресурс определяет интерфейс приложения/модуля в режиме run-time. Особый комментарий здесь не требуется. Можно только отметить, что для редактирования компонента в режиме Design его можно выделить в дереве компонентов Component Tree (слева снизу), и определить свойства в панели атрибутов, не представленной на скриншоте. Также компоненты можно редактировать непосредственно в файле, переключаясь в режим Code. ![]() Ниже (в свернутом виде) представлен листинг activity_main.xml. После переключения редактора ресурсного файла из режима Design в режим Code свойства визуальных компонентов интерфейса можно редактировать непосредственно в файле. IDE Android Studio "помогает" при прямом редактировании свойств компонента представлением всплывающих подсказок. Листинг activity_main.xml <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/tvEditor" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:labelFor="@id/etmEditor" android:text="@string/tv_editor" android:textStyle="bold" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <EditText android:id="@+id/etmEditor" android:layout_width="380dp" android:layout_height="128dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:background="@drawable/border_white" android:ems="10" android:gravity="start|top" android:importantForAutofill="no" android:inputType="textMultiLine" android:lines="10" android:maxLines="10" android:padding="4dp" android:text="@string/multiple_text" android:textAlignment="viewStart" android:textSize="14sp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/tvEditor" tools:ignore="DuplicateSpeakableTextCheck" /> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginTop="16dp" android:text="@string/tv_viewer" android:textStyle="bold" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/etmEditor"/> <EditText android:id="@+id/etmViewer" android:layout_width="380dp" android:layout_height="128dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:background="@drawable/border_gray" android:cursorVisible="false" android:ems="10" android:focusable="false" android:gravity="start|top" android:importantForAutofill="no" android:inputType="textMultiLine" android:lines="10" android:longClickable="false" android:maxLines="10" android:padding="4dp" android:textSize="14sp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/textView" tools:ignore="SpeakableTextPresentCheck" /> <Button android:id="@+id/btnRead" android:layout_width="160dp" android:layout_height="56dp" android:layout_marginStart="8dp" android:layout_marginTop="16dp" android:onClick="onBtnReadClick" android:text="@string/btn_read" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/rbGroup"/> <Button android:id="@+id/btnSave" android:layout_width="160dp" android:layout_height="56dp" android:layout_marginStart="8dp" android:layout_marginTop="16dp" android:onClick="onBtnSaveClick" android:text="@string/btn_save" app:layout_constraintStart_toEndOf="@+id/btnRead" app:layout_constraintTop_toBottomOf="@+id/rbGroup"/> <RadioGroup android:id="@+id/rbGroup" android:layout_width="320dp" android:layout_height="56dp" android:layout_marginStart="16dp" android:layout_marginTop="8dp" android:background="@drawable/border_white" android:orientation="horizontal" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/tvLocation"> <RadioButton android:id="@+id/rbIn" android:layout_width="160dp" android:layout_height="wrap_content" android:text="@string/radio_inner" app:layout_constraintStart_toStartOf="parent"/> <RadioButton android:id="@+id/rbOut" android:layout_width="160dp" android:layout_height="wrap_content" android:text="@string/radio_cd" /> </RadioGroup> <TextView android:id="@+id/tvLocation" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:layout_marginTop="16dp" android:text="@string/location" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/etmViewer"/> </androidx.constraintlayout.widget.ConstraintLayout> MainActivity.javaФайл MainActivity.java (представлен ниже в свернутом виде) наследует свойства активности AppCompatActivity, формирует интерфейс примера и определяет бизнес-логику его компонентов. Активность MainActivity включает несколько методов :
Детального описания кода активности не требуется, он прозрачен. Специфичные константы и методы обращения к хранилищам Android подсвечены. Листинг MainActivity.java package com.example.store.file; import android.os.Bundle; import android.os.Environment; import android.util.Log; import android.view.View; import android.widget.EditText; import android.widget.RadioButton; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { private EditText tvEdit = null; private EditText tvView = null; private RadioButton rbIn = null; private final String FILENAME = "myFile"; private final String LOG_TAG = "DEVELOPMENT"; private String EXTERNAL_DIR; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tvEdit = findViewById(R.id.etmEditor); tvView = findViewById(R.id.etmViewer); rbIn = findViewById(R.id.rbIn ); // Внешнее хранилище EXTERNAL_DIR = Environment.DIRECTORY_MUSIC; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ private void readExternalFile() { Log.d(LOG_TAG, "ExternalStorageState : " + Environment.getExternalStorageState()); File dir= getExternalFilesDir(EXTERNAL_DIR); if (dir == null) { Log.d(LOG_TAG, "dir = NULL"); return; } File file; file = new File(dir.getAbsolutePath(), FILENAME); Log.d(LOG_TAG, "file : " + file.getAbsolutePath()); Log.d(LOG_TAG, "file exists : " + file.exists()); if (file.exists()) { try { FileReader fr = new FileReader(file); BufferedReader br = new BufferedReader(fr); String str; StringBuilder text = new StringBuilder(); // читаем содержимое while ((str = br.readLine()) != null) { if (!str.contains(":")) str = " " + str.trim(); text.append(str).append("\n"); } tvView.setText(text.toString()); } catch (IOException e) { e.printStackTrace(); } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void readLocalFile() { try { FileInputStream fis ; InputStreamReader isr ; BufferedReader br ; StringBuilder text; fis = openFileInput(FILENAME); isr = new InputStreamReader(fis); br = new BufferedReader(isr); text = new StringBuilder(); // читаем содержимое String str; while ((str = br.readLine()) != null) { if (!str.contains(":")) str = " " + str.trim(); text.append(str).append("\n"); } tvView.setText(text.toString()); } catch (IOException e) { e.printStackTrace(); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void writeExternalFile() { Log.d(LOG_TAG, "ExternalStorageState : " + Environment.getExternalStorageState()); File dir= getExternalFilesDir(EXTERNAL_DIR); try { File file; file= new File(dir.getAbsolutePath(),FILENAME); Log.d(LOG_TAG, file exists : "+file.exists()); String txt="file :\n" +file.getAbsolutePath() + "\ntext :\n" + tvEdit.getText() .toString(); FileWriter fw = new FileWriter(file); BufferedWriter bw = new BufferedWriter(fw); // пишем данные bw.write(txt); // закрываем поток bw.close(); Log.d(LOG_TAG, "Файл записан"); Log.d(LOG_TAG, "file exists : " + file.exists()); Log.d(LOG_TAG, "file path : " + file.getAbsolutePath()); } catch (IOException e) { e.printStackTrace(); } catch (NullPointerException e) { e.printStackTrace(); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void writeLocalFile() { File internalStorageDir = getFilesDir(); File file = new File(internalStorageDir, FILENAME); String txt = "file :\n" + file.getAbsolutePath() +"\ntext :\n" + tvEdit.getText().toString(); try { FileOutputStream fos; OutputStreamWriter osw; fos = openFileOutput(FILENAME, MODE_PRIVATE); osw = new OutputStreamWriter(fos); BufferedWriter bw = new BufferedWriter(osw); bw.write(txt); bw.close(); Log.d(LOG_TAG, "Файл записан"); } catch (IOException e) { e.printStackTrace(); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ public void onBtnReadClick(View v) { if (rbIn.isChecked()) readLocalFile(); else readExternalFile(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ public void onBtnSaveClick(View v) { if (rbIn.isChecked()) writeLocalFile(); else writeExternalFile(); } } В модуле используется средство просмотра отладочных сообщений Logcat с тегом LOG_TAG для вывода дополнительной информации о состоянии внешнего хранилища, а также путей к файлам. |