Пользователи любят изображения, видео и другой выразительный контент, но вставка и перемещение этого контента в приложениях не всегда просты. Чтобы упростить приложениям доступ к разнообразному контенту, в Android 12 (API уровня 31) представлен унифицированный API, позволяющий вашему приложению принимать контент из любого источника: буфера обмена, клавиатуры или перетаскивания.
Вы можете прикрепить интерфейс, например OnReceiveContentListener
, к компонентам пользовательского интерфейса и получать обратный вызов при вставке контента через любой механизм. Обратный вызов становится единым звеном, где ваш код обрабатывает получение всего контента, от простого и стилизованного текста до разметки, изображений, видео, аудиофайлов и т. д.
Для обратной совместимости с предыдущими версиями Android этот API также доступен в AndroidX, начиная с Core 1.7 и Appcompat 1.4 , которые мы рекомендуем использовать при реализации этой функциональности.
Обзор
В других существующих API каждый механизм пользовательского интерфейса, например, сенсорное меню или перетаскивание, имеет свой собственный API. Это означает, что вам придётся интегрироваться с каждым API отдельно, добавляя аналогичный код для каждого механизма вставки контента:
API OnReceiveContentListener
объединяет эти различные пути кода, создавая единый API для реализации, что позволяет вам сосредоточиться на логике, специфичной для вашего приложения, и позволить платформе позаботиться обо всем остальном:
Такой подход также означает, что при добавлении на платформу новых способов добавления контента вам не придётся вносить дополнительные изменения в код для обеспечения их поддержки в вашем приложении. А если вашему приложению требуется полная настройка для конкретного сценария использования, вы по-прежнему сможете использовать существующие API, которые будут работать по тому же принципу.
Выполнение
API представляет собой интерфейс прослушивателя с единственным методом OnReceiveContentListener
. Для поддержки старых версий платформы Android мы рекомендуем использовать соответствующий интерфейс OnReceiveContentListener
из библиотеки AndroidX Core.
Чтобы использовать API, реализуйте прослушиватель, указав, какие типы контента может обрабатывать ваше приложение:
Котлин
object MyReceiver : OnReceiveContentListener { val MIME_TYPES = arrayOf("image/*", "video/*") // ... override fun onReceiveContent(view: View, payload: ContentInfoCompat): ContentInfoCompat? { TODO("Not yet implemented") } }
Ява
public class MyReceiver implements OnReceiveContentListener { public static final String[] MIME_TYPES = new String[] {"image/*", "video/*"}; // ... }
Указав все типы MIME контента, поддерживаемые вашим приложением, реализуйте остальную часть прослушивателя:
Котлин
class MyReceiver : OnReceiveContentListener { override fun onReceiveContent(view: View, contentInfo: ContentInfoCompat): ContentInfoCompat { val split = contentInfo.partition { item: ClipData.Item -> item.uri != null } val uriContent = split.first val remaining = split.second if (uriContent != null) { // App-specific logic to handle the URI(s) in uriContent. } // Return anything that your app didn't handle. This preserves the // default platform behavior for text and anything else that you aren't // implementing custom handling for. return remaining } companion object { val MIME_TYPES = arrayOf("image/*", "video/*") } }
Ява
public class MyReceiver implements OnReceiveContentListener { public static final String[] MIME_TYPES = new String[] {"image/*", "video/*"}; @Override public ContentInfoCompat onReceiveContent(View view, ContentInfoCompat contentInfo) { Pair<ContentInfoCompat, ContentInfoCompat> split = contentInfo.partition( item -> item.getUri() != null); ContentInfo uriContent = split.first; ContentInfo remaining = split.second; if (uriContent != null) { // App-specific logic to handle the URI(s) in uriContent. } // Return anything that your app didn't handle. This preserves the // default platform behavior for text and anything else that you aren't // implementing custom handling for. return remaining; } }
Если ваше приложение уже поддерживает обмен данными с помощью намерений, вы можете повторно использовать логику, специфичную для приложения, для обработки URI контента. Верните оставшиеся данные, чтобы делегировать обработку этих данных платформе.
После реализации прослушивателя установите его на соответствующих элементах пользовательского интерфейса вашего приложения:
Котлин
class MyActivity : Activity() { public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // ... val myInput = findViewById(R.id.my_input) ViewCompat.setOnReceiveContentListener(myInput, MyReceiver.MIME_TYPES, MyReceiver()) } }
Ява
public class MyActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { // ... AppCompatEditText myInput = findViewById(R.id.my_input); ViewCompat.setOnReceiveContentListener(myInput, MyReceiver.MIME_TYPES, new MyReceiver()); } }
Разрешения URI
Платформа автоматически предоставляет и освобождает разрешения на чтение для любых URI контента в полезной нагрузке, переданной в OnReceiveContentListener
.
Обычно ваше приложение обрабатывает URI контента в сервисе или активности. Для длительной обработки используйте WorkManager . При реализации этого решения расширьте разрешения для целевой службы или активности, передав контент с помощью Intent.setClipData
и установив флаг FLAG_GRANT_READ_URI_PERMISSION
.
В качестве альтернативы можно использовать фоновый поток в текущем контексте для обработки контента. В этом случае необходимо сохранить ссылку на объект payload
, полученный прослушивателем, чтобы гарантировать, что платформа не отзовёт разрешения преждевременно.
Пользовательские представления
Если ваше приложение использует пользовательский подкласс View
, убедитесь, что OnReceiveContentListener
не игнорируется.
Если ваш класс View
переопределяет метод onCreateInputConnection
, используйте API Jetpack InputConnectionCompat.createWrapper
для настройки InputConnection
.
Если ваш класс View
переопределяет метод onTextContextMenuItem
, делегируйте его super, когда пункт меню — R.id.paste
или R.id.pasteAsPlainText
.
Сравнение с API изображений клавиатуры
API OnReceiveContentListener
можно рассматривать как следующую версию существующего API для работы с изображениями клавиатуры . Этот унифицированный API поддерживает функциональность API для работы с изображениями клавиатуры, а также некоторые дополнительные функции. Совместимость с устройствами и функциями зависит от того, используете ли вы библиотеку Jetpack или нативные API из Android SDK.
Действие или функция | Поддерживается API изображения клавиатуры | Поддерживается единым API |
---|---|---|
Вставить с клавиатуры | Да (уровень API 13 и выше) | Да (уровень API 13 и выше) |
Вставьте с помощью вставки из сенсорного меню | Нет | Да |
Вставка с помощью перетаскивания | Нет | Да (уровень API 24 и выше) |
Действие или функция | Поддерживается API изображения клавиатуры | Поддерживается единым API |
---|---|---|
Вставить с клавиатуры | Да (уровень API 25 и выше) | Да (Android 12 и выше) |
Вставьте с помощью вставки из сенсорного меню | Нет | |
Вставить с помощью перетаскивания | Нет |