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;
}
}
}
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.
Hello I am trying to read and print all the cell values of an excel file using Apache POI library. This is my code:
MainActivity.java
public class MainActivity extends AppCompatActivity {
Button btn;
String name = null;
Uri uri = null;
private static final int STORAGE_PERMISSION_CODE = 101;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = findViewById(R.id.button);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent data = new Intent(Intent.ACTION_OPEN_DOCUMENT);
data.setType("*/*");
data = Intent.createChooser(data, "Choose a file");
launch_activity.launch(data);
}
});
}
ActivityResultLauncher<Intent> launch_activity = registerForActivityResult
(new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
#Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == Activity.RESULT_OK) {
Intent data = result.getData();
Uri uri = null;
if (data != null) {
uri = data.getData();
}
if (uri != null && uri.getScheme().equals("content")) {
try (Cursor returnCursor = getContentResolver().query(uri, null, null, null, null)) {
if (returnCursor != null && returnCursor.moveToFirst()) {
name = returnCursor.getString(returnCursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME));
}
}
}
if(name == null){
if (uri != null) {
name = uri.getPath();
}
int cut = 0;
if (name != null) {
cut = name.lastIndexOf('/');
}
if(cut != 1){
if (name != null) {
name = name.substring(cut + 1);
}
}
}
String[] extension = null;
if (name != null) {
extension = name.split("\\.");
}
if (extension != null && (extension[extension.length - 1].equals("xls") || extension[extension.length - 1].equals("xlsx")))
checkPermission(Manifest.permission.READ_EXTERNAL_STORAGE, STORAGE_PERMISSION_CODE);
else if (extension != null) {
Toast.makeText(MainActivity.this,extension[extension.length - 1]+" file is not supported",Toast.LENGTH_SHORT).show();
}
}
}
});
public static void readExcelFromStorage(Context context, String fileName) {
InputStream fileInputStream = null;
try {
try {
fileInputStream = getContentResolver().openInputStream(uri);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// Create instance having reference to .xls/.xlsx file
Workbook workbook = null;
try {
if (fileInputStream != null) {
workbook = new HSSFWorkbook(fileInputStream);
}
} catch (IOException e) {
e.printStackTrace();
}
// Fetch sheet at position 'i' from the workbook
Sheet sheet = null;
if (workbook != null) {
sheet = workbook.getSheetAt(0);
}
// Iterate through each row
if (sheet != null) {
for (Row row : sheet) {
if (row.getRowNum() > 0) {
// Iterate through all the cells in a row (Excluding header row)
Iterator<Cell> cellIterator = row.cellIterator();
while (cellIterator.hasNext()) {
Cell cell = cellIterator.next();
// Check cell type and format accordingly
switch (cell.getCellType()) {
case Cell.CELL_TYPE_NUMERIC:
Toast.makeText(context.getApplicationContext(), String.valueOf(cell.getNumericCellValue()),Toast.LENGTH_SHORT).show();
break;
case Cell.CELL_TYPE_STRING:
Toast.makeText(context.getApplicationContext(), cell.getStringCellValue(),Toast.LENGTH_SHORT).show();
break;
}
}
}
}
}
} finally {
try {
if (null != fileInputStream) {
fileInputStream.close();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
public void checkPermission(String permission, int requestCode)
{
if (ContextCompat.checkSelfPermission(MainActivity.this, permission) == PackageManager.PERMISSION_DENIED) {
// Requesting the permission
ActivityCompat.requestPermissions(MainActivity.this, new String[] { permission }, requestCode);
}
else {
Toast.makeText(MainActivity.this, "Permission already granted", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onRequestPermissionsResult(int requestCode,
#NonNull String[] permissions,
#NonNull int[] grantResults)
{
super.onRequestPermissionsResult(requestCode,
permissions,
grantResults);
if (requestCode == STORAGE_PERMISSION_CODE) {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(MainActivity.this, "Storage Permission Granted", Toast.LENGTH_SHORT).show();
readExcelFromStorage(MainActivity.this, uri);
} else {
Toast.makeText(MainActivity.this, "Storage Permission Denied", Toast.LENGTH_SHORT).show();
}
}
}
}
AndroidManifest.xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
When I execute my code, I choose my desired excel file (which is inside my internal storage) and then I keep getting this error:
java.io.FileNotFoundException: /storage/emulated/0/Android/data/com.example.uploadipaselectricdata/files/employee_details.xlsx: open failed: ENOENT (No such file or directory)
How do I fix this error? Please help.
I am testing this app on an actual android device
If you are sure the path to the file is correct but still get such an exception, check whether the app has enough permissions to access that location. After all the OS claims that there is no such file, and you won't be able to fix that inside your application code.
I'm not entirely sure what Excel's workbook wants, specifically FileInputStream or just InputStream, you can try opening using the URI the system returned with getContentResolver().openInputStream(uri) and try passing it instead (this is the data returned via Intent.getData().) That should work on API 30 and above as well.
I use system permission.And I announced permission to read and write in sdcard. According to the past, the following writing methods were made. But in Android 8.0+ devices. I always get permission denied at logFile.createNewFile(). But if my file path replace to internal storage is pass.
Looking for the network data, only find a SAF mechanism may provide assistance, but this mechanism is the file manager of the intent machine itself, after returning a URI to perform the function of reading and writing files, the same URI is given to the same funtion Unable to create a new file successfully.(https://github.com/termux/termux-app/issues/812)
I try to use execute function Runtime.getRuntime().exec("push '/storage/emulated/0/eee.txt' '/storage/3630-6236/'"). But it doesn't work,either.
Is there any solutions to write on Android 8.0+ sdcard?Currently trying to use DocumentFile to do.(https://github.com/TeamAmaze/AmazeFileManager/blob/master/app/src/main/java/com/amaze/filemanager/filesystem/HybridFile.java)
private final static String localFullPath = PATH_SDCARD + File.separator + nowFormat + "_log.txt";
public static void logWriter(String logText) {
try {
File logFile = new File(localFullPath);
if (!logFile.exists()) {
if (logFile.createNewFile()) {
Log.d("mkdir", "Create new file: " + localFullPath);
}
}
Date date = new Date(System.currentTimeMillis());
final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.getDefault());
String nowFormat = simpleDateFormat.format(date);
FileWriter fileWriter = new FileWriter(localFullPath, true);
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
bufferedWriter.append("[").append(nowFormat).append("] ").append(logText);
bufferedWriter.newLine();
bufferedWriter.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private void CheckPermission() {
// CheckStoragePermission();
String PERMISSION_WRITE_STORAGE = "android.permission.WRITE_EXTERNAL_STORAGE";
String PERMISSION_READ_PHONE_STATE = "android.permission.READ_PHONE_STATE";
String PERMISSION_ACCESS_FINE_LOCATION = "android.permission.ACCESS_FINE_LOCATION";
String PERMISSION_ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if ((ContextCompat.checkSelfPermission(this, PERMISSION_WRITE_STORAGE) != PackageManager.PERMISSION_GRANTED) ||
(ContextCompat.checkSelfPermission(this, PERMISSION_ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) ||
(ContextCompat.checkSelfPermission(this, PERMISSION_ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) ||
(ContextCompat.checkSelfPermission(this, PERMISSION_READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED)) {
String[] perms = {PERMISSION_WRITE_STORAGE, PERMISSION_READ_PHONE_STATE, PERMISSION_ACCESS_FINE_LOCATION, PERMISSION_ACCESS_COARSE_LOCATION};
int permsRequestCode = 1;
requestPermissions(perms, permsRequestCode);
}
}
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
}
public static String[] getExtSdCardPathsForActivity(Context context) {
List <String> paths = new ArrayList <>();
for (File file : context.getExternalFilesDirs("external")) {
if (file != null) {
int index = file.getAbsolutePath().lastIndexOf("/Android/data");
if (index < 0) {
Log.w(LOG, "Unexpected external file dir: " + file.getAbsolutePath());
} else {
String path = file.getAbsolutePath().substring(0, index);
try {
path = new File(path).getCanonicalPath();
} catch (IOException e) {
// Keep non-canonical path.
}
paths.add(path);
}
}
}
if (paths.isEmpty()) paths.add("/storage/sdcard1");
return paths.toArray(new String[0]);
}
1 Only define permissions in AndroidManifest.xml is not enough, you have to requestPermissions in onCreate #MainActivity.
2 Another way to solve it is to target the sdk version to lower than M, for ex targetSdkVersion 15.
At Android 8+ you have to add also the READ_EXTRERNAL_STORAGE permission
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
if ((checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) ||
(checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)) {
Log.e(getClass().getSimpleName(), "missing permission: external storage");
AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(this, R.style.AlertDialogCustom));
builder.setTitle(getResources().getString(R.string.assign_permissions));
builder.setMessage(getResources().getString(R.string.permissions_prompt));
builder.setPositiveButton(getResources().getString(android.R.string.ok), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
requestPermissions(new String[]
{android.Manifest.permission.READ_EXTERNAL_STORAGE,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_STORAGE);
}
dialog.dismiss();
}
});
builder.show();
return;
}
}
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!
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