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."
Related
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
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.
I'm building a dictionary application and I have a problem right now. My application's is 16MB and when I install it on a phone, Database files copies to the data folder and in the manage apps section I see that my application size is 32MB (my app+data folder).
I don't cheat user, I want to say, my app is 16MB, but when user install it , it become 32MB. Why? this is a negative point and I want to solve it. I want my app uses only 16MB in users phone. just that
How I can fix this? I have to read and write in assets folder directly or there is other solution? this is a problem in low storage size phones. how I can fix this?
I am not sure how your database is structured in terms of whether it is a pre-loaded database wherein you just include you .db file with all the data OR is it something where in you push all your DB content with the app and then at the time of app installation you actually install all you data in the DB.
In case of the latter situation you double the size of your app because you already have data content (in files) which you want to use to populate your database (say 16 mb in this case). Then you use these files to actually create your DB file (which is 16mb again) and this doubles the size of the app.
So what you could do is pre-populate your DB content in a .db file and then just use this file directly as the Db file in your app (this will keep it to 16mb). Follow this tutorial :
http://www.reigndesign.com/blog/using-your-own-sqlite-database-in-android-applications/
Hope this helps.
Not sure I fully understand your situation.
Do you have a roughly 16MB dictionary, that is packaged inside your app as string constants in your code or some resource file or something (to make it 16MB) and then, when your app installs or first launches, you also write this dictionary into your app's database?
If so, then now you have 2 copies of your dictionary around to make it 32MB.
To solve this, either keep only one copy in your app, or download the dictionary from somewhere to get it into your database rather than storing it as a constant in your app.
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
My application uses quite a lot of pictures that are downloaded from the internet and cached locally on the Android phone. I am wondering, what is the correct way to save those pictures. There are several ways I see, that are not fully satisfying.
Save them on SD Card in a public folder
Uses up space that wont be freed on uninstall
User can see pics in Gallery
Needs a folder on the sdcard root (you can actually see it while browsing your phone)
Save them on SD Card in a non-public folder
Uses up space that wont be freed on uninstall
Secretly uses space on the SD Card
Save them inside the application
Blows up application size far too much
What is the correct way of locally saving the images of my application to not distract the user and leave no garbage anywhere?
Your best solution is to use:
context.getCacheDir()
This directory is private to the application and will be deleted on uninstall, furthermore the system can delete from this directory for you if the device is running short of space.
Note though that the docs say:
you should not rely on the system
deleting these files for you; you
should always have a reasonable
maximum, such as 1 MB, for the amount
of space you consume with cache files,
and prune those files when exceeding
that space
If you need a lot of space and would rather use the SD card you can call
getExternalCacheDir()
instead. These will also get removed on uninstall, but the system does not monitor the space available in external storage, so won't automatically delete these files if low on space. If using this option you should also check that external storage is available with
Environment.getExternalStorageState()
before attempting to write to it.
You can hide images from the MediaScanner if you put it in a hidden dir (i.e., with a dot prefixed) such as /sdcard/.donotscan/.
Update: As romainguy mentions on twitter this also works if you put a file named .nomedia into the dir.
I think the best way is to use the database.
It does not blow up the application and memory.
The related database is deleted once the application is uninstalled.
Nobody can reach to this files besides your application.
Update: But; If you want to cache only the data, there is a cache manager defined in webkit. CacheManager
I didn't use the package before but the methods seem straight forward to use:
static boolean cacheDisabled()
static boolean endCacheTransaction()
static CacheManager.CacheResult getCacheFile(String url, Map<String, String> headers)
static File getCacheFileBaseDir()
static void saveCacheFile(String url, CacheManager.CacheResult cacheRet)
static boolean startCacheTransaction()
and you can find the usage at Google Gears code
I hope this helps.
If you you don't want to use the CacheManager then use a database or a local (non-SD) file (local files get deleted on a complete uninstall) and register to receive the 'ACTION_DEVICE_STORAGE_LOW' and 'ACTION_DEVICE_STORAGE_OK' broadcast actions. Then you'll know when your application is taking up too much space according to the device and when you need to start deleting pictures. Your application size will still grow, but you will be able to manage the growth and shrinkage.
Just a tip - if you save them on the SD Card, they will be scanned by the MediaScanner and will appear in the users's Gallery (Photos), which you probably don't want. So you probably want to store them on the phone, or somehow tell MediaScanner not to scan them (apparently impossible after a quick Google search.)
Probably best to store a select few in your application's private directory, which will be removed when your application is uninstalled.