getFilesDir() vs getExternalFilesDir(), which one is more recommended? - java

As far as I've noticed, using getFilesDir() to store data (camera captures in my case) is somewhat temporary. I say somewhat because if I close and reopen the app, I'm able to access the directory and files list, but not the file itself.
Is my logic wrong or is that by design?
Out of the 2 methods, which is more recommended in :
general
my case (privacy is needed)

Simply,
getFilesDir() refers to internal storage that cannot be accessible outside your application. It's not explorable by the device as well.
getExternalFilesDir() refers to external storage, it's a type of App-specific storage. this can be explorable as you find its directory in
data/data/your package name
In general, you may use external storage as internal storage may be limited.
For privacy, if you need you to file security, use getFilesDir() as it's not accessible outside your application as I mentioned before.

The main difference between the two is:
getFilesDir() - This path will be hidden from the user. This is more secure approach.
getExternalFilesDir() - Accessible by the user.
Received a good documentation on this which provides clear understanding:
http://androidvogella.blogspot.com/2015/12/getfilesdir-vs-getexternalfilesdir-vs.html

Update for the latest Android (currently Android 13)
In the old days getFilesDir() used to mean internal storage, and getExternalFilesDir() used to mean anything plugged in (usually an SD card).
These days phones don't have SD card slots, so the device emulates external storage by grabbing a slice of internal storage for the purpose. So the historic differences - that internal was faster and smaller, and external slower and larger - are generally no longer true.
In both cases apps get scoped storage - i.e. a directory they can access without permissions, which isn't accessible by any other app (though see below). This has been the case since Android 10 (but only enforced in Android 11).
Files stored under getFilesDir() and getExternalFilesDir() will be deleted when the app is uninstalled, but will persist until then. (If you're finding a file disappears before then, you have a different problem. I would suggest posting your code in a separate question).
The only major remaining difference between internal and external is that apps can get request a permission to read/write the entirety of external storage, including files it doesn't own. So don't use external for files that need to remain private to the app.
More information in this article: https://medium.com/#tdcolvin/demystifying-internal-vs-external-storage-in-modern-android-c9c31cb8eeec

Related

Is getExternalFilesDir() private?

I'm trying to store music files users can download with my application, but I don't want them to be publicly visible to 99% of users (I'm excluding rooted devices or special cases)
I'm not worried about the people that go above and beyond to get the audio out by using special tools or a rooted phone.
I am trying to understand the docs but it's not 100% clear to me that getExternalFilesDir() is good to use for that purpose.
Also, the library I'm currently using uses the following line:
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath()
Is this 100% interchangeable if I just replace it with...
Environment.getExternalFilesDir(Environment.DIRECTORY_MUSIC).getAbsolutePath()
(notice I changed both the directory function, as well as the DIRECTORY type (from PICTURES to MUSIC)
Thanks
Is getExternalFilesDir() private?
No. Any user and any app (with READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE) can access external storage.
Is this 100% interchangeable if I just replace it with..
That won't compile due to imbalanced parentheses. Also, the values are different (PICTURES versus MUSIC). Ignoring that, it is "interchangeable" insofar as they will both work and will both be on external storage. However, they are not the same thing. The first one is the user's standard PICTURES directory; the second one is a directory dedicated for pictures that is unique to your app. Also, the former requires WRITE_EXTERNAL_STORAGE on all devices; the latter requires it only for Android 4.3 and below.
I don't want them to be publicly visible to 99% of users (I'm excluding rooted devices or special cases)
Use internal storage (e.g., getFilesDir()).
Use getFilesDir() instead. Thats private app memory.
if you put "." before folder name this folder be hidden
e.g:
String root = Environment.getExternalStorageDirectory().toString();
File myDir = new File(root + "/.myFolderName");

Android clears my application's folder files

I'm working on an application that downloads many files to the SD card.For a device that doesn't have SD Card. It uses the internal storage.
Whenever the storage goes lower than 500Mb, the operating system clears the folder i'm using to store files these files. Did anybody have a problem like this?.
I think that this problem is related to memory swap for the internal storage(When it gets lower than 500MB, it clears the application folder).
Your help is appreciated.
The documentation can help you out here
If you'd like to cache some data, rather than store it persistently,
you should use getCacheDir() to open a File that represents the
internal directory where your application should save temporary cache
files.
When the device is low on internal storage space, Android may delete
these cache files to recover space. However, you should not rely on
the system to clean up these files for you. You should always maintain
the cache files yourself and stay within a reasonable limit of space
consumed, such as 1MB. When the user uninstalls your application,
these files are removed.
The documentation does not say what hard limit is considered while trying to recover space. Whether there is enough space on the internal storage is also not under your control. Repopulate the cache if you find that it is missing and try to maintain a low overhead on the cached files.
As an example I wrote an app a while back that downloads image and sound snippets and caches them. If they are available in the cache I return them. If not I attempt to download them again and put a placeholder image where the actual data is supposed to reside.
Another solution is to store your data in a directory that is not considered a cache by the android OS. However you run the risk of overpopulating the user's disk with data and your data will not be removed when the application has been uninstalled.
In which directory you are saving your downloaded files?
Please take a look at:
http://developer.android.com/reference/android/os/Environment.html
and
http://developer.android.com/training/basics/data-storage/files.html
Also keep in mind the definition of "ExternalStorage":
"Note: don't be confused by the word "external" here. This directory can better be thought as media/shared storage. It is a filesystem that can hold a relatively large amount of data and that is shared across all applications (does not enforce permissions). Traditionally this is an SD card, but it may also be implemented as built-in storage in a device that is distinct from the protected internal storage and can be mounted as a filesystem on a computer."

Android, Not sure if I should store to the internal storage or external storage

I have an app out there on the market already The app is not a game just an informative app with lots of pictures and stats and I received a comment from someone stating that the size of the app being 20Mb is being stored on the "internal storage which isn't fair and that some of it should be stored on the SD card."
Now I am still trying to learn everything about android coding but is this a big deal so that I should move all those images to the external storage like the SD card? Is 20Mb to the internal storage too much or what number in Mb should I look out for to know when to store to an external? I looked at the storage documentation here and it states that the user can modify when they enable USB mass storage to transfer files on a computer, so does this pose a risk to my app breaking if the user modifies/removes/changes anything?
You are looking for installLocation. Just change one thing in the manifest and let users choose where the APK is installed.
Note: By default, your application will be installed on the internal storage and cannot be installed on the external storage unless you define this attribute to be either "auto" or "preferExternal".
This is no different to a computer having two hard drives, a boot disk and a second disk.
Obvious if you can store using the second disk/external storage, you are generally better off as the internal storage has many uses and usually fills up first.
Generally speaking it is best to leave it to the user to decide but I would store on the external storage by default.
For an older phones it is a big deal, believe me. The best option would be to let user choose, which storage he wants to use, in some sort of configuration dialog.
If the app requires those files then do not put them in external storage as that will allow the user to remove them.
If they can be removed/altered then you should put them in external storage.
You could also do a mix of the two so that the size could be reduced without sacrificing the necessary components.

Difference between getExternalFilesDir and getExternalStorageDirectory()

I understand that ExternalFiles is to be used on API 8 and up and getExternalStorageDirectory is for 7 and down. However I am a little confused between the use. For example I wanted to check that a folder that exists and previously you would use something like:
File ChildFolder = new File(Environment.getExternalStorageDirectory() + "/ParentFolder/Child");
However every example I see says to use getExternalFilesDir (null), File.ext. Since I am above API 8 I want to use this method but how do I just check for a folder? I will check for a files existence at another point but for now just want to see if the folders exist??
getExternalFilesDir()
It returns the path to files folder inside Android/data/data/your_package/ on your SD card. It is used to store any required files for your app (e.g. images downloaded from web or cache files). Once the app is uninstalled, any data stored in this folder is gone too.
getExternalStorageDirectory()
It returns the root path to your SD card (e.g mnt/sdcard/). If you save data on this path and uninstall the app, that data won't be lost.
First of all, we need to understand what is difference between Internal Storage, External Storage (aka primary external storage), and Secondary External Storage?
Internal Storage: is storage that is not accessible by the user, except via installed apps (or by rooting their device). Example: data/data/app_packageName
Primary External Storage: In built shared storage which is "accessible by the user by plugging in a USB cable and mounting it as a drive on a host computer". Example: When we say Nexus 5 32 GB.
Secondary External Storage: Removable storage. Example: SD Card.
getExternalFilesDir (String type)
It returns the path to files folder inside Android/data/data/your_package/ on primary external storage. Which is inbuilt storage.
Environment.getExternalStorageDirectory()
It will return the path of the secondary external storage directory
! IMPORTANT UPDATE ! for whoever comes across this question.
As this is a somewhat old question just wanted to provide some additional information. Since KitKat even apps that have WRITE_EXTERNAL_STORAGE permission are only allowed to write to Android/data/data/your_package/ on external storage, a.k.a getExternalFilesDir()
If you will try to write to getExternalStorageDirectory() + "/somefolder/anotherfolder/" you will get a SecurityException on most devices
!! IMPORTANT !!
Environment.getExternalStorageDirectory() is deprecated and Context#getExternalFilesDir(String), MediaStore, or Intent#ACTION_OPEN_DOCUMENT, should be used instead.
This method was deprecated in API level 29.
To improve user privacy, direct access to shared/external storage devices is deprecated. When an app targets Build.VERSION_CODES.Q, the path returned from this method is no longer directly accessible to apps. Apps can continue to access content stored on shared/external storage by migrating to alternatives such as Context#getExternalFilesDir(String), MediaStore, or Intent#ACTION_OPEN_DOCUMENT.
https://developer.android.com/reference/android/os/Environment.html#getExternalStorageDirectory()
Also beginning from Android.M developers need to ask for permissions at run time.
See more details in documentation here and this question
Environment.getExternalStorageDirectory() deprecated in API level 29 java

When caching images and data should you use Internal or External Storage?

I've read this Android save app settings/data in Internal/External Storage but I don't think i've really got an answer.
I'm developing an app where I should store some "cache" data, like a dozen of images and some strings (json).
Initially I was storing all that on the sdcard, (external storage) but later i thought that this could be deprecated by the SDCard deprecation in most recent devices.
After reading a bit, I understood that external storage is not only sdcard, but "a removable storage media (such as an SD card) or an internal (non-removable) storage" so it should not be deprecated but...it's shared space, and there is not ownership over the files stored there, so the first problem was that I was unable to delete them when the app was deleted.
So I changed to the Internal Storage, to avoid having the files/images "public" and also having them removed after app deletion.
Is this the recommended approach?
On devices older with low internal storage but with a lot of space in the SDcard is this a good approach?
My application supports from 1.6 to 4.0 (so far) so I have a lot of legacy devices... and I must have the app working (well) on all.
Looking forward for some interesting answers!
It depends on the type of data you are wanting to store.
You mention it's cached data so myassumption is that it should not matter if for some reason it all disappears. This leads me to believe that you should be using the getCacheDir(). In this case the system will remove files if the cache becomes too big so devices with low internal storage shouldn't present a problem (although it is recommended to manage this your self anyway), it's relatively secure and it will be managed by the app so if there is an uninstall it will be removed.
getExternalCacheDir() was introduced in 2.2 so isn't any use to you unless you would like to detect the version and switch between the 2 caching directories getExternalCacheDir() doesn't provide security so data could be accessed by anyway with access to the SD card. The only reason I could think you might want to do this is because of size of cache you desire but from your description the data doesn't seem excessive.
UPDATED from comment:
although this is a specific case where it's cache...but I don't want
it to be deleted whenever the system wants. It's the kind of cache
that I need the to app decide when to purge. What is the main concern
of storing in on "normal" internal storage without being on the cache
dir?
If you get to the stage where the system is cleaning up internal cached data because storage is so low then you should probably leave it to clean up this sort of app data. By using standard internal data storage you are bypassing this safe guard which would probably create more unpleasant problems than having app data deleted.
If your data is of high importance then I would suggest trying to identify specific data that is more important and managing that separately. If this data you identify needs to be secure then internal storage using files or a db (depending on the data type) seems like your only real option but you would have to be wary of this data building up.
UPDATED from comment
What do you think about using SharedPreferences to save string data?
Is there a limit on SharedPreference string saved size? Is it a (good)
possibility?
I have used shared preferences to store relatively big json strings in the past with no problem, I find it's simpler than using the databases for primitive data types (and strings) where there are limited values to save. However when you have images or lot's of values, management becomes more complex. Also you will have the same problem as you would with standard internal storage in terms of storage space.
I would keep images on the external storage, probably in a "hidden" folder (adding a dot at the beggining of the folder's name: .folder) and also a the Media Scanner "avoider" (.nomedia), because, as you pointed, you want the application to work in old devices, and precisely those devices don't have to much internal memory.
You can also add an option in your application to remove that folder, so in case the user wants to uninstall, he can do that before.
I would use internal storage for cache. This will take away the chance of a user being able to access the files used in your app. I would go for internal

Categories