I am developing an Android application in which I need to get the specified audio file from my website when the user plays it, but I don't want to stream it or download it every time, just the first time. So I was thinking of caching it and play offline whenever the user is in need. So please suggest any method to do so. Or if exists any other method rather than caching like downloading the actual file to file storage and play whenever needed.
If you need to cache files, you should use createTempFile(). For example, the following method extracts the file name from a URL and creates a file with that name in your app's internal cache directory:
private File getTempFile(Context context, String url) {
File file;
try {
String fileName = Uri.parse(url).getLastPathSegment();
file = File.createTempFile(fileName, null,
context.getCacheDir());
} catch (IOException e) {
// Error while creating file
}
return file;
}
You can also see here for more about caching files.
https://developer.android.com/training/data-storage/files.html#WriteCacheFileInternal
Hope this will help.
Related
Currently, we have an app that we are targeting Android 10 and right now are using the legacy storage API. Our app communicates via Bluetooth sensors and reads and writes raw data in CSV files in a subfolder in the main directory, with that subfolder having subfolders for each user.
I know Android 11 will enforce Scoped Storage. I would like to know, is our use case outside of the Scoped Storage requirement? It appears our use case isn't supported by MediaStore. If not, how would we go about this?
MediaStore APIs are just for media files - images, videos, and audio.
You can store all files in the app's private folder and add an export option to your app (maybe compress the whole structure to an archive). So a user will be able to store or send it wherever they want.
In this case, you need to use FileProvider to expose the file from the private directory.
reads and writes raw data in CSV files in a subfolder in the main directory,
For an Android 11 device you can create your own folders an subfolders in the Documents directory of what you call the 'main folder'.
And for using the MediaStore: you can also write any file to that Documents directory. Well in a subfolder if not directly.
I'm in a similar boat. This may help you get started.
public class FirstFragment extends Fragment {
...
public void fauxMakeCsvSurveyFile() {
File appDir = new File(getContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "Field_data");
appDir.mkdirs();
try {
String storageState = Environment.getExternalStorageState();
if (storageState.equals(Environment.MEDIA_MOUNTED)) {
File file = new File(getContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS) + "/Field_data/" + "OutputFile.csv");
FileOutputStream fos = new FileOutputStream(file);
String text = "Hello, world!";
fos.write(text.getBytes());
fos.close();
}
} catch (IOException e) {
Log.e("IOException", "exception in createNewFile() method");
}
}
...
}
I am trying to use Android's internal helpers to get a path from the system for my file first and then put my files where the system wants. Because tomorrow they might change their minds.
I made a simple program to explore this subject. Here is my code;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String path = letsMakeAfile(this, "myFile.txt");
}
private static String letsMakeAfile(Context context, String nameOfFile) {
String strOfFinalPath ="";
//ask the system what path to use...
String strOfContextPath = context.getFilesDir() + "/";
//line above doesnt work without ' + "/" ' or something on the end
//line above records this path: /data/user/0/com.example.filesexperimenting/files/
//this appears to be an invalid path unless "user" is a hidden directory
Log.d("IDIOT", "strOfContextPath: "+ strOfContextPath);
try
{
File file = new File(strOfContextPath, nameOfFile);
if (file.exists() == false) {
file.mkdirs();
//after this line "makes dirs" is file automatically still made and dropped in?
letsMakeAfile(context, nameOfFile);
//I assume not so Ive made a recursive call
}
else
;
//escape recursion....
strOfFinalPath = file.getAbsolutePath();
//Here I record the path where I hope the file is located
Log.d("IDIOT", "strOfFinalPath: "+ strOfFinalPath);
}
catch (Exception e) {
e.printStackTrace();
Log.d("IDIOT", "CATCH ERROR: "+ e.getLocalizedMessage());
}
//runs without a catch
return strOfFinalPath;
}
}
Logcat:
2019-04-09 09:59:22.901 16819-16819/? D/IDIOT: strOfContextPath: /data/user/0/com.example.filesexperimenting/files/
2019-04-09 09:59:22.901 16819-16819/? D/IDIOT: strOfFinalPath: /data/user/0/com.example.filesexperimenting/files
Ultimately I am getting a path of /data/user/0/com.example.filesexperimenting/files/ from context.getFilesDir() which appears to be an invalid path unless "user" is a hidden directory (then why can I see root?). In Device File Explorer under data the only other directories are app, data and local
What am I missing? I'll assume its something with file.makedirs()
Full disclosure, I am a student and there is not a lot out there on this so your replies, while obvious to you at your experience level, should help others. I have some experience with Java and more with C++ but Android is new to me. Thanks in advance!
So, in talking outside of StackExchange it appears that using java.io like I am trying to in the example can cause some problems because of the preset file directories that may be locked or restricted that Java io might not know about.
Android has it's own method openFileOutput(String name, int mode) that has the ability to create the app resource file and directory it belongs in.
Description copied from class: android.content.Context
Actions:
~Open a private file associated with this Context's application package for writing.
~Creates the file if it doesn't already exist.
~No additional permissions are required for the calling app to read or write the returned file.
Params:
~name – The name of the file to open; can not contain path separators.
~mode – Operating mode.
Returns: The resulting FileOutputStream.
Throws: java.io.FileNotFoundException
If you want to be able to navigate to the location of your saved files through the file explorer (either in Android Studio or the Files app on the phone) you should use Context.getExternalFilesDir().
Context.getFilesDir() returns a directory not accessible by anyone BUT the creating application. So if you would like to see what is in this file you would need to open it with the same application that wrote it. IE: Print the contents to the screen after you save it in your app.
Context.getExternalFilesDir() returns a directory completely accessible by anyone and any application. So files created and saved in this external directory can be seen by Android Studio's file explorer as the OP has screenshot or by any application installed on the phone.
What is nice about both of these methods is that as long as you are only accessing files you have created you never need to ask the user for storage permissions Read or Write. If you would like to write to someone else's external files dir then you do.
Source
Check if sdcard is mounted or not.
if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)){
///mounted
}
Get the path of sd card
File dir= new File(android.os.Environment.getExternalStorageDirectory());
walkdir(dir);
ArrayList<String> filepath= new ArrayList<String>();
//list for storing all file paths
public void walkdir(File dir) {
File listFile[] = dir.listFiles();
if (listFile != null) {
for (int i = 0; i < listFile.length; i++) {
if (listFile[i].isDirectory()) {
// if its a directory need to get the files under that directory
walkdir(listFile[i]);
} else {
// add path of files to your arraylist for later use
//Do what ever u want
filepath.add( listFile[i].getAbsolutePath());
}
}
}
}
Try using this:
context.getFilesDir().getParentFile().getPath()
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 am working on a big project with a reasonably big code base. What I want to ask you is hints on how to reliably check where I have to provide a solution to adapt for android 6.0 . What i have used is Analyze > Inspect Code , it does a static analysis of the code and than shows missing checks in the section :
Android > Constant and Resource Type Mismatches. It looks somewhat not the right place to find those problems and that is why I am asking to make sure I am using the right thing and am looking at the right thing, plus I am a bit confused because I have parts of code which write files and i am not getting notified about permissions checks there(is it a normal behaviour?!)
public static boolean write(String folderName, String filename, Object objToWrite) {
// serialize cardModel
FileOutputStream file = null;
ObjectOutputStream o = null;
File dirFile = AppController.getInstance().getApplicationContext().getDir(folderName, Context.MODE_PRIVATE);
try {
// Create archiveDir
File mypath = new File(dirFile, filename);
file = new FileOutputStream(mypath, false);
o = new ObjectOutputStream(file);
o.writeObject(objToWrite);
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
try {
o.close();
file.close();
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
return true;
}
Should I get a warning for Write permission here ?
Another thing that makes me ask is this issue that i have posted on google regarding an Android Studio bug:
Android Studio Bug
Not every write to a file needs a permission - only the one to external storage - this function might also write to the app file space - this needs no permission. Depends on the parameters
Interestingly enough, the definition of what "external storage" vs "internal storage" has changed quite a bit since Android Lollipop. What does this mean?
This call will require you to have storage permissions in the external public directory:
public File getAlbumStorageDir(String albumName) {
// Get the directory for the user's public pictures directory.
File file = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), albumName);
if (!file.mkdirs()) {
Log.e(LOG_TAG, "Directory not created");
}
return file;
}
However, if you do the following, you won't need STORAGE Permissions.
public File getAlbumStorageDir(Context context, String albumName) {
// Get the directory for the app's private pictures directory.
File file = new File(context.getExternalFilesDir(
Environment.DIRECTORY_PICTURES), albumName);
if (!file.mkdirs()) {
Log.e(LOG_TAG, "Directory not created");
}
return file;
}
According to Google:
`If none of the pre-defined sub-directory names suit your files, you can instead call getExternalFilesDir() and pass null. This returns the root directory for your app's private directory on the external storage.
Remember that getExternalFilesDir() creates a directory inside a directory that is deleted when the user uninstalls your app. If the files you're saving should remain available after the user uninstalls your app—such as when your app is a camera and the user will want to keep the photos—you should instead use getExternalStoragePublicDirectory().
Regardless of whether you use getExternalStoragePublicDirectory() for files that are shared or getExternalFilesDir() for files that are private to your app, it's important that you use directory names provided by API constants like DIRECTORY_PICTURES. These directory names ensure that the files are treated properly by the system. For instance, files saved in DIRECTORY_RINGTONES are categorized by the system media scanner as ringtones instead of music.
`
I'm having an issue with opening internal data files in native applications
Its properly important to point out that I'm fairly new to Android development but not new to programming
Setup
I have a mobile Air application which i am running on an Android device. To load PDF's/ play videos within the application I have written a native extension to load the files via their native application.
Problem
When testing the app i found that file's stored in the external storage were loading fine and files in the internal storage were presenting messages from the native applications like cannot play file or cannot open file.( files in internal storage are downloaded and saved on the Air application end ).
This lead me to think its the permission setup within Android.
I know that files within the internal storage are private by default
I have read how to write to a file setting its permission using openFileOutput
but as the file already exists this won't work. I could load the file in and spit it out again but this isn't ideal as will result in what might be unnecessary overhead.
I'm not sure how to proceed, do i need to set a manifest properties on the Air App side? Android App side? both sides? If so which one and where
Or is their a way to change it at run-time, i found the setReadable function but its at API level 9 and i am idealy aiming a little lower than that.
Any help is greatly appreciated
public static void openFile( Activity parentActivity, String filePath, String fileType, String mimeType ) {
//Create the file we are to create
File fileToOpen = new File(filePath);
//Check if the file exists
if( fileToOpen.exists() ) {
//The path of the file we want to open
Uri path = Uri.fromFile(fileToOpen);
//Create a new intent of the file we want to view
Intent intent = new Intent(Intent.ACTION_VIEW);
//Set the path and the mime type for the file
intent.setDataAndType(path, mimeType);
//Remove any other activities
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
//Check that its within the try and catch block
try {
//Open the file by stating a new activity
parentActivity.startActivity(intent);
}
catch (ActivityNotFoundException e) {
//Make a pop-up informing that we don't have an application to open the file
Toast.makeText( parentActivity,"No Application Available to View " + fileType,Toast.LENGTH_SHORT).show();
}
} else {
//Display an alert which will show that the file dosn't exist
Toast.makeText( parentActivity, fileType+" file dosn't exist", Toast.LENGTH_SHORT).show();
}
}