Intereting Posts
Как изменить положение диалога прогресса? Где ввести код для запуска приложения? Android пытается запустить мой проект в eclipse и в итоге с xml.out Android, как запуститьOnUiThread в другом классе? Внутренний класс внутри интерфейса, реализующий тот же интерфейс, что мы достигаем этим? Каковы плюсы и минусы использования configChanges = «ориентация» для устройств Android? Android FinalizerDaemon повесил трубку Динамическая установка высоты ViewPager Android. Как изменить активность в одной вкладке В Android: как вызвать функцию активности из службы? Android Webview: невозможно вызвать функцию definedVisibility () – никогда не видел подключения для pid Как разместить изображение в верхней части другого изображения в Android Как автоматически переключаться между страницами viewPager Побочные эффекты изменения фильтра и требования к существующему приложению в Android Play / Market Холст HTML5 на телефонах Android – перерисовать и выделить проблемы

Как хранить большие капли в поставщике контента для Android?

У меня есть большие файлы (изображения и видео), которые мне нужно хранить в контент-провайдере. Документация android указывает …

Если вы выставляете байт-данные, которые слишком велики для размещения в самой таблице – например, большой файл растрового изображения – поле, которое предоставляет данные клиентам, должно фактически содержать строку содержимого: URI. Это поле, которое дает клиентам доступ к файлу данных. В записи также должно быть другое поле с именем «_data», в котором указан точный путь к файлу на устройстве для этого файла. Это поле не предназначено для чтения клиентом, а ContentResolver. Клиент будет вызывать ContentResolver.openInputStream () в поле, обращенном к пользователю, с URI для элемента. ContentResolver запросит поле «_data» для этой записи и потому, что имеет более высокие разрешения, чем клиент, он должен иметь возможность напрямую обращаться к этому файлу и возвращать оболочку для чтения для клиента. – http://developer.android.com/guide/topics/providers/content-providers.html#creating

Мне трудно найти пример. В частности, я хочу использовать растровое изображение в контексте ImageView. Рассмотрим следующий код квазикода (он не работает) …

ImageView iv = .... String iconUri = cursor.getString(cursor.getColumnIndex(Table.ICON)); iv.setImageURI(Uri.parse(iconUri)); 

Замечания / проблемы …

  1. Как восстановить восстановленный или восстановленный uri правильно? (Это текст в таблице)
  2. Реализация setImageURI использует разрешение контента openInputStream, поэтому это должно работать.

     String scheme = mUri.getScheme(); ... } else if (ContentResolver.SCHEME_CONTENT.equals(scheme) || ContentResolver.SCHEME_FILE.equals(scheme)) { try { d = Drawable.createFromStream( mContext.getContentResolver().openInputStream(mUri), null); 

    –frameworks / основание / ядро ​​/ Java / Android / виджет / ImageView.java

Я заработал. Я сделал намек на MediaStore и MediaProvider. Файлы, содержащие данные, называются на основе поставщика контента (каталога), имени столбца, идентификатора строки и типа носителя. После этого контент-резольвер получает файловый дескриптор так …

 Uri iconUri = Uri.withAppendedPath(Table.getUri(cursor), Table.ICON); ib.setImageURI(iconUri); 

… и поставщик контента отвечает натурой …

 @Override public ParcelFileDescriptor openFile (Uri uri, String mode) { int imode = 0; if (mode.contains("w")) imode |= ParcelFileDescriptor.MODE_WRITE_ONLY; if (mode.contains("r")) imode |= ParcelFileDescriptor.MODE_READ_ONLY; if (mode.contains("+")) imode |= ParcelFileDescriptor.MODE_APPEND; List<String> pseg = uri.getPathSegments(); if (pseg.size() < 3) return null; try { File filePath = filePathFromRecord(pseg.get(2), pseg.get(1)); return ParcelFileDescriptor.open(filePath, imode); } catch (FileNotFoundException e) { e.printStackTrace(); } return null; } 

Solutions Collecting From Web of "Как хранить большие капли в поставщике контента для Android?"

Решение phreed дает в нижней половине вопроса, в основном, правильно. Я попытаюсь добавить здесь несколько подробностей.

Когда вы получите getContentResolver().openInputStream(...) , преобразователь контента перейдет к вашему провайдеру контента и вызовет его метод openFile . Так выглядит openFile в ContentProvider.java :

 public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { throw new FileNotFoundException("No files supported by provider at " + uri); } 

Таким образом, это объясняет, откуда происходит ошибка «Без файлов …». Вы обойдете это, переопределив метод openFile в своем подклассе и предоставив свою собственную реализацию. Это аккуратно: вы прекрасно контролируете, где ваши файлы размещаются, когда какой-либо клиент делает openInputStream или openOutputStream .

Образец кода в вопросе фиделя дает подсказку о том, как может выглядеть реализация. Вот моя слегка измененная версия, которая также создает каталоги и файлы по мере необходимости. Я новичок в этом, так что это может быть не оптимальный способ делать что-то, но это дает представление. Во-первых, вероятно, следует проверить, доступно ли внешнее хранилище.

 @Override public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { File root = new File(Environment.getExternalStorageDirectory(), "/Android/data/com.example.myapp/cache"); root.mkdirs(); File path = new File(root, uri.getEncodedPath()); // So, if the uri was content://com.example.myapp/some/data.xml, // we'll end up accessing /Android/data/com.example.myapp/cache/some/data.xml int imode = 0; if (mode.contains("w")) { imode |= ParcelFileDescriptor.MODE_WRITE_ONLY; if (!path.exists()) { try { path.createNewFile(); } catch (IOException e) { // TODO decide what to do about it, whom to notify... e.printStackTrace(); } } } if (mode.contains("r")) imode |= ParcelFileDescriptor.MODE_READ_ONLY; if (mode.contains("+")) imode |= ParcelFileDescriptor.MODE_APPEND; return ParcelFileDescriptor.open(path, imode); } 

Android предоставляет вспомогательный метод openFileHelper (), который упрощает реализацию метода openFile (). Все, что вам нужно сделать, чтобы использовать этот метод, – это указать расположение файла в столбце с именем «_data».

 @Override public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { if (URI_MATCHER.match(uri) != PHOTO_ID) { throw new IllegalArgumentException ("URI invalid. Use an id-based URI only."); } return openFileHelper(uri, mode); } 

Нажмите здесь для подробностей

Однако есть проблема с написанием файлов. Как поставщик контента знает, что запись завершена?

При закрытии OutputStream, полученном с помощью ContentResolver.openOutputStream (), я хочу, чтобы соответствующий (пользовательский) ContentProvider выполнял некоторые пользовательские действия. В настоящее время я использую создание FileObserver во временном файле, но это похоже на неправильный способ сделать это. Моя первая мысль заключалась в подтипе ParcelFileDescriptor, созданного методом ContentProvider.openFile (), но это, похоже, не работало для меня.

При этом были некоторые ошибки, которые привели к использованию MyParcelFileDescriptor.

  • Я не гарантировал, что файловый дескриптор не будет предварительно собран с мусором.
  • Я не пытался в конечном итоге переопределить () (похоже, документация говорит о том, что место для этого, но close (), казалось, было правильным выбором для меня.

Итог, есть ли какое-либо взаимодействие между файловыми объектами, как показано в ContentResolver и в ContentProvider ?