Как вывести список файлов android studio java
Одна из частых задач, возникающих при программировании Android приложений, - это отображение на дисплее набора данных. Например, списка пользователей, содержимого папки, набора заметок и так далее. Для решения данной задачи в составе Android SDK есть такие компоненты как ListView, GridView, RecyclerView. В этой статье речь пойдет об использовании ListView. Этот компонент на данный момент является самым распространенным.
Итак, ListView предназначен для отображения набора данных в виде одномерного (в один столбец) списка. Принцип работы данного компонента состоит в том, что он создает несколько View элементов, достаточных для отображения видимой части списка и затем переиспользует их (то есть заполняет новыми данными), когда пользователь скролит список.
Созданием View элементов списка и заполнением их данными занимается адаптер - объект, который реализует интерфейс Adapter. Он создается разработчиком на этапе конфигурирования ListView. В составе Android SDK уже есть несколько готовых адаптеров, работающих «из коробки», например ArrayAdapter, SimpleAdapter, CursorAdapter. Также разработчик может написать свой, так называемый custom адаптер, что обычно и приходится делать.
Базовая схема использования ListView выглядит так:
- прописываем ListView в требуемый layout файл Activity или Fragment
- создаем объект для хранения данных и заполняем его данными
- создаем layout для одного элемента списка
- создаем адаптер, передав ему набор данных и layout одного элемента списка
- получаем ссылку на ListView и передаем ему адаптер
- добавляем обработчики событий, например OnItemClickListener
Попробуем написать простое приложение с ListView и ArrayAdapter.
1. Создаем в Android Studio проект на базе шаблона EmptyActivity.
File > New > New Project. далее следуем указаниям визарда.
Я создал проект с такими параметрами:
2. В layout файл Activity добавляем ListView.
По умолчанию AndroidStudio создает файл разметки с RelativeLayout и TextView. Меняем RelativeLayout на FrameLayout, а TextView на ListView. Должен получиться примерно такой код:
id нужен для того чтобы получить ссылку на ListView в коде.
layout_width и layout_height задают размеры Listview. В данном случае ListView займет все пространство, которое ему предоставит FrameLayout.
3. Создаем объект для хранения данных и заполняем его.
Тип объекта, используемого для хранения данных, определяется типом используемого адаптера. ArrayAdapter может работать с массивами или коллекциями, реализующими List интерфейс. Если разработчик создает свой адаптер, он может использовать произвольные объекты, например xml файл.
Мы будем использовать ArrayList и набор строк. Код будет выглядеть так:
Замечание! На этапе создания адаптера и конфигурирования ListView, данные для отображения могут отсутствовать, например, если они подгружаются из базы данных или удаленного веб-сервиса. В этом нет ничего необычного, их можно добавить и потом. Этот момент будет разобран в следующих статьях.
4. Создаем layout одного элемента списка.
Для этого в AndroidStudio нажимаем правой кнопкой мыши на папке res > layout и создаем новый Layout resource file.
ArrayAdapter умеет работать только с макетами, в которых есть только одно текстовое поле для заполнения. Обычно это TextView. В макете могут присутствовать другие View элементы, но ArrayAdapter не сможет ничего с ними сделать.
Наш макет будет выглядеть так:
id нужен для того, чтобы адаптер мог получить ссылку на TextView (хотя если макет состоит из одного TextView, то этот параметр можно опустить)
layout_with и layout_height задают размеры TextView. В данном случае он растянется по горизонтали на всю ширину, предоставленную родительским компонентом (ListView), а по высоте будет равен высоте текста + padding параметр.
padding – задается в dp (density-independent pixel) единицах и представляет собой пространство между текстом и внешней границей TextView
textSize – определяет размер текста и задается в sp (scale-independent pixel) единицах
Замечание! Android SDK имеет собственный набор ресурсов (картинки, макеты, наборы цветов и так далее), которые разработчик может использовать в своих приложениях. В данном случае мы могли бы применить готовый макет android.R.layout.simple_list_item_1, который имеет такую же структуру — один TextView.
5. Создаем адаптер и передаем его ListView.
Адаптер - это объект, создающий View объект на основе переданного ему layout файла и заполняющий этот объект данными. В этой роли может выступать класс, который реализует интерфейс Adapter. Для упрощения задачи, мы используем готовый класс адаптера — ArrayAdapter. Это самый простой адаптер в Android SDK, поэтому с него и стоит начать знакомство.
Класс ArrayAdapter имеет несколько конструкторов, нам подойдут вот такие:
context – это объект, который используется адаптером для создания View объектов на основе переданного макета. Обычно здесь передается ссылка на Activity.
resource – это id макета элемента списка, то есть id layout файла.
textViewResouceId – id элемента, отображающего текст. В нашем случае это id TextView.
objects – ссылка на коллекцию, содержащую данные
Если layout элемента списка состоит только из TextView (как в нашем случае), достаточно первого конструктора. Если layout более сложный (из нескольких View объектов), нужно использовать второй конструктор и передавать адаптеру id текстового поля.
В нашем случае код будет выглядеть так:
6. Получаем ссылку на ListView и передаем ему адаптер.
Тут все просто, ссылку на View объект в Activity мы получаем с помощью метода findViewById(int id).
Все. С этого момента ListView уже будет работать. Можно загрузить приложение в телефон или эмулятор и убедиться в этом.
7. Добавляем обработчики нажатий — listener объекты.
Имея ссылку на ListView, разработчик может назначить ему обработчики событий. Наиболее часто используемые события — это кратковременное нажатие на элемент списка и длительное нажатие. Для регистрации обработчиков этих событий используются следующие методы:
Эти методы принимают ссылки на объекты, реализующие интерфейсы OnItemClickListener и OnItemLongClickListener. Каждый интерфейс содержит по одному методы, которые будут вызываться ListView при наступлении соответствующего события. Для интерфейса OnItemClickListener метод выглядит так:
parent – ссылка на ListVew
view – ссылка на view объект, на который было произведено нажатие.
position – позиция view в адаптере
id – идентификационный номер элемента списка, обычно совпадает с position.
Самый простой вариант добавления обработчика состоит в использовании анонимного класса. Вот так:
Многие разработчики не любят подобное нагромождение кода и предпочитают реализовать требуемый интерфейс в Activity (или Fragment) и передавать ссылку на нее. Вот так:
В обработчике события обычно выполняется какая-либо работа с нажатым View или данными, соответствующими этому элементу списка. Получить данные из обработчика можно несколькими способами. Самый простой способ состоит в использовании ссылки на объект, в котором хранит данные. В нашем случае это ссылка на ArrayList.
Также можно получить данные, использую объект parent, который передается обработчику. На мой взгляд - это более правильный способ доступа к данным.
Работа с настройками уровня activity и приложения позволяет сохранить небольшие данные отдельных типов (string, int), но для работы с большими массивами данных, такими как графически файлы, файлы мультимедиа и т.д., нам придется обращаться к файловой системе.
ОС Android построена на основе Linux. Этот факт находит свое отражение в работе с файлами. Так, в путях к файлам в качестве разграничителя в Linux использует слеш "/", а не обратный слеш "\" (как в Windows). А все названия файлов и каталогов являются регистрозависимыми, то есть "data" это не то же самое, что и "Data".
Приложение Android сохраняет свои данные в каталоге /data/data/<название_пакета>/ и, как правило, относительно этого каталога будет идти работа.
Для работы с файлами абстрактный класс android.content.Context определяет ряд методов:
boolean deleteFile (String name) : удаляет определенный файл
String[] fileList () : получает все файлы, которые содержатся в подкаталоге /files в каталоге приложения
File getCacheDir() : получает ссылку на подкаталог cache в каталоге приложения
File getDir(String dirName, int mode) : получает ссылку на подкаталог в каталоге приложения, если такого подкаталога нет, то он создается
File getExternalCacheDir() : получает ссылку на папку /cache внешней файловой системы устройства
File getExternalFilesDir(String type) : получает ссылку на каталог /files внешней файловой системы устройства
File getFileStreamPath(String filename) : возвращает абсолютный путь к файлу в файловой системе
FileInputStream openFileInput(String filename) : открывает файл для чтения
FileOutputStream openFileOutput (String name, int mode) : открывает файл для записи
Все файлы, которые создаются и редактируются в приложении, как правило, хранятся в подкаталоге /files в каталоге приложения.
Для непосредственного чтения и записи файлов применяются также стандартные классы Java из пакета java.io.
Итак, применим функционал чтения-записи файлов в приложении. Пусть у нас будет следующая примитивная разметка layout:
Поле EditText предназначено для ввода текста, а TextView - для вывода ранее сохраненного текста. Для сохранения и восстановления текста добавлены две кнопки.
Теперь в коде Activity пропишем обработчики кнопок с сохранением и чтением файла:
При нажатии на кнопку сохранения будет создаваться поток вывода FileOutputStream fos = openFileOutput(FILE_NAME, MODE_PRIVATE)
В данном случае введенный текст будет сохраняться в файл "content.txt". При этом будет использоваться режим MODE_PRIVATE
Система позволяет создавать файлы с двумя разными режимами:
MODE_PRIVATE : файлы могут быть доступны только владельцу приложения (режим по умолчанию)
MODE_APPEND : данные могут быть добавлены в конец файла
Поэтому в данном случае если файл "content.txt" уже существует, то он будет перезаписан. Если же нам надо было дописать файл, тогда надо было бы использовать режим MODE_APPEND:
Для чтения файла применяется поток ввода FileInputStream :
В итоге после нажатия кнопки сохранения весь текст будет сохранен в файле /data/data/название_пакета/files/content.txt
Где физически находится созданный файл? Чтобы увидеть его на подключенном устройстве перейдем в Android Stud в меню к пункту View -> Tool Windows -> Device File Explorer
После этого откроектся окно Device File Explorer для просмотра файловой системы устройства. И в папке data/data/[название_пакета_приложения]/files мы сможем найти сохраненный файл.
Многие приложения каким-то образом обрабатывают файлы, и манипулирование файлами является одним из основных знаний на любом языке программирования.
Чтобы манипулировать файлами, нам нужно знать, где они находятся. Наличие обзора файлов в каталоге имеет первостепенное значение, если мы хотим этого добиться, особенно если мы можем выполнять операции с ними с помощью итерации. В Java есть несколько способов сделать это, которые мы покажем в этой статье.
Для простоты все примеры будут написаны для следующего дерева файлов:
Файл.список()
Самым простым методом для перечисления имен файлов и папок в заданном каталоге без обхода подкаталогов является вспомогательный метод .list () , который возвращает массив String s.
Мы делаем это с помощью метода .list() в экземпляре Файла :
Используя простой цикл для каждого , мы перебираем массив и выводим Строку s.
При использовании этого подхода все элементы в каталоге Кодирование музыки не отображаются, и недостатком этого подхода является то, что мы действительно ничего не можем сделать с самими файлами. Мы только узнаем их имена. Это полезно, когда мы просто хотим взглянуть на файлы по номиналу.
Фильтр имен файлов
Запуск этого фрагмента кода приведет к:
Файл.listFiles()
Подобно предыдущему методу, этот метод можно использовать для возврата имен файлов и каталогов, но на этот раз мы получаем их в виде массива объектов File , что дает нам возможность напрямую манипулировать ими:
Теперь давайте углубимся в файловую систему, используя рекурсию и еще несколько методов для использования с Файлом объектом:
Файлы.прогулка()
В Java 8 и более поздних версиях мы можем использовать файл java.nio.Файлы класс для заполнения потока и использования его для просмотра файлов и каталогов и в то же время рекурсивного обхода всех подкаталогов.
Обратите внимание, что в этом примере мы будем использовать лямбда-выражения:
Git Essentials
Ознакомьтесь с этим практическим руководством по изучению Git, содержащим лучшие практики и принятые в отрасли стандарты. Прекратите гуглить команды Git и на самом деле изучите это!
Здесь мы заполнили Поток , используя метод .walk () , передав аргумент Пути|/. Класс Пути состоит из статических методов , которые возвращают Путь на основе строкового URI - и, используя Путь , мы можем легко найти файл.
Путь , Пути , Файлы и многие другие классы принадлежат пакету java.nio , который был представлен в Java 7 как более современный способ представления файлов неблокирующим способом.
Затем с помощью Collections Framework создается список.
Запуск этого фрагмента кода приведет к:
Вывод
Обработка файлов каким-либо образом является основной задачей для большинства языков программирования, и это включает в себя возможность перечислять и находить файлы в файловой системе. Чтобы манипулировать файлами, нам нужно знать, где они находятся. Наличие обзора файлов в каталоге имеет первостепенное значение, если мы хотим этого добиться, особенно если мы можем выполнять операции с ними с помощью итерации.
В этой статье мы показали несколько различных способов в Java перечисления файлов в файловой системе, используя как линейный, так и рекурсивный подходы.
В отличие от большинства классов ввода/вывода, класс File работает не с потоками, а непосредственно с файлами. Данный класс позволяет получить информацию о файле: права доступа, время и дата создания, путь к каталогу. А также осуществлять навигацию по иерархиям подкаталогов.
Класс java.io.File может представлять имя определённого файла, а также имена группы файлов, находящихся в каталоге. Если класс представляет каталог, то его метод list() возвращает массив строк с именами всех файлов.
Для создания объектов класса File можно использовать один из следующих конструкторов.
- File(File dir, String name) - указывается объекта класса File (каталог) и имя файла
- File(String path) - указывается путь к файлу без указания имени файла
- File(String dirPath, Sring name) - указывается путь к файлу и имя файла
- File(URI uri) - указывается объекта URI, описывающий файл
Методы класса File
Класс File может использоваться для создания каталога или дерева каталогов. Также можно узнать свойства файлов (размер, дату последнего изменения, режим чтения/записи), определить к какому типу (файл или каталог) относится объект File, удалить файл. У класса очень много методов, перечислим некоторые.
- getAbsolutePath() - абсолютный путь файла, начиная с корня системы. В Android корневым элементом является символ слеша (/)
- canRead() - доступно для чтения
- canWrite() - доступно для записи
- exists() - файл существует или нет
- getName() - возвращает имя файла
- getParent() - возвращает имя родительского каталога
- getPath() - путь
- lastModified() - дата последнего изменения
- isFile() - объект является файлом, а не каталогом
- isDirectory - объект является каталогом
- isAbsolute() - возвращает true, если файл имеет абсолютный путь
- renameTo(File newPath) - переименовывает файл. В параметре указывается имя нового имени файла. Если переименование прошло неудачно, то возвращается false
- delete() - удаляет файл. Также можно удалить пустой каталог
Каталог
Каталог - это объект класса File, который содержит список других файлов и каталогов. После создания объекта класса File, являющего каталогом, его метод isDirectory() вернёт значение true. И тогда вы можете вызывать метод list().
Для создания каталога можно использовать метод mkdir(), который вернёт true в успешном случае. Если указанный путь уже существует или каталог нельзя создать из-за отсутствия полного пути к нему, то вернётся false.
Метод mkdirs() создаёт сам каталог, так и всех его родителей.
Список каталогов
Если вы хотите получить содержимое каталога, то можно вызвать метод list() без аргументов. Вам вернётся полный список (массив) имён файлов и каталогов, содержащихся в данном каталоге. Есть ещё похожий метод listFiles(), который возвращает массив файлов (объектов, а не их имён), о котором поговорим отдельно.
Если вам нужен только список файлов с расширением .java, то можно использовать специальный фильтр-класс, который описывает критерии отбора объектов File с помощью интерфейса FilenameFilter.
Интерфейс FilenameFilter определяет единственный метод accept(), вызываемый по одному разу с каждым файлом в списке.
Метод возвращает true для файлов каталога, указанного в dir, которые должны быть включены в список, и false - для файлов, которые следует исключить.
Метод listFiles()
Метод имеет несколько перегруженных версий. Он возвращает список файлов в виде массива объектов класса File. Одна из версий метода также использует интерфейс FilenameFilter. Другая версия использует интерфейс FileFilter и возвращает те файлы, путевые имена которых соответствует интерфейсу.
Пример использования методов класса File показан в уроке Файловый менеджер и в других примерах.
Перед тем, как начать говорить про компонент ListView, предлагаю вспомнить еще раз прошлый урок и механизм построения списка, который мы там использовали. Мы перебирали массив данных, в каждой итерации создавали пункт списка, заполняли его данными и помещали в список.
При создании ListView создавать пункты за нас будет адаптер. Адаптеру нужны от нас данные и layout-ресурс пункта списка. Далее мы присваиваем адаптер списку ListView. Список при построении запрашивает у адаптера пункты, адаптер их создает (используя данные и layout) и возвращает списку. В итоге мы видим готовый список.
Есть различные типы списков и адаптеров. Мы пока что рассмотрим простейший вариант.
Project name: P0421_SimpleList
Build Target: Android 2.3.3
Application name: SimpleList
Package name: ru.startandroid.develop.p0421simplelist
Create Activity: MainActivity
Открываем main.xml и добавим на экран компонент ListView (вкладка Composite):
ListView – это и есть компонент списка.
Теперь надо создать адаптер. Открываем MainActivity.java и пишем:
Вы не поверите, но это весь код, необходимый для создания списка )
В качестве данных используем массив имен. В onCreate мы находим список, создаем адаптер и присваиваем адаптер списку. Давайте разберемся, как создали адаптер.
и передали ему следующие параметры:
this – контекст
android.R.layout.simple_list_item_1 – это системный layout-файл, который представляет собой TextView
names – массив данных, которые мы хотим вывести в список
Мы можем посмотреть содержимое использованного simple_list_item_1. Для этого в вашем проекте найдите пункт Android 2.3.3., раскройте его, и раскройте android.jar
Проматывайте в самый низ и открывайте res.layout.
И внутри находим используемый нами simple_list_item_1
Двойной клик на него и смотрим содержимое:
Обычный TextView с набором параметров.
Когда список при формировании запрашивает очередной пункт, адаптер берет этот Layout-ресурс simple_list_item_1, прогоняет его через LayoutInflater и получает View, преобразует View к TextView, присваивает ему текст из массива данных и отдает списку.
Все сохраним и запустим. Видим список из наших данных.
Использование системного layout-ресурса simple_list_item_1 хорошо тем, что нам не надо самим layout рисовать. Однако, если нас не устраивает то, как выглядит список с использованием simple_list_item_1 в качестве пункта списка, мы можем создать свой layout-ресурс.
Создадим layout-файл my_list_item.xml в папке res/layout нашего проекта:
TextView с указанием цвета и размера шрифта, выравнивания текста и отступов.
Изменим существующий код, укажем адаптеру наш созданный layout-ресурс my_list_item:
Теперь адаптер будет использовать его при создании пунктов списка.
Все сохраним и запустим. Видим наш зеленый список:
В layout-ресурсе для пункта списка вместо TextView вы можете использовать какой-нибудь его производный класс – например Button. Главное, чтобы объект прошел преобразование к TextView. Адаптер присвоит ему текст методом setText и отдаст списку.
Немного про Context
На одном из прошлых уроков я говорил, что Context (контекст) используется для доступа к базовым функциям приложения. В этом уроке у нас получилось хорошее подтверждение этим словам.
ArrаyAdapter использует LayoutInflater, чтобы конвертнуть layout-ресурс в View. Но получение объекта LayoutInflater – это одна из базовых функций и она недоступна для класса ArrаyAdapter. Поэтому мы в ArrаyAdapter в качестве контекста передаем ссылку на Activity (Activity имеет доступ к базовым функциям через восходящую иерархию классов). А класс ArrayAdapter внутри себя использует переданный ему контекст, чтобы вызвать LayoutInflater. Без контекста он не смог бы это сделать.
На следующем уроке:
- используем список ListView для одиночного и множественного выбора элементов
public ArrayAdapter (Context context, int textViewResourceId, T[] objects)
- в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование
- ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
- новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме
Читайте также: