I'm having a hard time figuring out what is going on with my app. Various users have reported that the app generated image files are gone. However, the database data isn't gone and it is stored at the common location Context.getDatabasePath(). Also, all folders are kept intact just images missing.
So I'm thinking there is some routine in Android causing this? Or some other app cleaning up *.png files? I know my app isn't removing them since I don't have any routine to recursively remove all image files.
Also, the parent folder has the .nomedia file so all child folders shouldn't be touched by the gallery right?
I'm storing these files inside the following path structure where %d is a unique number:
getExternalFilesDir()/projects/p_%d/l_%d/%d.png
This is how I get the projects path creates:
public static File getProjectsDir(Context context)
{
// External app directory handled by the OS. Meaning that when the app is uninstalled all
// the data inside this folder will be also removed.
File appRoot = context.getExternalFilesDir(null);
if (null == appRoot) {
Log.e(TAG,"getProjectsDir() -> External storage not accessible!");
return null;
}
File projectsDir = new File(appRoot, "projects");
// create projects directory
if (!projectsDir.exists()) {
if (!projectsDir.mkdir()) {
Log.e(TAG,"getProjectsDir() -> Unable to create projects folder!");
return null;
} else {
File noMediaFile = new File(projectsDir, ".nomedia");
if (!noMediaFile.exists()) {
try {
if (!noMediaFile.createNewFile()) {
Log.e(TAG,"getProjectsDir() -> no media file failed to be created!");
}
} catch (IOException e) {
Log.e(TAG,"getProjectsDir() -> no media file failed to be created!",e);
}
}
}
}
return projectsDir;
}
According to this, it appears that the DownloadManager deletes any files from third-party apps that haven't been accessed (i.e. "UI-Visible") in over 7 days.
The workaround would be to rename the file after it's downloaded so the DownloadManager can no longer track it.
I have a small problem here.
In my application I let the user select a picture from the gallery. I save the path to it before doing anything else.
When the user picks the picture he wants, I want it to be copied in a other folder, and then deleted from the original one.
Well, it kiiinda works. The original picture is deleted, and a copy appears in the other folder.
Buuut. It's still there. The deleted picture can still be seen in the gallery, and the copy can't be seen. When I call Gdx.files.absolute(originalPath).exists() it returns false, and Gdx.files.external(copyPath).exists() it returns true, and I can work with the copy of the picture with no problem.
It looks like the gallery is not updated.
I use this to delete and copy a picture :
public void MoveToCustomFolder() {
if (DoesOriginalPathExist()) {
if (!DoesCopyExist()) {
System.out.println("Copying");
Gdx.files.external("/CustomFolder/" + fileName).write(Gdx.files.absolute(filePath).read(), true);
}
System.out.println("Deleting");
Gdx.files.absolute(filePath).delete();
}
}
filePath being the absolutePath of the original picture in the gallery and fileName the name of the file ("picture.jpg")
I found something during my research. When clear the data of the media storage application, after little time the correct gallery shows up, with no deleted pictures and with copies where they belong.
Also, I do have the WRITE_EXTERNAL_STORAGE permission.
Do you guys know what's wrong ?
Found the solution.
I had to update the Gallery with this function :
public void UpdateGallery(String filePath) {
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(new File(filePath))));
}
Here is my code:
File storageFile = new File("/mnt/extSdCard/DCIM/Camera/IMG_123456789.jpg");
if(storageFile.exists()) {
//copy the file to another folder
MyCopyFoo(storageFile);
if(storageFile.delete()) {
Log.d("Debug", "Success!");//have shown
//refresh sth
}
}
After operation, I checked the system gallery, and there is still a thumbnail in it.
When I restarted the system, it was gone.
I know there is some other way to handle this- the "setting"=>clear sth
What if I wanna deal with it in the code above?
Use MediaScannerConnection to notify the system of modified media files and to regenerate their metadata and thumbnails.
Mediascanner runs as part of the boot sequence so that's why a reboot also fixes the issue.
In my application I am capturing photos and storing into the SD card.
The location of my file is:
photoPath = getExternalFilesDir(Environment.DIRECTORY_PICTURES) + "/"
+ "MyFolder" + "/"+"ImageName";
But when I give clear data using the "device's clear data option" the file is not getting deleted.When I used the Samsung devices, it is getting deleted. But I am facing this problem when I trying with Lenovo devices.
Any one could you please share your suggestions?
I think that option is meant to clear just the data associated with the app internally.
You have chosen to store extra data on the SD card, and I don't think the system is meant to delete it. You should be managing that yourself.
Which brings up the question of why Samsung is able to delete that file? I do not know why.
May be it depends upon the device.
If you want to delete the entire content in a folder, try this code.
void DeleteRecursive(File fileOrDirectory) {
if (fileOrDirectory.isDirectory())
for (File child : fileOrDirectory.listFiles())
DeleteRecursive(child);
fileOrDirectory.delete();
}
I have an application that displays pictures from the internet (showcase for designer work). I start caching my content in the internal cache directory, but the app content could take about 150 MB in cache size. And what android docs says :
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.
So I took a look at the Currents app (Galaxy Nexus) and the cache size for the application is 110 MB. But what's weird is that applications like Google Currents & Google Maps cache the content in something called (USB Storage Data) :
So what is this 'USB Storage Data' that the previous application uses. And if you implement caching in your application, Do you loop over all your application files in cache to get the size every time you need to insert something and then compare and clear it? Or do you keep caching the content until Android decides its time to clean some application cache directory ?
I'm really interested to know what is the flow of managing cache in Android, or at least what other applications do with large content to cache.
Before I get to your question, here's a brief explanation of the two storage types:
Cache
This is an app-specific directory on the filesystem. The intent for this directory is store temporary data your application may need to keep around between sessions, but may not be vital to keep them forever. You typically access this directory with Context.getCacheDir(). This will show up as "Cache" on your app settings.
Files
Like the cache directory, your app also has an app-specific directory for holding files. Files in this directory will exist until the app explicitly deletes them or the app is uninstalled. You typically access this directory with Context.getFilesDir(). This can show up as various things on the app info screen, but in your screenshot this is "USB Storage Data".
NOTE: If you want to explicitly place on external media (typically SD card), you can use Context.getExternalFilesDir(String type).
The Difference
Both directories are specific only to your application (other apps do not have access). One of the differences between the cache and files directory is that if the system gets low on storage, the first place it is going to free resources is from your cache directory. The system will not clear any data from the files directory. Another difference is that the cache directory can typically be cleared manually from the app info screen. The files directory typically can as well, but clearing the files directory will also clear the cache directory.
Which one do I use?
It depends on how vital that data is compared to the lifetime of your app. If you only need data for one session and you doubt you'll ever need to use that data again, then don't use either. Just keep it in memory until you don't need it. If you suspect you'll need to reuse the data between multiple sessions, but you don't have to keep a hard copy, use the cache directory. If you must have this data no matter what, or if it's rather large data that needs persistent storage, use the files directory. Here's some examples I can think of:
Cache - A recently opened email
Once opened, cache the data so when the user wants to read that email again, it loads instantly rather using the network again to retrieve the same data. I don't need to keep this forever, because eventually the user will be finished with the email.
Files - An attachment downloaded from an email
This is an action by the user who is saying "I want to keep this data so I can pull it back up whenever I need it." Therefore, put it in files directory as I don't ever want to delete this file until the user wants it deleted.
When should I clear the cache directory?
From the Context.getCacheDir() javadocs:
Note: 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.
It uses the example of 1 MB, but that may or may not be reasonable for your app. Regardless, you need to set a hard maximum. The reason for this simply comes down to designing a responsible app. So when should you check? I would recommend checking every time you want to put something in the cache directory. Here's a very simple cache manager:
public class CacheManager {
private static final long MAX_SIZE = 5242880L; // 5MB
private CacheManager() {
}
public static void cacheData(Context context, byte[] data, String name) throws IOException {
File cacheDir = context.getCacheDir();
long size = getDirSize(cacheDir);
long newSize = data.length + size;
if (newSize > MAX_SIZE) {
cleanDir(cacheDir, newSize - MAX_SIZE);
}
File file = new File(cacheDir, name);
FileOutputStream os = new FileOutputStream(file);
try {
os.write(data);
}
finally {
os.flush();
os.close();
}
}
public static byte[] retrieveData(Context context, String name) throws IOException {
File cacheDir = context.getCacheDir();
File file = new File(cacheDir, name);
if (!file.exists()) {
// Data doesn't exist
return null;
}
byte[] data = new byte[(int) file.length()];
FileInputStream is = new FileInputStream(file);
try {
is.read(data);
}
finally {
is.close();
}
return data;
}
private static void cleanDir(File dir, long bytes) {
long bytesDeleted = 0;
File[] files = dir.listFiles();
for (File file : files) {
bytesDeleted += file.length();
file.delete();
if (bytesDeleted >= bytes) {
break;
}
}
}
private static long getDirSize(File dir) {
long size = 0;
File[] files = dir.listFiles();
for (File file : files) {
if (file.isFile()) {
size += file.length();
}
}
return size;
}
}
Of course, this could be an expensive operation, so you should plan on caching on a background thread.
Also, this could be as complicated as you need it to be. In my example, I'm assuming all cached files are placed at the root of the cache directory, so I don't check for potential sub-directories. The routine for deleting files can also become more sophisticated, such as deleting files by oldest access date.
One thing to keep in mind when deciding to cache data is that you need to always plan for the case that your cached data no longer exists. Always have a routine in place to retrieve data by external means when your cache doesn't have it in storage. Likewise, always check your cache before retrieve data externally. The purpose of the cache is to cut down on network activity, long processes, and provide a responsive UI in your app. So use it responsibly :)
i thing best way to clearing app cache when activity finish so that every time cache clear when new activity call.
put this code in onDestroy() for clear app cache
#Override
protected void onDestroy() {
super.onDestroy();
try {
trimCache(this);
// Toast.makeText(this,"onDestroy " ,Toast.LENGTH_LONG).show();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void trimCache(Context context) {
try {
File dir = context.getCacheDir();
if (dir != null && dir.isDirectory()) {
deleteDir(dir);
}
} catch (Exception e) {
// TODO: handle exception
}
}
public static boolean deleteDir(File dir) {
if (dir != null && dir.isDirectory()) {
String[] children = dir.list();
for (int i = 0; i < children.length; i++) {
boolean success = deleteDir(new File(dir, children[i]));
if (!success) {
return false;
}
}
}
// The directory is now empty so delete it
return dir.delete();
}
I think the idea behind the cache is to write anything you want on it and Android will manage its size if it gets too high.
You should keep in mind that you can write files to the cache, but always checks if the file is still saved when trying to access it. And let android manage th cache.
Depends on the type of application:
Some applications only use single sessions and don't need to remember any data, so you can clear the cache when you want (some apps even do this automatically in their onStop activity)
Most application keep your data because they remember your settings, the account you have used to log in,... In this case, it's best to only clear the cache when you don't use the application a lot.
Also:
So i took a look at Chrome app (Galaxy Nexus) and the cache size for the application is 110 MB. But what wired is that applications like Google current & Google maps cache the content in something called (USB Storage Data) :
AFAIK, Usb storage data has a different use from cache: the storage is to store program specific information (like maps for a GPS app), the cache is used to store user specific information (like logins)
In case of google maps: I assume they store map data in the usb storage, and keep your settings and search history in the cache ==> map data is application specific, settings and search history are user specific
According to the documentation the system will clear the cache when the device is low on internal storage. Since API8 you have getExternalCacheDir() method that i think useful since i read you can have around 150MB of data but the drawback of the external cache it's that you will have to clean your cache directory yourself if it's get too big.