Как передавать файлы между приложениями Android, работающими на одном устройстве?
Я пишу приложение для Android, которое взаимодействует с сервисом RESTful. Этот веб-сервис, по существу, выходит из файловой системы и предоставляет метаданные, а также доступ к файлам с помощью CRUD. Мое приложение извлекает метаданные и предоставляет их сторонним приложениям через ContentProvider
.
Мне нужно добавить способность сторонних приложений, работающих на том же устройстве, что и мое приложение, к CRUD с фактическими файлами, делая запросы в/из моего приложения (а не напрямую с сервера). Это означает, что они должны либо отправлять, либо получать содержимое файлов (которые обычно являются XML или изображениями) через мое приложение.
Я подумал о двух подходах для реализации этого:
Вариант 1 - Использование ContentProvider.openFile
Это кажется очевидным выбором для предоставления сторонним приложениям возможности читать файлы с моего ContentProvider
. Я думаю, что это начинает усложняться, когда эти приложения должны создавать или обновлять файлы через мой ContentProvider. Мне понадобится обратный вызов, когда они будут завершены, чтобы узнать, когда отправить новый/измененный файл обратно на сервер. Я полагаю, что для этой цели я мог бы использовать FileObserver.
Вариант 2 - Использование Messenger через службу
При таком подходе я могу отправить файлы между моим приложением и клиентскими приложениями через Messenger
. Файлы должны быть переданы через Bundle
, поэтому я не уверен, какой лучший формат для их передачи (File
, FileDescriptor
, массив байтов, что-то еще?). У меня нет хорошей справки о том, вызовет ли это проблемы, если файлы станут большими.
Вариант 3 - гибридный подход
- Использовать папку (-ы) на внешней памяти в качестве раскрывающегося списка
- Обмениваться запросами CRUD и отображать содержимое окна с помощью
Messenger
/Service
- Используйте
ContentProvider
для хранения статуса запросов
- Стороннее приложение получает обновления статуса через
ContentObserver
Резюме
Я думаю, что использование ContentProvider
было бы идеальным решением, но похоже, что API не полностью поддерживает мой прецедент. Я обеспокоен тем, что попытка спуститься по этому пути может привести к запутанной реализации. Если я использую подход Messenger
и Service
, я не уверен в наиболее надежном способе переноса файлов через Bundle
.
Гибридный подход кажется довольно надежным, но наиболее сложным для реализации. Файлы фактически не передаются, поэтому производительность должна быть хорошей. Однако я боюсь, что это чрезмерное архитектурное решение.
Каков наилучший способ передачи файлов между приложениями, запущенными на одном устройстве Android? Конечно, я открыт для других вариантов, которые я не указал в моем вопросе.
Ответы
Ответ 1
Поставщик контента - это, безусловно, путь. Если вы считаете, что Google использует этот подход почти для всех, то он становится appaentr, что это предполагаемый метод проектирования.
Я не превозношу достоинства их, но на земле слепых провайдер контента с одним взглядом является королем.
Обновление
Ниже приведен пример того, как это сделать в книге CommonsWare, см. предоставленную ссылку.
Источник поставщика контента/файлы
Используйте инфраструктуру синхронизации для поставщиков контента. Просто поддерживайте список запросов, а затем планируйте синхронизацию для загрузки этих файлов. Вы также можете сделать это на сетевых щеках и т.д. Вы можете использовать трансляции или контент-сервер, чтобы уведомить клиентов о том, что файл загружен.
По сути, это, вероятно, похоже на ваш третий вариант, но важно, чтобы он использовал инструменты, поставляемые Android, а не сворачивал ваши собственные.
Ad Endum
Лучшим местом для начала является образец SDK для Android в: android-sdk\samples\android-8\SampleSyncAdapter, но следует предупредить о том, что нагрузка связанных с контактами материалов, которая маскирует сочные биты. Мне потребовалось некоторое время, чтобы понять, что я могу удалить почти все, кроме syncadapter
Ответ 2
http://developer.android.com/reference/android/os/ParcelFileDescriptor.html может быть отправлено между процессами. Я считаю, что есть тонко, где они явно занесены в черный список из-за того, что их можно ввести в заблуждение. Они могут быть отправлены через AIDL.
Кроме того, НЕ используйте SDK для этого. Это просто просит неприятностей. Одна SD-карта является читаемой в мире, поэтому любой может ее увидеть. Кроме того, у вас не всегда есть доступ к записи на SD-карту (она удаляется или помещается в UMS).
Ответ 3
Использование SD-карты, безусловно, рекомендуется для обмена файлами на Android.
Однако я бы пошел с модифицированным гибридным решением, которое использует startActivityForResult()
и onActivityResult()
(docs здесь) на клиенте чтобы сообщать запросы CRUD (и получать Uri в файл на SD-карте, если это необходимо), если вы не возражаете против создания фиктивной активности в качестве передней части вашей службы. Клиенты, закончив с файлом (-ами), могут снова вызвать startActivityForResult()
, чтобы предупредить ваше приложение об изменениях.
Конечно, это можно сделать с помощью startService()
/bindService()
, однако он не обеспечивает простой способ для клиентов получить результат статуса, особенно если вам нужен IPC.
Хотя контент-провайдеры/преобразователи чувствуют себя как правильный способ заниматься вещами, я чувствую, что это больше для запросов с одним направлением, специфичных для предоставления/потребления контента.