Been stuck on this for a while now and have no clue. I'm trying to write some objects to file for an app I'm making but keep getting the file not found exception. Here are the methods for write & read that I'm using.
I get the log to say read is starting, but after that I get the error and get no more logs.
private void loadData() throws IOException, ClassNotFoundException {
// Will run and load all data from the config file into the app's memory
Log.d("READ:", "reading starting");
FileInputStream fileInputStream = new FileInputStream("config");
ObjectInputStream oIS = new ObjectInputStream(fileInputStream);
Object[] output = new Object[4];
for (int i=0; i<4; i++) {
output[i] = oIS.readObject();
Log.d("READ:", output[i].toString());
}
oIS.close();
fileInputStream.close();
return;
}
public void writeData() throws IOException {
FileOutputStream fOut = openFileOutput("config", Context.MODE_PRIVATE);
ObjectOutputStream oOut = new ObjectOutputStream(fOut);
Log.d("writeData:", "streamsOpened");
oOut.writeInt(this.targetINR);
oOut.writeObject(this.inrReadings);
oOut.writeObject(this.weeklyDoses);
oOut.writeObject(this.alarmTime);
Log.d("writeData:", "objectsWritten");
oOut.close();
fOut.close();
Log.d("writeData:", "Streams closed, write finished");
return;
}
Heres the code that calls these methods.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_launcher);
inrReadings = new HashMap<Calendar, Integer>();
weeklyDoses = new HashMap<Calendar, Integer>();
TextView debug = (TextView) findViewById(R.id.textView) ;
debug.setText("Vars init");
targetINR = 2;
inrReadings.put(Calendar.getInstance(), 2);
weeklyDoses.put(Calendar.getInstance(), 2);
alarmTime = Calendar.getInstance();;
isStoragePermissionGranted();
/* try {
writeData();
} catch (IOException e) {
e.printStackTrace();
debug.setText(debug.getText() + " errorWrite");
Log.d("writeData:", "ioException");
}
try {
loadData();
} catch (IOException e) {
e.printStackTrace();
Log.d("readData:", "ioException");
debug.setText(debug.getText() + " errorRead");
} catch (ClassNotFoundException e) {
e.printStackTrace();
Log.d("readData:", "ioException");
debug.setText(debug.getText() + " errorClassNotFound");
}
*/
}
Here are the two permision check methods:
public boolean isStoragePermissionGranted() {
if (Build.VERSION.SDK_INT >= 23) {
if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
Log.v("Perms:","Permission is granted now");
return true;
} else {
Log.v("Perms:","Permission is revoked");
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
return false;
}
}
else { //permission is automatically granted on sdk<23 upon installation
Log.v("Perms:","Permission is granted already");
return true;
}
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(grantResults[0]== PackageManager.PERMISSION_GRANTED){
Log.v("Perms:","Permission: "+permissions[0]+ "was "+grantResults[0]);
// User has granted the access. Now you can initiate the file writing.
try {
writeData();
} catch (IOException e) {
e.printStackTrace();
Log.v("Write:", "ioError");
}
MediaScannerConnection.scanFile(this,
new String[]{file.toString()}, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.i("ExternalStorage", "Scanned " + path + ":");
}
});
try {
loadData();
} catch (IOException e) {
e.printStackTrace();
Log.v("Read:", "ioError");
} catch (ClassNotFoundException e) {
e.printStackTrace();
Log.v("Read:", "ClassNotFound");
}
}
}
Full error log here: https://pastebin.com/dhxnXyUg
New error log: https://pastebin.com/Nq0Kh1Au
**Edit:
Fixed it with a work around, see answers.**
I think you have not added the following permission in your AndroidManifest.xml file.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
If you are using the latest version of Android SDK in your device, then you have to request for permission from the user as well. Here's how you can request the permission to write external storage from user.
public boolean isStoragePermissionGranted() {
if (Build.VERSION.SDK_INT >= 23) {
if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
Log.v(TAG,"Permission is granted");
return true;
} else {
Log.v(TAG,"Permission is revoked");
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
return false;
}
}
else { //permission is automatically granted on sdk<23 upon installation
Log.v(TAG,"Permission is granted");
return true;
}
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(grantResults[0]== PackageManager.PERMISSION_GRANTED){
Log.v(TAG,"Permission: "+permissions[0]+ "was "+grantResults[0]);
// User has granted the access. Now you can initiate the file writing.
writeData();
}
}
Update
I can see that you are trying to access the file immediately after the file is created. In case of doing that, you need to scan the file before you access the newly created file.
// Tell the media scanner about the new file so that it is
// immediately available to the user.
MediaScannerConnection.scanFile(this,
new String[]{file.toString()}, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.i("ExternalStorage", "Scanned " + path + ":");
}
});
I think you need to modify your writeData function like the following.
public void writeData() throws IOException {
FileOutputStream fOut = openFileOutput("config", Context.MODE_PRIVATE);
ObjectOutputStream oOut = new ObjectOutputStream(fOut);
Log.d("writeData:", "streamsOpened");
oOut.writeInt(this.targetINR);
oOut.writeObject(this.inrReadings);
oOut.writeObject(this.weeklyDoses);
oOut.writeObject(this.alarmTime);
Log.d("writeData:", "objectsWritten");
oOut.close();
fOut.close();
Log.d("writeData:", "Streams closed, write finished");
MediaScannerConnection.scanFile(this,
new String[]{"/data/data/" + "com.example.yourpackage" + "/config" }, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.i("ExternalStorage", "Scanned " + path + ":");
}
});
return;
}
And the loadData function should be.
private void loadData() throws IOException, ClassNotFoundException {
// Will run and load all data from the config file into the app's memory
Log.d("READ:", "reading starting");
FileInputStream fileInputStream = new FileInputStream("/data/data/" + "com.example.yourpackage" + "/config");
ObjectInputStream oIS = new ObjectInputStream(fileInputStream);
Object[] output = new Object[4];
for (int i=0; i<4; i++) {
output[i] = oIS.readObject();
Log.d("READ:", output[i].toString());
}
oIS.close();
fileInputStream.close();
return;
}
Replace com.example.yourpackage with the package name that you have for your project.
I fixed it in the end, without implementing the onRequestPermision() etc. I just simplified the object write by getting it only write one object (an array of objects). That array has all the values needed stored inside it. Bit of a workaround but it simplifies the writing process!
Related
This related with my previous question after I changed readFile and make it read from URI for devices running in android 11 and above I got ANR error while I tried to read file
gif showing the error
this my full code
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_CODE_DOC = 1;
private static final String TAG = "MainActivity";
private ActivityMainBinding activityMainBinding = null;
private File file;
private Uri selectedFileURI;
BufferedReader bufferedReader;
InputStream inputStream;
FileReader fileReader;
#Override
protected void onDestroy() {
super.onDestroy();
activityMainBinding = null;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activityMainBinding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(activityMainBinding.getRoot());
}
#Override
protected void onStart() {
super.onStart();
activityMainBinding.textView.setMovementMethod(new ScrollingMovementMethod());
activityMainBinding.browseButton.setOnClickListener(view -> {
browseDocuments();
});
activityMainBinding.read.setOnClickListener(view -> {
if (TextUtils.isEmpty(activityMainBinding.editTextPath.getText())) {
activityMainBinding.editTextPath.setError("The file path cannot be empty");
} else {
readFile();
}
});
activityMainBinding.clear.setOnClickListener(view -> activityMainBinding.textView.setText(null));
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_DOC && resultCode == Activity.RESULT_OK) {
try {
if (data != null) {
selectedFileURI = data.getData();
file = new File(selectedFileURI.getPath());
activityMainBinding.editTextPath.setText(file.getAbsolutePath());
Log.d(TAG, "onActivityResult: " + file.getAbsolutePath());
} else {
Toast.makeText(this, "Allow permission for storage access!", Toast.LENGTH_SHORT).show();
}
String mimeType = getContentResolver().getType(selectedFileURI);
Log.i("Type of file", mimeType + "");
} catch (Exception exception) {
if (exception.getMessage() != null) {
Log.e("test Exception", exception.getMessage());
} else if (exception.getCause() != null) {
Log.e("test Exception", Objects.requireNonNull(exception.getCause()).toString());
}
}
}
}
public String getPath(Uri uri) {
String[] projection = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
if (cursor == null) return null;
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String s = cursor.getString(column_index);
cursor.close();
return s;
}
private void readFile() {
try {
StringBuilder sb = new StringBuilder();
String line;
if (SDK_INT >= Build.VERSION_CODES.R) {
inputStream = getContentResolver().openInputStream(selectedFileURI);
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
} else {
fileReader = new FileReader(file);
bufferedReader = new BufferedReader(fileReader);
}
while ((line = bufferedReader.readLine()) != null) {
sb.append(line).append("\n");
}
activityMainBinding.textView.setText(sb.toString());
if(inputStream != null) {
inputStream.close();
}else if(bufferedReader != null) {
bufferedReader.close();
}else if(fileReader != null) {
fileReader.close();
}
} catch (IOException e) {
Log.e("IOException", e.getMessage());
Log.e("IOException2", e.getCause() + "");
Log.e("IOException3", "exception", e);
Toast.makeText(MainActivity.this, "Cannot read this file", Toast.LENGTH_LONG).show();
}
}
private boolean checkPermission() {
if (SDK_INT >= Build.VERSION_CODES.R) {
return Environment.isExternalStorageManager();
} else {
int result = ContextCompat.checkSelfPermission(this, READ_EXTERNAL_STORAGE);
int result1 = ContextCompat.checkSelfPermission(this, WRITE_EXTERNAL_STORAGE);
return result == PackageManager.PERMISSION_GRANTED && result1 == PackageManager.PERMISSION_GRANTED;
}
}
private void requestPermission() {
if (SDK_INT >= Build.VERSION_CODES.R) {
try {
Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
intent.addCategory("android.intent.category.DEFAULT");
intent.setData(Uri.parse(String.format("package:%s", getApplicationContext().getPackageName())));
startActivityForResult(intent, 1);
} catch (Exception e) {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
startActivityForResult(intent, 1);
}
} else {
ActivityCompat.requestPermissions(this, new String[]{READ_EXTERNAL_STORAGE,
WRITE_EXTERNAL_STORAGE}, 1);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQUEST_CODE_DOC:
if (grantResults.length > 0) {
boolean READ_EXTERNAL_STORAGE = grantResults[0] == PackageManager.PERMISSION_GRANTED;
boolean WRITE_EXTERNAL_STORAGE = grantResults[1] == PackageManager.PERMISSION_GRANTED;
if (READ_EXTERNAL_STORAGE && WRITE_EXTERNAL_STORAGE) {
readFile();
} else {
Toast.makeText(this, "Allow permission for storage access!", Toast.LENGTH_SHORT).show();
}
}
break;
}
}
private void browseDocuments() {
if (!checkPermission()) {
requestPermission();
} else {
String[] mimeTypes =
{"text/plain", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"application/vnd.ms-powerpoint", "application/vnd.openxmlformats-officedocument.presentationml.presentation",
"application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"textView/plain",
"application/pdf"};
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
setResult(Activity.RESULT_OK);
intent.setType("*/*");
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
startActivityForResult(Intent.createChooser(intent, "ChooseFile"), REQUEST_CODE_DOC);
}
}
}
That's because you reading files on the Main UI thread which blocks it and causes ANR until is finished, you need to do this work on a background thread, I suggest to take look at the answers on this question even it's old "since 10 years approximately" but it's a good place to start trying, you will find some methods to do the process in background threads like AsyncTask, Callbacks and Executors all this ways can help you to do the fix the issue, but I'll focus in my answer on the newest and recommended way is using "RX Java" I suggest to take look at this RxJava Tutorial you will learn more about it.
let's start to fix this
Add Rx Java dependencies to your project
in build.gradle(app)
implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
// Because RxAndroid releases are few and far between, it is recommended you also
// explicitly depend on RxJava's latest version for bug fixes and new features.
// (see https://github.com/ReactiveX/RxJava/releases for latest 3.x.x version)
implementation 'io.reactivex.rxjava3:rxjava:3.0.3'
in read button onClick create a new Observable and call method readFile on it,
the subscribeOn it's defines the thread that the observable will work on it I choosed Schedulers.computation() because you will not be able to determine the size of the doc/text file or How long this process will take, but you can choose other threads like Schedulers.io(), in observeOn you added the thread that observer will work on it, in your case, it's the main thread, and finally call subscribe to connect observable with the observer, I also suggest to add progressBar on your layout to show it while reading the file and hide it when finished the process
activityMainBinding.read.setOnClickListener(view -> {
if (TextUtils.isEmpty(activityMainBinding.editTextPath.getText())) {
activityMainBinding.editTextPath.setError("The file path cannot be empty");
} else {
Observable.fromCallable(this::readFile)
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Object>() {
#Override public void onSubscribe(Disposable d) {
activityMainBinding.progressBar.setVisibility(View.VISIBLE);
}
#Override public void onNext(Object o) {
if(o instanceof StringBuilder){
activityMainBinding.textView.setText((StringBuilder) o);
}
}
#Override public void onError(Throwable e) {
}
#Override public void onComplete() {
activityMainBinding.progressBar.setVisibility(View.INVISIBLE);
}
});
}
});
also, I would suggest you if the file is PDF use AndroidPdfViewer library it makes a lot easier for you and you will not need all these permissions to read PDF files, you can check these this article to learn more about it.
The major problem is caused by blocking the main thread.
You are reading from memory, which is usually taking some time. You are doing it on the main thread, which is used for all UI operations (layout, detecting inputs etc.). While you are occupying it, no rendering or input detection can happen. That is why you are seeing the ANR warning.
To solve your problem, you need to put your work to a background thread. There are several ways to do so.
This is a good starting point. Also that one, if you are running tasks frequently.
Now to give you a quick solution to your problem, you can create a class to do your work:
public class ReadFile extends Worker
{
private File file;
private BufferedReader bufferedReader;
private InputStream inputStream;
private FileReader fileReader;
public ReadFile(#NonNull Context context, #NonNull WorkerParameters workerParams)
{
super(context, workerParams);
}
#NonNull
#Override
public Result doWork()
{
try
{
StringBuilder sb = new StringBuilder();
String line;
if (SDK_INT >= Build.VERSION_CODES.R)
{
Uri uri = Uri.parse(getInputData().getString("URI"));
inputStream = getApplicationContext().getContentResolver().openInputStream(uri);
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
}
else
{
fileReader = new FileReader(file);
bufferedReader = new BufferedReader(fileReader);
}
while ((line = bufferedReader.readLine()) != null)
{
sb.append(line).append("\n");
}
if (inputStream != null)
{
inputStream.close();
}
else if (bufferedReader != null)
{
bufferedReader.close();
}
else if (fileReader != null)
{
fileReader.close();
}
Data myData = new Data.Builder()
.putString("text", sb.toString())
.build();
return Result.success(myData);
}
catch (IOException e)
{
Log.e("IOException", e.getMessage());
Log.e("IOException2", e.getCause() + "");
Log.e("IOException3", "exception", e);
return Result.failure();
}
}
}
If you are using an inner class of your activity, just make sure you are not using any fields in the UI thread, that you are using inside the worker as well. If you do so, you need to synchronize them. That's why I used input and output data in the example.
Then finally in your activity call:
Data myData = new Data.Builder()
.putString("URI", selectedFileURI.toString())
.build();
OneTimeWorkRequest readFile = new OneTimeWorkRequest.Builder(ReadFile.class).setInputData(myData).build();
WorkManager.getInstance(getContext()).enqueue(readFile);
WorkManager.getInstance(getContext()).getWorkInfoByIdLiveData(readFile.getId()).observe(this, info ->
{
String myResult = info.getOutputData().getString("text");
activityMainBinding.textView.setText(myResult);
});
this is because you are using the main thread to handle a lengthy operations
(ANR) error stands for Application Not Responding and this is happening because the main thread handle the application UI and other important staff , but you try to do a lengthy operation by get the image so this makes the main thread unable to manage the UI and the main app.
that's why this message appear to make you chose between waiting for the main thread to be ready for the UI or to close the app.
a good solution is to make this lengthy operation (get the image) handled by another thread , so you need to create a thread that will work with the operation and when the mission completed you need to switch back to the main thread so you can apply the changes on the UI.
Note that you can not touch or change the UI from any thread but the Main Thread because the main thread is the responsible for the application UI , that's why you need to switch back to the main thread after the mission complete.
I am trying to create a text document with user inputted information but nothing is being created... Here is the code I have used for the button click:
runnerTestResultBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (capitanPasswordValidate()& permissionGranted) {
if (capitanPasswordET.getText().toString().equals(capitanPassword)) {
createFile();
} else {
capitanPasswordError.setText("Wrong Password!");
capitanPasswordError.requestFocus();
}
}
}
});
Also, here is the code I am using to create the file:
private void createFile() {
String familiaName = familiaNamesSpinner.getSelectedItem().toString();
String FILE_NAME = familiaName + "_Runner_Test_Results.txt";
String cafeteroTestResultString = runnerTestResult1.getText().toString();
FileOutputStream fos = null;
File file = new File(FILE_NAME);
try {
capitanPasswordError.setText("");
fos = new FileOutputStream(file);
fos.write(cafeteroTestResultString.getBytes());
fos.close();
Toast.makeText(this, "worked", Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(this, "did not work", Toast.LENGTH_SHORT).show();
} finally {
if (fos != null) try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Just a side note, I am making it so the user selects a choice from a spinner View in order to track down which file belongs to which person. it is under familiaName and will be part of the name of the file created. any feedback would be amazing, thank you!!
You must check for permissions before reading or writing a file, Please add permission requests to manifests and request permissions for READ, WRITE operations at runtime,
Here i have a simple solution, - (Multiple permission checking)
String[] permissions = new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE}; // Here i used multiple permission check
Then call it in Oncreate
if (checkPermissions()) {
// permissions granted.
getCallDetails();
}
Finally, copy the below code
private boolean checkPermissions() {
int result;
List<String> listPermissionsNeeded = new ArrayList<>();
for (String p : permissions) {
result = ContextCompat.checkSelfPermission(getApplicationContext(), p);
if (result != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(p);
}
}
if (!listPermissionsNeeded.isEmpty()) {
ActivityCompat.requestPermissions(this, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]), MULTIPLE_PERMISSIONS);
return false;
}
return true;
}
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case MULTIPLE_PERMISSIONS: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permissions granted.
getCallDetails(); // Now you call here what ever you want :)
} else {
String perStr = "";
for (String per : permissions) {
perStr += "\n" + per;
}
// permissions list of don't granted permission
}
return;
}
}
}
I'm trying to make an app that detects motion and takes picture when the motion is detected. Its saving the picture when I don't try to save it in the directory(folder). But when I try it with the directory, the picture is not being saved even though the directory is being created successfully.
What changes should I make to the following code in order to make it work:
private void createDirectoryAndSaveFile(String name, Bitmap bitmap) {
File folder = new File(Environment.getExternalStorageDirectory() +
File.separator + "XYX APP");
boolean success = true;
if (!folder.exists()) {
success = folder.mkdirs();
}
if (success) {
// Do something on success
} else {
// Do something else on failure
}
File photo = new File(new File(Environment.getExternalStorageDirectory()+"XYZ APP/"), name+ ".jpg");
if (photo.exists()) {
photo.delete();
}
try {
FileOutputStream out = new FileOutputStream(photo.getPath());
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Note: The file name is generated in the following instruction:
String name = "MotDet_"+String.valueOf(System.currentTimeMillis());
if (bitmap != null) createDirectoryAndSaveFile(name, bitmap);
Update
It works with the following code but not with the code above :
private void save(String name, Bitmap bitmap) {
File photo = new File(Environment.getExternalStorageDirectory(), name + ".jpg");
if (photo.exists()) photo.delete();
try {
FileOutputStream fos = new FileOutputStream(photo.getPath());
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.close();
} catch (java.io.IOException e) {
Log.e("PictureDemo", "Exception in photoCallback", e);
}
}
First of all you missed the FileSeperator before xyz
File photo = new File(folder.getAbsolutePath()+"/XYZ APP/"+ name+ ".jpg");
And your Function becomes
private void createDirectoryAndSaveFile(String name, Bitmap bitmap) {
File folder = new File(Environment.getExternalStorageDirectory() +
File.separator + "XYZ APP");//here you have created different name
boolean success = true;
if (!folder.exists()) {
success = folder.mkdirs();
}
if (success) {
// Do something on success
} else {
// Do something else on failure
}
File photo = new File(folder.getAbsolutePath(), name+ ".jpg");
if (photo.exists()) {
photo.delete();
}
try {
FileOutputStream out = new FileOutputStream(photo.getPath());
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Marshmello comes with RuntimePermissions in order for you to save file in external directory you need to ask permission first, like below code
public boolean isStoragePermissionGranted() {
if (Build.VERSION.SDK_INT >= 23) {
if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
Log.v(TAG,"Permission is granted");
return true;
} else {
Log.v(TAG,"Permission is revoked");
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
return false;
}
}
else { //permission is automatically granted on sdk<23 upon installation
Log.v(TAG,"Permission is granted");
return true;
}
}
permission result callback
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(grantResults[0]== PackageManager.PERMISSION_GRANTED){
Log.v(TAG,"Permission: "+permissions[0]+ "was "+grantResults[0]);
//resume tasks needing this permission
}
}
before saving call isStoragePermissionsGranted() if it returns true proceed saving file.
Try this code :
String partFilename = currentDateFormat();
storeCameraPhotoInSDCard(bp, partFilename);
private String currentDateFormat(){
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HH_mm_ss");
String currentTimeStamp = dateFormat.format(new Date());
return currentTimeStamp;
}
private void storeCameraPhotoInSDCard(Bitmap bitmap, String currentDate){
File outputFile = new File(Environment.getExternalStorageDirectory(), "photo_" + currentDate + ".jpg");
try {
FileOutputStream fileOutputStream = new FileOutputStream(outputFile);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream);
fileOutputStream.flush();
fileOutputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
This code is work for me..Save image to directory.
You have to get permission of external storage at run time in android 6.0 and above to write in SDCard
Read Run time Permission
add in manifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
replace your function with below one
private void createDirectoryAndSaveFile(String name, Bitmap bitmap) {
File folder = new File(Environment.getExternalStorageDirectory() +
File.separator + "XYZ APP");//here you have created different name
boolean success = true;
if (!folder.exists()) {
success = folder.mkdirs();
}
if (success) {
// Do something on success
} else {
// Do something else on failure
}
File photo = new File(folder.getAbsolutePath(), name+ ".jpg"); //use path of above created folder
if (photo.exists()) {
photo.delete();
}
try {
FileOutputStream out = new FileOutputStream(photo.getPath());
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
i seem to be having problems creating folders in LOLLIPOP and up although code works just fine for previous versions
there is no error in the log-cast it simply does not crate the folder can someone help
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
private static Uri getOutputMediaFileUri(int type){
return Uri.fromFile(getOutputMediaFile(type));
}
private static File getOutputMediaFile(int type){
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_MOVIES), "reelyChat/vids");
if(!mediaStorageDir.exists()){
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
mediaStorageDir.mkdirs();
try {
mediaStorageDir.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}else{
if(!mediaStorageDir.mkdirs()){
Log.d("reelyChat", "failed to create directory");
return null;
}
}
}
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile;
if(type == MEDIA_TYPE_VIDEO){
vid_name = "RC_"+my_user_id+"_profile.mp4";
mediaFile = new File(mediaStorageDir.getPath() + File.separator + vid_name);
}else{
return null;
}
return mediaFile;
}
You need write permission at run time.
//Just call this function
getWirtePermissionAndCreateDir();
private void getWirtePermissionAndCreateDir() {
if (Build.VERSION.SDK_INT < 23) {
createDir();
} else {
final String[] PERMISSIONS_STORAGE = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
//Asking request Permissions
ActivityCompat.requestPermissions(mActivity, PERMISSIONS_STORAGE, 9);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
boolean writeAccepted = false;
switch (requestCode) {
case 9:
writeAccepted = grantResults[0] == PackageManager.PERMISSION_GRANTED;
break;
}
if (writeAccepted) {
createDir();
} else {
Toast.makeText(mActivity, "You don't assign permission.", Toast.LENGTH_LONG).show();
}
}
private void createDir(){
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_MOVIES), "reelyChat/vids");
mediaStorageDir.mkdirs();
}
It looks like you have took permissions but not at run time. Device running on Marshmallow or above needs to take permissions at run time.
For more information visit Developer Site
I want my program to download many images (around 500) from the internet and store them in my external storage. Currently when I download a single image, it shows a progressBar and downloads the image properly. However when I am trying to replicate w/ two images, it gives the Toast for "Download complete" for both images being downloaded, however no progressBar for either image is shown and only the first image is properly downloaded.
Here is the code for my onCreate method for activity.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Remove Title bar
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
//force portrait orientation. (No landscape orientation).
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
setContentView(R.layout.activity_quran);
//Instantiate ProgressDialog (Used for downloading quran pages).
myProgressDialog = new ProgressDialog(QuranActivity.this);
myProgressDialog.setMessage("Downloading Quran");
myProgressDialog.setIndeterminate(true);
myProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
myProgressDialog.setCancelable(true);
//execute when the downloader must be fired.
final DownloadTask downloadTask = new DownloadTask(QuranActivity.this);
DownloadTask second = new DownloadTask(getApplicationContext());
myHTTPURL = "https://ia601608.us.archive.org/BookReader/BookReaderImages.php?zip=/10/items/05Quran15LineWhitePageWithVioletBorderWww.Momeen.blogspot.com/05%20Quran%2015%20Line%20[White%20page%20with%20Violet%20border]%20-%20www.Momeen.blogspot.com_jp2.zip&file=05%20Quran%2015%20Line%20[White%20page%20with%20Violet%20border]%20-%20www.Momeen.blogspot.com_jp2/05%20Quran%2015%20Line%20[White%20page%20with%20Violet%20border]%20-%20www.Momeen.blogspot.com_0001.jp2&scale=1&rotate=0";
myHTTPURL2 = "https://ia601608.us.archive.org/BookReader/BookReaderImages.php?zip=/10/items/05Quran15LineWhitePageWithVioletBorderWww.Momeen.blogspot.com/05%20Quran%2015%20Line%20[White%20page%20with%20Violet%20border]%20-%20www.Momeen.blogspot.com_jp2.zip&file=05%20Quran%2015%20Line%20[White%20page%20with%20Violet%20border]%20-%20www.Momeen.blogspot.com_jp2/05%20Quran%2015%20Line%20[White%20page%20with%20Violet%20border]%20-%20www.Momeen.blogspot.com_0002.jp2&scale=1&rotate=0";
//First check if the file has already been created. (Only need to download 1ce, or
//in the case where the user deleted the files, we reinstall them again).
if (isExternalStorageWritable()) {
File makeDirectory = getQuranStorageDir(QuranActivity.this, "Quran_Pages");
for (int i = 0; i < 2; i++) {
Bundle myBundle = new Bundle();
myBundle.putInt("i", i);
if (i == 0) {
downloadTask.execute(myHTTPURL);
try {
downloadTask.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
myProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
downloadTask.cancel(true);
}
});
} else {
/*if (downloadTask.getStatus() == AsyncTask.Status.FINISHED) {
downloadTask.execute(myHTTPURL2);
} else if (downloadTask.getStatus() == AsyncTask.Status.RUNNING) {
try {
downloadTask.execute(myHTTPURL2).wait(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} */
second.execute(myHTTPURL2);
try {
second.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
// downloadTask.execute(myHTTPURL2);
}
}
}
and this is the code for my AsynTask Class.
#TargetApi(Build.VERSION_CODES.FROYO)
private class DownloadTask extends AsyncTask {
private Context context;
private PowerManager.WakeLock myWakeLock;
public DownloadTask(Context context) {
this.context = context;
}
#Override
protected String doInBackground(String... sUrl) {
InputStream input = null;
OutputStream output = null;
HttpURLConnection connection = null;
try {
URL url = new URL(sUrl[0]);
connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("GET");
connection.connect();
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
return "Server returned HTTP " + connection.getResponseCode()
+ " " + connection.getResponseMessage();
}
//Display download percentage.
int fileLength = connection.getContentLength();
//create folder to place the downloaded file in.
// File Path:E:\Android\data\com.syedabdullah.syed.quran_memorization_application
// \files\Quran Memorization Application\Quran_Pictures
//So first create a root folder Quran Memorization Application then inside that
//folder we create another folder named Quran Pictures.
/* File rootFolder = new File(getExternalFilesDir("Quran Memorization Application"),
"Quran_Pages"); */
//Here we insert inside the Quran_Pictures folder the quran_pages.
//String myFileName = "quran_01.jpg";
Bundle y = new Bundle();
int retrievePos = y.getInt("i");
String quranFilePageName = "_" + retrievePos + ".jpg";
// String fileName = "justwork.jpg";
File sup = new File(getExternalFilesDir("Quran Memorization Application"), "Quran_Pages");
File myFile = new File(sup, quranFilePageName);
myFile.createNewFile();
//downlaod the file.
input = connection.getInputStream();
output = new FileOutputStream(myFile);
byte data[] = new byte[4096];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
//allow cancel with back button.
if (isCancelled()) {
input.close();
return null;
}
total += count;
//publish the progress.
if (fileLength > 0) {
publishProgress((int) (total * 100 / fileLength));
}
output.write(data, 0, count);
}
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
intent.setData(Uri.fromFile(myFile));
QuranActivity.this.sendBroadcast(intent);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (output != null) {
output.close();
}
if (input != null) {
input.close();
}
} catch (IOException e) {
e.printStackTrace();
}
if (connection != null) {
connection.disconnect();
}
}
return null;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
//Take CPU lock to prevent CPU from going off if the user presses the power button.
//during download.
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
myWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName());
myWakeLock.acquire();
myProgressDialog.show();
}
#Override
protected void onProgressUpdate(Integer... progress) {
super.onProgressUpdate(progress);
//If we get here length is known, so setIndertimante to false.
myProgressDialog.setIndeterminate(false);
myProgressDialog.setMax(100);
myProgressDialog.setProgress(progress[0]);
}
#Override
protected void onPostExecute(String result) {
myWakeLock.release();
myProgressDialog.dismiss();
if (result != null) {
Toast.makeText(context, "Download error: " + result, Toast.LENGTH_LONG).show();
} else {
Toast.makeText(context, "Download Complete", Toast.LENGTH_SHORT).show();
}
}
} }
I was hoping to have a for loop that would create hundreds of downloadTasks and download all the images I need, and then I would call the get method. However in order for that to work, I first need too know why when I try for 2 images only the first one gets downloaded and why no progressbar shows up. Also if possible if I could get a hint as to how I can make my progressBar update for all the images and not be designed for just 1. Thanks in advance. (Note all URLs are currect.)
Thank you so much! figured out that my loops were suppose to go inside doInBackground. Also to anyone else having a similar issue. To download multiple files and display a decent progressBar, here is a very great tutorial: http://theopentutorials.com/tutorials/android/dialog/android-download-multiple-files-showing-progress-bar/