Пользователи любят изображения, видео и другой выразительный контент, но вставка и перемещение этого контента в приложениях не всегда просты. Чтобы упростить приложениям получение богатого контента, 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 изображения клавиатуры
Вы можете думать об OnReceiveContentListener
API как о следующей версии существующего API изображения клавиатуры . Этот унифицированный API поддерживает функциональность API изображения клавиатуры, а также некоторые дополнительные функции. Совместимость устройств и функций зависит от того, используете ли вы библиотеку Jetpack или собственные API из Android SDK.
Действие или особенность | Поддерживается API изображения клавиатуры | Поддерживается единым API |
---|---|---|
Вставить с клавиатуры | Да (уровень API 13 и выше) | Да (уровень API 13 и выше) |
Вставьте с помощью вставки из меню касания и удержания | Нет | Да |
Вставить с помощью перетаскивания | Нет | Да (уровень API 24 и выше) |
Действие или особенность | Поддерживается API изображения клавиатуры | Поддерживается единым API |
---|---|---|
Вставить с клавиатуры | Да (уровень API 25 и выше) | Да (Android 12 и выше) |
Вставьте с помощью вставки из меню касания и удержания | Нет | |
Вставить с помощью перетаскивания | Нет |