Андроид 6 - запись на внешний носитель не только при первом запуске
Я знаю, что вопрос, похожий на этот, задавался несколько раз, но эта проблема-другая. Мне нужно записать данные во внешнее хранилище. Я знаю, что мне нужно попросить разрешения во время выполнения на Android 6 . Пока все это работает нормально. Только одно странно. Предоставленное разрешение, кажется, работает только во второй раз, когда я запускаю приложение.
Мой пример выглядит так:
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQUEST_WRITE_STORAGE: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "Permission granted!");
write();
} else {
Log.d(TAG, "No permission granted!");
}
}
}
}
@Override
public void onClick(View v) {
boolean hasPermission = (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED);
if (!hasPermission) {
Log.d(TAG, "Has no permission! Ask!");
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_WRITE_STORAGE);
} else {
Log.d(TAG, "Permission already given!");
write();
}
}
private void write(){
Log.d(TAG, "Trying to write");
// Get the directory for the user's public pictures directory.
File root = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "test");
if (! root.exists() && !root.mkdirs()) {
Log.e(TAG, "Directory not created");
return;
}
File testFile = new File(root, "TEST.tmp");
FileWriter writer;
try {
StringBuilder sb = new StringBuilder();
sb.append("TEST TEST TEST");
writer = new FileWriter(testFile, false);
writer.append(sb.toString());
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
Log.d(TAG, "Write successful");
}
Нажатие кнопки вызывает onClick()
, который проверяет наличие разрешений. Если при условии, что он вызывает метод write()
- если он не запрашивает разрешения.
Итак, при первом нажатии кнопки открывается всплывающее окно разрешения, я нажимаю " да " и предполагаю, что он напишет мой тестовый файл. Тем не менее, я получаю следующее сообщение об ошибке, и файл или даже каталог не был создан:
D/LOG: Has no permission! Ask!
D/LOG: Permission granted!
D/LOG: Trying to write
E/LOG: Directory not created
Если я нажму еще раз (с уже предоставленным разрешением), он покажет только
D/LOG: Permission already given!
D/LOG: Trying to write
E/LOG: Directory not created
На самом деле ни директория, ни файл еще не существуют.
Поэтому я закрываю приложение и запускаю его снова и нажмите кнопку.
Консоль показывает следующее:
D/LOG: Permission already given!
D/LOG: Trying to write
D/LOG: Write successful
Вуаля, теперь каталог и файл существуют.
Так почему же он работает только во второй раз, когда я запускаю приложение? Похоже, что разрешения обновляются только при запуске приложения. Есть идеи?
---- править ----
В связи с комментарием Я разделил exists()
и mkdirs()
.
Тем не менее метод выглядит так:
private void write(){
Log.d(TAG, "Trying to write");
// Get the directory for the user's public pictures directory.
File root = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "test");
if (! root.exists()){
if(!root.mkdirs()) {
Log.e(TAG, "Directory not created");
return;
} else {
Log.e(TAG, "Directory created");
}
}
...
Тем не менее, при первом запуске приложения я получаю Каталог не созданный. При следующем запуске приложения каталог был создан. Так что, похоже, это не проблема.
Также я добавил метод, проверяющий, существует ли Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
. Это верно, даже с самого начала. Что не удается-это mkdirs()
для моей вложенной папки.
3 ответа:
Как опубликовано здесь: https://stackoverflow.com/a/37135078/1565635 Я думаю, что нашел решение - или, по крайней мере, объяснение.
Оказывается, что это, кажется, более серьезная проблема. Изменение разрешения на запись во внешнее хранилище изменяет gid Linux для этого процесса. Чтобы изменить идентификатор, процесс должен быть перезапущен. В следующий раз, когда приложение откроется, будет установлен новый идентификатор группы и предоставлено разрешение. Это приводит к выводу, что это не ошибка, а в факт более серьезная проблема с Linux и Android.
Я "решил" это, попросив разрешения при первом запуске приложения и перезапустив его, когда разрешение дается следующим образом:
PackageManager packageManager = getPackageManager(); Intent intent = packageManager.getLaunchIntentForPackage(getPackageName()); ComponentName componentName = intent.getComponent(); Intent mainIntent = IntentCompat.makeRestartActivityTask(componentName); startActivity(mainIntent); System.exit(0);
Решение, которое я не пробовал, состояло в том, чтобы создать службу, работающую в фоновом режиме (таким образом, имея другой идентификатор процесса) и дать ей разрешение. Таким образом, необходимо перезапустить только службу, но не все приложение. С другой стороны, это может сделать больше работы для связи между процессы. Если я правильно понимаю, контент-провайдер тоже может работать, но также означает больше работы.
--- править ---
Пользователь M66B (https://stackoverflow.com/a/32473449/1565635 ) нашел список связанных гид. Дополнительную информацию можно найти здесь: https://android.googlesource.com/platform/frameworks/base/+/master/data/etc/platform.xml
Попробуйте этот код: -
@Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case REQUEST_WRITE_STORAGE: { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { Log.d(TAG, "Permission granted!"); write(); } else { Log.d(TAG, "No permission granted!"); } } } } @Override public void onClick(View v) { File root = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "test"); dircheck(root); filecheck(new File(root, "TEST.tmp")); boolean hasPermission = (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED); if (!hasPermission) { Log.d(TAG, "Has no permission! Ask!"); ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_WRITE_STORAGE); } else { Log.d(TAG, "Permission already given!"); write(); } } private void dircheck(File file) { if (!file.exists()) { file.mkdirs(); } } private void filecheck(File file){ if(!file.exists()){ file.createNewFile(); } } private void write(){ File root = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "test"); File testFile = new File(root, "TEST.tmp"); FileWriter writer; try { StringBuilder sb = new StringBuilder(); sb.append("TEST TEST TEST"); writer = new FileWriter(testFile, false); writer.append(sb.toString()); writer.flush(); writer.close(); } catch (IOException e) { e.printStackTrace(); } Log.d(TAG, "Write successful"); }
Отредактированный ответ : -
@Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case REQUEST_WRITE_STORAGE: { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { Log.d(TAG, "Permission granted!"); write(); } else { Log.d(TAG, "No permission granted!"); } } } } @Override public void onClick(View v) { boolean hasPermission = (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED); if (!hasPermission) { Log.d(TAG, "Has no permission! Ask!"); ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_WRITE_STORAGE); } else { Log.d(TAG, "Permission already given!"); write(); } } private void dircheck(File file) { if (!file.exists()) { file.mkdirs(); } } private void filecheck(File file){ if(!file.exists()){ try { file.createNewFile(); }catch (Exception e){e.printStackTrace();} } } private void write(){ File root = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "test"); dircheck(root); filecheck(new File(root, "TEST.tmp")); File testFile = new File(root, "TEST.tmp"); FileWriter writer; try { StringBuilder sb = new StringBuilder(); sb.append("TEST TEST TEST"); writer = new FileWriter(testFile, false); writer.append(sb.toString()); writer.flush(); writer.close(); } catch (IOException e) { e.printStackTrace(); } Log.d(TAG, "Write successful"); }