So now that you have set up the project, lets start coding and making this File Explorer come to life! (If you haven’t read the first part of this series, please read it here.)

Setting up FilesListFragment

The first thing you are going to do is create a Fragment named FilesListFragment. In this fragment you will take a path as an argument, read all the files/directories on that path and show them in a RecyclerView.

FilesListFragment class FilesListFragment : Fragment() { companion object { private const val ARG_PATH: String = "com.thetechnocafe.gurleensethi.kotlinfileexplorer.fileslist.path" } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_files_list, container, false) } } 1 2 3 4 5 6 7 8 9 10 class FilesListFragment : Fragment ( ) { companion object { private const val ARG_PATH : String = "com.thetechnocafe.gurleensethi.kotlinfileexplorer.fileslist.path" } override fun onCreateView ( inflater : LayoutInflater , container : ViewGroup ? , savedInstanceState : Bundle ? ) : View ? { return inflater . inflate ( R . layout . fragment_files_list , container , false ) } }

Here is the layout file for FilesListFragment. As you can see it has a RecyclerView and Layout that we will show when a folder is empty and doesn’t have and files in it.

fragment_files_list.xml <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:id="@+id/filesRecyclerView" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> <LinearLayout android:id="@+id/emptyFolderLayout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:gravity="center" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent"> <ImageView android:layout_width="200dp" android:layout_height="200dp" android:background="@drawable/background_circle" android:padding="40dp" android:src="@drawable/ic_folder_dark_24dp" /> <TextView android:layout_width="wrap_content" android:layout_marginTop="16dp" android:layout_height="wrap_content" android:textSize="16sp" android:textStyle="bold" android:text="There is nothing here!"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="12sp" android:text="Empty Folder."/> </LinearLayout> </android.support.constraint.ConstraintLayout> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 <? xml version = "1.0" encoding = "utf-8" ?> < android . support . constraint . ConstraintLayout xmlns : android = "http://schemas.android.com/apk/res/android" xmlns : app = "http://schemas.android.com/apk/res-auto" android : layout_width = "match_parent" android : layout_height = "match_parent" > < android . support . v7 . widget . RecyclerView android : id = "@+id/filesRecyclerView" android : layout_width = "match_parent" android : layout_height = "match_parent" app : layout_behavior = "@string/appbar_scrolling_view_behavior" / > < LinearLayout android : id = "@+id/emptyFolderLayout" android : layout_width = "wrap_content" android : layout_height = "wrap_content" android : orientation = "vertical" android : gravity = "center" app : layout_constraintBottom_toBottomOf = "parent" app : layout_constraintLeft_toLeftOf = "parent" app : layout_constraintRight_toRightOf = "parent" app : layout_constraintTop_toTopOf = "parent" > < ImageView android : layout_width = "200dp" android : layout_height = "200dp" android : background = "@drawable/background_circle" android : padding = "40dp" android : src = "@drawable/ic_folder_dark_24dp" / > < TextView android : layout_width = "wrap_content" android : layout_marginTop = "16dp" android : layout_height = "wrap_content" android : textSize = "16sp" android : textStyle = "bold" android : text = "There is nothing here!" / > < TextView android : layout_width = "wrap_content" android : layout_height = "wrap_content" android : textSize = "12sp" android : text = "Empty Folder." / > < / LinearLayout > < / android . support . constraint . ConstraintLayout >

Sprinkle Kotlin Magic

In the app.gradle file make sure you have added the kotlin-extensions plugin.

apply plugin: 'kotlin-android-extensions' 1 apply plugin : 'kotlin-android-extensions'

We will use Builder pattern in the Fragment to instantiate its objects.

Go ahead and a new Builder class inside FilesListFragment.

class FilesListFragment : Fragment() { companion object { private const val ARG_PATH: String = "com.thetechnocafe.gurleensethi.kotlinfileexplorer.fileslist.path" } class Builder { var path: String = "" fun build(): FilesListFragment { val fragment = FilesListFragment() val args = Bundle() args.putString(ARG_PATH, path) fragment.arguments = args; return fragment } } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_files_list, container, false) } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class FilesListFragment : Fragment ( ) { companion object { private const val ARG_PATH : String = "com.thetechnocafe.gurleensethi.kotlinfileexplorer.fileslist.path" } class Builder { var path : String = "" fun build ( ) : FilesListFragment { val fragment = FilesListFragment ( ) val args = Bundle ( ) args . putString ( ARG_PATH , path ) fragment . arguments = args ; return fragment } } override fun onCreateView ( inflater : LayoutInflater , container : ViewGroup ? , savedInstanceState : Bundle ? ) : View ? { return inflater . inflate ( R . layout . fragment_files_list , container , false ) } }

In the companion object of FilesListFragment add a build function that takes in an extension function on Builder applies it on a new Builder instance and calls the build, method to return the instance of FilesListFragment.

class FilesListFragment : Fragment() { companion object { private const val ARG_PATH: String = "com.thetechnocafe.gurleensethi.kotlinfileexplorer.fileslist.path" fun build(block: Builder.() -> Unit) = Builder().apply(block).build() } class Builder { var path: String = "" fun build(): FilesListFragment { val fragment = FilesListFragment() val args = Bundle() args.putString(ARG_PATH, path) fragment.arguments = args; return fragment } } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_files_list, container, false) } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class FilesListFragment : Fragment ( ) { companion object { private const val ARG_PATH : String = "com.thetechnocafe.gurleensethi.kotlinfileexplorer.fileslist.path" fun build ( block : Builder . ( ) -> Unit ) = Builder ( ) . apply ( block ) . build ( ) } class Builder { var path : String = "" fun build ( ) : FilesListFragment { val fragment = FilesListFragment ( ) val args = Bundle ( ) args . putString ( ARG_PATH , path ) fragment . arguments = args ; return fragment } } override fun onCreateView ( inflater : LayoutInflater , container : ViewGroup ? , savedInstanceState : Bundle ? ) : View ? { return inflater . inflate ( R . layout . fragment_files_list , container , false ) } }

The concept is relatively simple here, the build functions takes an extension function on Builder so you have access to all variables in the Builder class, then you create a new Builder instance and apply this function on it, which will set the variables to whatever value was assigned in the extension function. These are also known as receiver functions. Lets build and set this Fragment in MainActivity.

MainActivity.kt class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) window.decorView.systemUiVisibility = window.decorView.systemUiVisibility.or(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) setContentView(R.layout.activity_main) if (savedInstanceState == null) { val filesListFragment = FilesListFragment.build { path = Environment.getExternalStorageDirectory().absolutePath } supportFragmentManager.beginTransaction() .add(R.id.container, filesListFragment) .addToBackStack(Environment.getExternalStorageDirectory().absolutePath) .commit() } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class MainActivity : AppCompatActivity ( ) { override fun onCreate ( savedInstanceState : Bundle ? ) { super . onCreate ( savedInstanceState ) window . decorView . systemUiVisibility = window . decorView . systemUiVisibility . or ( View . SYSTEM_UI_FLAG_LIGHT_STATUS_BAR ) setContentView ( R . layout . activity_main ) if ( savedInstanceState == null ) { val filesListFragment = FilesListFragment . build { path = Environment . getExternalStorageDirectory ( ) . absolutePath } supportFragmentManager . beginTransaction ( ) . add ( R . id . container , filesListFragment ) . addToBackStack ( Environment . getExternalStorageDirectory ( ) . absolutePath ) . commit ( ) } } }

Initially the path will to the user’s public directory. Below is the layout file of MainActivity.

<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout 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:id="@+id/coordinatorLayout" android:layout_height="match_parent" android:background="@color/colorPrimaryDark" tools:context=".main.MainActivity"> <FrameLayout app:layout_behavior="@string/appbar_scrolling_view_behavior" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/container"> </FrameLayout> </android.support.design.widget.CoordinatorLayout> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <? xml version = "1.0" encoding = "utf-8" ?> < android . support . design . widget . CoordinatorLayout 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 : id = "@+id/coordinatorLayout" android : layout_height = "match_parent" android : background = "@color/colorPrimaryDark" tools : context = ".main.MainActivity" > < FrameLayout app : layout_behavior = "@string/appbar_scrolling_view_behavior" android : layout_width = "match_parent" android : layout_height = "match_parent" android : id = "@+id/container" > < / FrameLayout > < / android . support . design . widget . CoordinatorLayout >

Your application might crash when you run it, because we haven’t yet request file permission on runtime, we will do that later, for time being go to Settings > Apps > Kotlin File Explorer > Permissions, and grant the files permission. Re run this app, it should now work perfectly.

Reading files at path

Before we start reading files, lets do some set up!

In a folder named common, create a new enum named FileType. This enum will help us denote the file type of current file, whether is a directory or a simple file.

FileType.kt enum class FileType { FILE, FOLDER; companion object { fun getFileType(file: File) = when (file.isDirectory) { true -> FOLDER false -> FILE } } } 1 2 3 4 5 6 7 8 9 10 11 enum class FileType { FILE , FOLDER ; companion object { fun getFileType ( file : File ) = when ( file . isDirectory ) { true -> FOLDER false -> FILE } } }

Create a new data class named FileModel, this class will contain all the data we require related to a file.

FileModel.kt data class FileModel( val path: String, val fileType: FileType, val name: String, val sizeInMB: Double, val extension: String = "", val subFiles: Int = 0 ) 1 2 3 4 5 6 7 8 data class FileModel ( val path : String , val fileType : FileType , val name : String , val sizeInMB : Double , val extension : String = "" , val subFiles : Int = 0 )

Now create a new file named FileUtils, this file will contain all of the code related to reading, creating, deleting, copying and moving files.

Let’s add a function to FileUtils that reads all the files from a path. You can do that simple create an instance of File with the given path and call listFiles() on it. We will also add two extra parameters, once to toggle the viability of hidden files(files starting with a ‘.’), and other to view just folder.

fun getFilesFromPath(path: String, showHiddenFiles: Boolean = false, onlyFolders: Boolean = false): List<File> { val file = File(path) return file.listFiles() .filter { showHiddenFiles || !it.name.startsWith(".") } .filter { !onlyFolders || it.isDirectory } .toList() } 1 2 3 4 5 6 7 fun getFilesFromPath ( path : String , showHiddenFiles : Boolean = false , onlyFolders : Boolean = false ) : List < File > { val file = File ( path ) return file . listFiles ( ) . filter { showHiddenFiles || ! it . name . startsWith ( "." ) } . filter { ! onlyFolders || it . isDirectory } . toList ( ) }

In the same FileUtils let’s create a function that converts List<File> to List<FileModel>. We will also add a function convert the file size of MB.

fun getFileModelsFromFiles(files: List<File>): List<FileModel> { return files.map { FileModel(it.path, FileType.getFileType(it), it.name, convertFileSizeToMB(it.length()), it.extension, it.listFiles()?.size ?: 0) } } fun convertFileSizeToMB(sizeInBytes: Long): Double { return (sizeInBytes.toDouble()) / (1024 * 1024) } 1 2 3 4 5 6 7 8 9 10 fun getFileModelsFromFiles ( files : List < File > ) : List < FileModel > { return files . map { FileModel ( it . path , FileType . getFileType ( it ) , it . name , convertFileSizeToMB ( it . length ( ) ) , it . extension , it . listFiles ( ) ? . size ? : 0 ) } } fun convertFileSizeToMB ( sizeInBytes : Long ) : Double { return ( sizeInBytes . toDouble ( ) ) / ( 1024 * 1024 ) }

Never miss a post from TheTechnoCafe

Displaying files at path

Now that we are done getting a list of files, lets show them in the RecyclerView in FilesListFragment.

Create a layout file for a single recycler view item named item_recycler_file.xml.

item_recycler_file.xml <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.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="wrap_content" android:layout_marginBottom="1dp" android:background="@color/colorPrimary" android:foreground="?selectableItemBackground" android:padding="16dp"> <TextView android:id="@+id/nameTextView" android:layout_width="0dp" android:layout_height="wrap_content" android:textSize="20sp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" tools:text="Pictuers" /> <TextView android:id="@+id/folderTextView" android:layout_width="0dp" android:layout_height="wrap_content" android:text="(Folder)" android:textSize="12sp" android:visibility="gone" app:layout_constraintLeft_toLeftOf="@id/nameTextView" app:layout_constraintRight_toRightOf="@id/nameTextView" app:layout_constraintTop_toBottomOf="@id/nameTextView" /> <TextView android:id="@+id/totalSizeTextView" android:layout_width="0dp" android:layout_height="wrap_content" android:text="4 MB" android:textSize="12sp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@id/folderTextView" /> </android.support.constraint.ConstraintLayout> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 <? xml version = "1.0" encoding = "utf-8" ?> < android . support . constraint . 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 = "wrap_content" android : layout_marginBottom = "1dp" android : background = "@color/colorPrimary" android : foreground = "?selectableItemBackground" android : padding = "16dp" > < TextView android : id = "@+id/nameTextView" android : layout_width = "0dp" android : layout_height = "wrap_content" android : textSize = "20sp" app : layout_constraintLeft_toLeftOf = "parent" app : layout_constraintRight_toRightOf = "parent" app : layout_constraintTop_toTopOf = "parent" tools : text = "Pictuers" / > < TextView android : id = "@+id/folderTextView" android : layout_width = "0dp" android : layout_height = "wrap_content" android : text = "(Folder)" android : textSize = "12sp" android : visibility = "gone" app : layout_constraintLeft_toLeftOf = "@id/nameTextView" app : layout_constraintRight_toRightOf = "@id/nameTextView" app : layout_constraintTop_toBottomOf = "@id/nameTextView" / > < TextView android : id = "@+id/totalSizeTextView" android : layout_width = "0dp" android : layout_height = "wrap_content" android : text = "4 MB" android : textSize = "12sp" app : layout_constraintLeft_toLeftOf = "parent" app : layout_constraintRight_toRightOf = "parent" app : layout_constraintTop_toBottomOf = "@id/folderTextView" / > < / android . support . constraint . ConstraintLayout >

Now create a adapter for the RecyclerView named FilesRecyclerAdapter.

FilesRecyclerAdapter.java class FilesRecyclerAdapter : RecyclerView.Adapter<FilesRecyclerAdapter.ViewHolder>() { var onItemClickListener: ((FileModel) -> Unit)? = null var onItemLongClickListener: ((FileModel) -> Unit)? = null var filesList = listOf<FileModel>() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.item_recycler_file, parent, false) return ViewHolder(view) } override fun getItemCount() = filesList.size override fun onBindViewHolder(holder: ViewHolder, position: Int) = holder.bindView(position) fun updateData(filesList: List<FileModel>) { this.filesList = filesList notifyDataSetChanged() } inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener, View.OnLongClickListener { init { itemView.setOnClickListener(this) itemView.setOnLongClickListener(this) } override fun onClick(v: View?) { onItemClickListener?.invoke(filesList[adapterPosition]) } override fun onLongClick(v: View?): Boolean { onItemLongClickListener?.invoke(filesList[adapterPosition]) return true } fun bindView(position: Int) { val fileModel = filesList[position] itemView.nameTextView.text = fileModel.name if (fileModel.fileType == FileType.FOLDER) { itemView.folderTextView.visibility = View.VISIBLE itemView.totalSizeTextView.visibility = View.GONE itemView.folderTextView.text = "(${fileModel.subFiles} files)" } else { itemView.folderTextView.visibility = View.GONE itemView.totalSizeTextView.visibility = View.VISIBLE itemView.totalSizeTextView.text = "${String.format("%.2f", fileModel.sizeInMB)} mb" } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 class FilesRecyclerAdapter : RecyclerView . Adapter < FilesRecyclerAdapter . ViewHolder > ( ) { var onItemClickListener : ( ( FileModel ) -> Unit ) ? = null var onItemLongClickListener : ( ( FileModel ) -> Unit ) ? = null var filesList = listOf < FileModel > ( ) override fun onCreateViewHolder ( parent : ViewGroup , viewType : Int ) : ViewHolder { val view = LayoutInflater . from ( parent . context ) . inflate ( R . layout . item_recycler_file , parent , false ) return ViewHolder ( view ) } override fun getItemCount ( ) = filesList . size override fun onBindViewHolder ( holder : ViewHolder , position : Int ) = holder . bindView ( position ) fun updateData ( filesList : List < FileModel > ) { this . filesList = filesList notifyDataSetChanged ( ) } inner class ViewHolder ( itemView : View ) : RecyclerView . ViewHolder ( itemView ) , View . OnClickListener , View . OnLongClickListener { init { itemView . setOnClickListener ( this ) itemView . setOnLongClickListener ( this ) } override fun onClick ( v : View ? ) { onItemClickListener ? . invoke ( filesList [ adapterPosition ] ) } override fun onLongClick ( v : View ? ) : Boolean { onItemLongClickListener ? . invoke ( filesList [ adapterPosition ] ) return true } fun bindView ( position : Int ) { val fileModel = filesList [ position ] itemView . nameTextView . text = fileModel . name if ( fileModel . fileType == FileType . FOLDER ) { itemView . folderTextView . visibility = View . VISIBLE itemView . totalSizeTextView . visibility = View . GONE itemView . folderTextView . text = "(${fileModel.subFiles} files)" } else { itemView . folderTextView . visibility = View . GONE itemView . totalSizeTextView . visibility = View . VISIBLE itemView . totalSizeTextView . text = "${String.format(" % . 2f ", fileModel.sizeInMB)} mb" } } } }

As you can see we have set up click and long click listener for a single item which we will use in future tutorials. There is an updateData method that updates the content inside the adapter. In the ViewHolder’s bindView method you can see that when the FileType is Folder we have hidden the totalSizeTextView, reason is that android doesn’t actually return the exact size of folder, it works fine for individual files though. So we hide the size in case of FileType.Folder and show a normal TextView with text “Folder”.

Jump into the FilesListFragment and set up the Adapter for RecyclerView.

class FilesListFragment : Fragment() { private lateinit var mFilesAdapter: FilesRecyclerAdapter private lateinit var PATH: String companion object { private const val ARG_PATH: String = "com.thetechnocafe.gurleensethi.kotlinfileexplorer.fileslist.path" fun build(block: Builder.() -> Unit) = Builder().apply(block).build() } class Builder { var path: String = "" fun build(): FilesListFragment { val fragment = FilesListFragment() val args = Bundle() args.putString(ARG_PATH, path) fragment.arguments = args; return fragment } } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_files_list, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val filePath = arguments?.getString(ARG_PATH) if (filePath == null) { Toast.makeText(context, "Path should not be null!", Toast.LENGTH_SHORT).show() return } PATH = filePath initViews() } private fun initViews() { filesRecyclerView.layoutManager = LinearLayoutManager(context) mFilesAdapter = FilesRecyclerAdapter() filesRecyclerView.adapter = mFilesAdapter updateDate() } fun updateDate() { val files = getFileModelsFromFiles(getFilesFromPath(PATH)) if (files.isEmpty()) { emptyFolderLayout.visibility = View.VISIBLE } else { emptyFolderLayout.visibility = View.INVISIBLE } mFilesAdapter.updateData(files) } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 class FilesListFragment : Fragment ( ) { private lateinit var mFilesAdapter : FilesRecyclerAdapter private lateinit var PATH : String companion object { private const val ARG_PATH : String = "com.thetechnocafe.gurleensethi.kotlinfileexplorer.fileslist.path" fun build ( block : Builder . ( ) -> Unit ) = Builder ( ) . apply ( block ) . build ( ) } class Builder { var path : String = "" fun build ( ) : FilesListFragment { val fragment = FilesListFragment ( ) val args = Bundle ( ) args . putString ( ARG_PATH , path ) fragment . arguments = args ; return fragment } } override fun onCreateView ( inflater : LayoutInflater , container : ViewGroup ? , savedInstanceState : Bundle ? ) : View ? { return inflater . inflate ( R . layout . fragment_files_list , container , false ) } override fun onViewCreated ( view : View , savedInstanceState : Bundle ? ) { super . onViewCreated ( view , savedInstanceState ) val filePath = arguments ? . getString ( ARG_PATH ) if ( filePath == null ) { Toast . makeText ( context , "Path should not be null!" , Toast . LENGTH_SHORT ) . show ( ) return } PATH = filePath initViews ( ) } private fun initViews ( ) { filesRecyclerView . layoutManager = LinearLayoutManager ( context ) mFilesAdapter = FilesRecyclerAdapter ( ) filesRecyclerView . adapter = mFilesAdapter updateDate ( ) } fun updateDate ( ) { val files = getFileModelsFromFiles ( getFilesFromPath ( PATH ) ) if ( files . isEmpty ( ) ) { emptyFolderLayout . visibility = View . VISIBLE } else { emptyFolderLayout . visibility = View . INVISIBLE } mFilesAdapter . updateData ( files ) } }

In onViewCreated we first check that there is a PATH provided in the arguments. Then in initViews we set up FilesRecyclerAdapter and in updateData using the functions created in FileUtils.kt we get list of File, convert then to list of FileModel and pass it to our FileRecyclerAdapter. We also check if the list of files is empty then emptyFolderLayout is shown.

Go ahead and run the application now, you should see a list of files and folders.

<< Previous Tutorial – Part 1 – Introduction and Set up.

Next Tutorial – Part 3 – Navigating through File System >>