Użytkownicy lubią obrazy, filmy i inne treści, ale wstawianie i przenoszenie ich w aplikacjach nie zawsze jest łatwe. Aby ułatwić aplikacjom odbieranie szczegółowych treści, w Androidzie 12 (poziom interfejsu API 31) wprowadziliśmy ujednolicony interfejs API, który umożliwia aplikacji akceptowanie treści z dowolnego źródła: schowka, klawiatury lub przeciągania.
Możesz dołączyć interfejs, np. OnReceiveContentListener, do komponentów interfejsu i otrzymać wywołanie zwrotne, gdy treść zostanie wstawiona za pomocą dowolnego mechanizmu. Wywołanie zwrotne staje się jedynym miejscem, w którym kod obsługuje odbieranie wszystkich treści, od zwykłego i stylizowanego tekstu po znaczniki, obrazy, filmy, pliki audio i inne.
Aby zapewnić zgodność wsteczną z poprzednimi wersjami Androida, ten interfejs API jest też dostępny w AndroidX, począwszy od Core 1.7 i Appcompat 1.4. Zalecamy korzystanie z tych wersji podczas wdrażania tej funkcji.
Przegląd
W przypadku innych istniejących interfejsów API każdy mechanizm interfejsu użytkownika, taki jak menu naciśnięcia i przytrzymania lub przeciąganie, ma własny interfejs API. Oznacza to, że musisz przeprowadzić integrację z każdym interfejsem API osobno, dodając podobny kod dla każdego mechanizmu, który wstawia treści:
Interfejs API OnReceiveContentListener konsoliduje te różne ścieżki kodu, tworząc jeden interfejs API do wdrożenia, dzięki czemu możesz skupić się na logice aplikacji, a platforma zajmie się resztą:
Takie podejście oznacza również, że gdy do platformy zostaną dodane nowe sposoby wstawiania treści, nie musisz wprowadzać dodatkowych zmian w kodzie, aby włączyć obsługę w aplikacji. Jeśli aplikacja wymaga pełnego dostosowania w konkretnym przypadku użycia, możesz nadal korzystać z istniejących interfejsów API, które działają tak samo.
Implementacja
Interfejs API to interfejs detektora z jedną metodą: OnReceiveContentListener.
Aby zapewnić obsługę starszych wersji platformy Androida, zalecamy użycie odpowiedniego interfejsu OnReceiveContentListener w bibliotece AndroidX Core.
Aby używać interfejsu API, zaimplementuj detektor, określając, jakie typy treści może obsługiwać Twoja aplikacja:
Kotlin
object MyReceiver : OnReceiveContentListener { val MIME_TYPES = arrayOf("image/*", "video/*") // ... override fun onReceiveContent(view: View, payload: ContentInfoCompat): ContentInfoCompat? { TODO("Not yet implemented") } }
Java
public class MyReceiver implements OnReceiveContentListener { public static final String[] MIME_TYPES = new String[] {"image/*", "video/*"}; // ... }
Po określeniu wszystkich typów MIME treści obsługiwanych przez aplikację zaimplementuj resztę detektora:
Kotlin
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/*") } }
Java
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; } }
Jeśli Twoja aplikacja obsługuje już udostępnianie za pomocą intencji, możesz ponownie użyć logiki aplikacji do obsługi identyfikatorów URI treści. Zwróć pozostałe dane, aby przekazać ich obsługę platformie.
Po zaimplementowaniu detektora ustaw go w odpowiednich elementach interfejsu w aplikacji:
Kotlin
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()) } }
Java
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()); } }
Uprawnienia do identyfikatorów URI
Uprawnienia do odczytu są przyznawane i zwalniane automatycznie przez platformę w przypadku wszystkich identyfikatorów URI treści w ładunku przekazywanym do OnReceiveContentListener.
Zwykle aplikacja przetwarza identyfikatory URI treści w usłudze lub aktywności. W przypadku długotrwałego przetwarzania użyj biblioteki WorkManager. Gdy to zrobisz, rozszerz uprawnienia na usługę lub aktywność docelową, przekazując treść za pomocą Intent.setClipData i ustawiając flagę FLAG_GRANT_READ_URI_PERMISSION.
Możesz też użyć wątku w tle w bieżącym kontekście, aby przetworzyć treść. W takim przypadku musisz zachować odwołanie do obiektu payload otrzymanego przez detektor, aby mieć pewność, że platforma nie cofnie uprawnień przedwcześnie.
Widoki niestandardowe
Jeśli aplikacja używa niestandardowej podklasy View, upewnij się, że OnReceiveContentListener nie jest pomijany.
Jeśli klasa View zastępuje metodę onCreateInputConnection, użyj interfejsu Jetpack API InputConnectionCompat.createWrapper, aby skonfigurować InputConnection.
Jeśli klasa View zastępuje metodę onTextContextMenuItem, przekaż ją do klasy nadrzędnej, gdy element menu to R.id.paste lub R.id.pasteAsPlainText.
Porównanie z interfejsem API obrazów klawiatury
Interfejs API OnReceiveContentListener można traktować jako kolejną wersję dotychczasowego interfejsu API obrazu klawiatury. Ten ujednolicony interfejs API obsługuje funkcje interfejsu API obrazów klawiatury oraz niektóre dodatkowe funkcje. Zgodność urządzeń i funkcji zależy od tego, czy używasz biblioteki Jetpack, czy natywnych interfejsów API z pakietu Android SDK.
| Działanie lub funkcja | Obsługiwane przez interfejs API obrazów klawiatury | Obsługiwane przez ujednolicony interfejs API |
|---|---|---|
| Wstawianie za pomocą klawiatury | Tak (poziom API 13 lub wyższy) | Tak (poziom API 13 lub wyższy) |
| Wstawianie za pomocą opcji wklejania z menu naciśnięcia i przytrzymania | Nie | Tak |
| Wstawianie za pomocą przeciągania i upuszczania | Nie | Tak (poziom API 24 lub wyższy) |
| Działanie lub funkcja | Obsługiwane przez interfejs API obrazów klawiatury | Obsługiwane przez ujednolicony interfejs API |
|---|---|---|
| Wstawianie za pomocą klawiatury | Tak (poziom interfejsu API 25 lub wyższy) | Tak (Android 12 lub nowszy) |
| Wstawianie za pomocą opcji wklejania z menu naciśnięcia i przytrzymania | Nie | |
| Wstawianie za pomocą przeciągania i upuszczania | Nie |