Aby zapewnić użytkownikom większą kontrolę nad plikami i ograniczyć ich bałagan, w Androidzie 10 wprowadziliśmy nowy model pamięci masowej dla aplikacji, który nazywa się ograniczonym dostępem do miejsca na dane. Wydzielony obszar pamięci zmienia sposób, w jaki aplikacje przechowują pliki w pamięci zewnętrznej urządzenia i uzyskują do nich dostęp. Aby ułatwić Ci migrację aplikacji na potrzeby obsługi ograniczonego dostępu do miejsca na dane, w tym przewodniku opisaliśmy sprawdzone metody dotyczące typowych przypadków użycia pamięci. Przypadki użycia są podzielone na 2 kategorie: obsługa plików multimedialnych i obsługa plików innych niż multimedialne.
W wielu przypadkach aplikacja tworzy pliki, do których inne aplikacje nie muszą lub nie powinny mieć dostępu. System udostępnia lokalizacje pamięci masowej przeznaczone dla aplikacji, które umożliwiają zarządzanie takimi plikami.
Więcej informacji o przechowywaniu plików i uzyskiwaniu do nich dostępu na Androidzie znajdziesz w przewodnikach dotyczących pamięci.
Obsługa plików multimedialnych
W tej sekcji opisujemy niektóre typowe przypadki użycia związane z obsługą plików multimedialnych (plików wideo, obrazów i plików audio) oraz ogólne podejście, które może zastosować Twoja aplikacja. Tabela poniżej zawiera podsumowanie każdego z tych przypadków użycia oraz linki do sekcji, w których znajdziesz więcej informacji.
| Przypadek użycia | Podsumowanie |
|---|---|
| Wyświetlanie wszystkich plików graficznych i wideo | Takie samo podejście dotyczy wszystkich wersji Androida. |
| Wyświetlanie obrazów lub filmów z określonego folderu | Takie samo podejście dotyczy wszystkich wersji Androida. |
| Uzyskiwanie dostępu do informacji o lokalizacji ze zdjęć | Jeśli aplikacja korzysta z ograniczonego dostępu do miejsca na dane, użyj jednej metody. Jeśli Twoja aplikacja nie korzysta z ograniczonego dostępu do miejsca na dane, użyj innego podejścia. |
| Definiowanie lokalizacji przechowywania nowych pobranych plików | Jeśli aplikacja korzysta z ograniczonego dostępu do miejsca na dane, użyj jednej metody. Jeśli Twoja aplikacja nie korzysta z ograniczonego dostępu do miejsca na dane, użyj innego podejścia. |
| Eksportowanie plików multimedialnych użytkownika na urządzenie | Takie samo podejście dotyczy wszystkich wersji Androida. |
| Modyfikowanie lub usuwanie wielu plików multimedialnych w ramach jednej operacji | W przypadku Androida 11 użyj jednego podejścia. W przypadku Androida 10 zrezygnuj z wydzielonej pamięci i zastosuj podejście dla Androida 9 i starszych wersji. |
| Importowanie pojedynczego obrazu, który już istnieje | Takie samo podejście dotyczy wszystkich wersji Androida. |
| Robienie pojedynczego zdjęcia | Takie samo podejście dotyczy wszystkich wersji Androida. |
| Udostępnianie plików multimedialnych innym aplikacjom | Takie samo podejście dotyczy wszystkich wersji Androida. |
| Udostępnianie plików multimedialnych określonej aplikacji | Takie samo podejście dotyczy wszystkich wersji Androida. |
| Uzyskiwanie dostępu do plików z kodu lub bibliotek, które używają bezpośrednich ścieżek do plików | W przypadku Androida 11 użyj jednego podejścia. W przypadku Androida 10 zrezygnuj z wydzielonej pamięci i zastosuj podejście dla Androida 9 lub starszego. |
Wyświetlanie plików graficznych lub wideo z wielu folderów
Wysyłanie zapytania do kolekcji multimediów za pomocą interfejsu API query(). Aby filtrować lub sortować pliki multimedialne, dostosuj parametry projection, selection, selectionArgs i sortOrder.
wyświetlać obrazy lub filmy z określonego folderu;
Zastosuj to podejście:
- Postępuj zgodnie ze sprawdzonymi metodami opisanymi w artykule Prośba o uprawnienia aplikacji i poproś o uprawnienie
READ_EXTERNAL_STORAGE. - Pobieraj pliki multimedialne na podstawie wartości
MediaColumns.DATA, która zawiera bezwzględną ścieżkę systemu plików do elementu multimedialnego na dysku.
Uwaga: gdy uzyskujesz dostęp do istniejącego pliku multimedialnego, możesz użyć w logice wartości z kolumny DATA. Dzieje się tak, ponieważ ta wartość ma prawidłową ścieżkę do pliku.
Nie zakładaj jednak, że plik jest zawsze dostępny. Przygotuj się na obsługę wszelkich błędów wejścia/wyjścia związanych z plikami, które mogą wystąpić.
Aby utworzyć lub zaktualizować plik multimedialny, nie używaj kolumny DATA. Zamiast tego użyj kolumn DISPLAY_NAME i RELATIVE_PATH.
Dostęp do informacji o lokalizacji ze zdjęć
Jeśli Twoja aplikacja korzysta z ograniczonego dostępu do miejsca na dane, wykonaj czynności opisane w sekcji Informacje o lokalizacji na zdjęciach w przewodniku po pamięci multimediów.
Definiowanie lokalizacji zapisu nowych pobranych plików
Jeśli Twoja aplikacja korzysta z ograniczonego dostępu do miejsca na dane, zwróć uwagę na lokalizację, w której chcesz przechowywać pobrane pliki multimedialne.
Jeśli inne aplikacje wymagają dostępu do plików, rozważ użycie dobrze zdefiniowanych kolekcji multimediów do pobierania lub kolekcji dokumentów.
Na Androidzie 11 i nowszych pliki w zewnętrznym katalogu aplikacji nie są dostępne dla innych aplikacji, nawet jeśli do ich pobrania używasz DownloadManager.
Eksportowanie plików multimedialnych użytkownika na urządzenie
Zdefiniuj odpowiednią domyślną lokalizację do przechowywania plików multimedialnych użytkownika:
- Zezwalaj użytkownikom na wybór, czy ich pliki multimedialne mają być odczytywane przez inne aplikacje, czy nie, za pomocą pamięci aplikacji lub pamięci współdzielonej.
- Zezwalaj użytkownikom na eksportowanie plików z katalogów aplikacji do bardziej ogólnie dostępnej lokalizacji. Użyj kolekcji obrazów, filmów i plików audio w MediaStore, aby wyeksportować pliki multimedialne do galerii urządzenia.
Modyfikowanie lub usuwanie wielu plików multimedialnych w ramach jednej operacji
Uwzględnij logikę opartą na wersjach Androida, na których działa Twoja aplikacja.
z Androidem 11,
Zastosuj to podejście:
- Utwórz intencję oczekującą dla żądania zapisu lub usunięcia aplikacji za pomocą
MediaStore.createWriteRequest()lubMediaStore.createTrashRequest(), a następnie poproś użytkownika o zgodę na edytowanie zestawu plików, wywołując tę intencję. Oceń odpowiedź użytkownika:
- Jeśli uprawnienie zostało przyznane, przejdź do operacji modyfikacji lub usunięcia.
- Jeśli uprawnienie nie zostało przyznane, wyjaśnij użytkownikowi, dlaczego funkcja w aplikacji go wymaga.
Dowiedz się więcej o zarządzaniu grupami plików multimedialnych za pomocą tych metod, które są dostępne na urządzeniach z Androidem 11 lub nowszym.
działa na Androidzie 10,
Jeśli Twoja aplikacja jest kierowana na Androida 10 (poziom API 29), zrezygnuj z wydzielonej pamięci i nadal używaj metody dla Androida 9 i starszych wersji, aby wykonać tę operację.
urządzenie z Androidem 9 lub starszym,
Zastosuj to podejście:
- Postępując zgodnie ze sprawdzonymi metodami opisanymi w artykule Prośba o uprawnienia aplikacji, poproś o uprawnienie
WRITE_EXTERNAL_STORAGE. - Aby zmodyfikować lub usunąć pliki multimedialne, użyj interfejsu API
MediaStore.
Importowanie pojedynczego obrazu, który już istnieje
Jeśli chcesz zaimportować pojedynczy obraz, który już istnieje (np. aby użyć go jako zdjęcia profilowego użytkownika), aplikacja może użyć własnego interfejsu lub selektora systemowego.
Wyświetlanie własnego interfejsu
Zastosuj to podejście:
- Postępuj zgodnie ze sprawdzonymi metodami opisanymi w artykule Prośba o uprawnienia aplikacji i poproś o uprawnienie
READ_EXTERNAL_STORAGE. - Użyj interfejsu API
query(), aby wysłać zapytanie do kolekcji multimediów. - Wyświetl wyniki w niestandardowym interfejsie aplikacji.
Używanie selektora systemowego
Użyj intencji ACTION_GET_CONTENT, która prosi użytkownika o wybranie obrazu do zaimportowania.
Jeśli chcesz filtrować typy obrazów, które selektor systemowy prezentuje użytkownikowi do wyboru, możesz użyć setType() lub EXTRA_MIME_TYPES.
Zrób jedno zdjęcie
Jeśli chcesz zrobić pojedyncze zdjęcie do użycia w aplikacji (np. jako zdjęcie profilowe użytkownika), użyj intencji ACTION_IMAGE_CAPTURE, aby poprosić użytkownika o zrobienie zdjęcia aparatem urządzenia. System zapisuje zrobione zdjęcie w tabeli MediaStore.Images.
Udostępnianie plików multimedialnych innym aplikacjom
Aby dodawać rekordy bezpośrednio do MediaStore, użyj metody insert(). Więcej informacji znajdziesz w sekcji Dodawanie elementu w przewodniku po pamięci multimediów.
Udostępnianie plików multimedialnych określonej aplikacji
Użyj komponentu Androida FileProvider zgodnie z opisem w przewodniku Konfigurowanie udostępniania plików.
uzyskiwać dostęp do plików z kodu lub bibliotek, które używają bezpośrednich ścieżek do plików;
Uwzględnij logikę opartą na wersjach Androida, na których działa Twoja aplikacja.
z Androidem 11,
Zastosuj to podejście:
- Postępuj zgodnie ze sprawdzonymi metodami opisanymi w artykule Prośba o uprawnienia aplikacji i poproś o uprawnienie
READ_EXTERNAL_STORAGE. - Uzyskiwać dostęp do plików za pomocą bezpośrednich ścieżek.
Więcej informacji znajdziesz w sekcji dotyczącej otwierania plików multimedialnych za pomocą bezpośrednich ścieżek do plików.
działa na Androidzie 10,
Jeśli Twoja aplikacja jest kierowana na Androida 10 (poziom API 29), zrezygnuj z wydzielonej pamięci i nadal używaj metody dla Androida 9 i starszych wersji, aby wykonać tę operację.
urządzenie z Androidem 9 lub starszym,
Zastosuj to podejście:
- Postępuj zgodnie ze sprawdzonymi metodami opisanymi w artykule Prośba o uprawnienia aplikacji i poproś o uprawnienie
WRITE_EXTERNAL_STORAGE. - Uzyskaj dostęp do plików, korzystając z bezpośrednich ścieżek do nich.
Obsługa plików innych niż multimedialne
W tej sekcji opisano niektóre typowe przypadki użycia związane z obsługą plików innych niż multimedialne oraz ogólne podejście, które może zastosować aplikacja. Tabela poniżej zawiera podsumowanie każdego z tych przypadków użycia oraz linki do sekcji, w których znajdziesz więcej informacji.
| Przypadek użycia | Podsumowanie |
|---|---|
| Otwieranie pliku dokumentu | Takie samo podejście dotyczy wszystkich wersji Androida. |
| Zapisywanie plików na dodatkowych woluminach pamięci | W przypadku Androida 11 użyj jednego podejścia. W przypadku wcześniejszych wersji Androida użyj innego podejścia. |
| Przenoszenie istniejących plików ze starszej lokalizacji przechowywania | Jeśli to możliwe, przenieś pliki do pamięci wydzielonej. W razie potrzeby zrezygnuj z wydzielonego miejsca na dane na Androidzie 10. |
| Udostępnianie treści innym aplikacjom | Takie samo podejście dotyczy wszystkich wersji Androida. |
| Zapisywanie w pamięci podręcznej plików innych niż multimedialne | Takie samo podejście dotyczy wszystkich wersji Androida. |
| Eksportowanie plików innych niż multimedialne na urządzenie | Jeśli aplikacja korzysta z ograniczonego dostępu do miejsca na dane, użyj jednej metody. Jeśli Twoja aplikacja nie korzysta z ograniczonego dostępu do miejsca na dane, użyj innego podejścia. |
Otwieranie pliku dokumentu
Użyj intencji ACTION_OPEN_DOCUMENT, aby poprosić użytkownika o wybranie pliku do otwarcia za pomocą selektora systemowego. Jeśli chcesz przefiltrować typy plików, które selektor systemowy będzie prezentować użytkownikowi do wyboru, możesz użyć setType() lub EXTRA_MIME_TYPES.
Możesz na przykład znaleźć wszystkie pliki PDF, ODT i TXT, używając tego kodu:
Kotlin
startActivityForResult( Intent(Intent.ACTION_OPEN_DOCUMENT).apply { addCategory(Intent.CATEGORY_OPENABLE) type = "*/*" putExtra(Intent.EXTRA_MIME_TYPES, arrayOf( "application/pdf", // .pdf "application/vnd.oasis.opendocument.text", // .odt "text/plain" // .txt )) }, REQUEST_CODE )
Java
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("*/*"); intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[] { "application/pdf", // .pdf "application/vnd.oasis.opendocument.text", // .odt "text/plain" // .txt }); startActivityForResult(intent, REQUEST_CODE);
Zapisywanie plików na dodatkowych woluminach pamięci masowej
Dodatkowe woluminy pamięci masowej obejmują karty SD. Informacje o danym woluminie pamięci masowej możesz uzyskać za pomocą klasy StorageVolume.
Uwzględnij logikę opartą na wersji Androida, na której działa aplikacja.
Android 11
Zastosuj to podejście:
- Używaj modelu ograniczonego dostępu do miejsca na dane.
- być kierowane na Androida 10 (poziom interfejsu API 29) lub starszego;
- Zadeklaruj uprawnienie
WRITE_EXTERNAL_STORAGE. - Wykonaj jedną z tych czynności:
- Dostęp do plików za pomocą interfejsu API
MediaStore. - Bezpośredni dostęp do ścieżki pliku za pomocą interfejsów API, takich jak
Filelubfopen().
- Dostęp do plików za pomocą interfejsu API
Starsze wersje
Użyj platformy Storage Access Framework, która umożliwia użytkownikom wybranie lokalizacji na dodatkowym woluminie pamięci, w której aplikacja może zapisać plik.
Przenoszenie istniejących plików ze starszej lokalizacji pamięci
Katalog jest uznawany za starszą lokalizację miejsca na dane, jeśli nie jest katalogiem aplikacji ani publicznym katalogiem udostępnionym. Jeśli aplikacja tworzy lub wykorzystuje pliki w starszej lokalizacji, zalecamy przeniesienie plików aplikacji do lokalizacji dostępnych w ramach wydzielonej pamięci i wprowadzenie niezbędnych zmian w aplikacji, aby mogła ona działać z plikami w wydzielonej pamięci.
Utrzymywanie dostępu do starszej lokalizacji przechowywania na potrzeby migracji danych
Aplikacja musi zachować dostęp do starszej lokalizacji pamięci, aby móc przenieść pliki do lokalizacji dostępnych w ramach pamięci ograniczonej. Metoda, której należy użyć, zależy od docelowego poziomu interfejsu API aplikacji.
Jeśli aplikacja jest kierowana na Androida 11
Ustaw flagę
preserveLegacyExternalStoragenatrue, aby zachować starszy model pamięci masowej. Dzięki temu aplikacja będzie mogła przenieść dane użytkownika, gdy przejdzie on na nową wersję aplikacji kierowaną na Androida 11.Nadal rezygnuj z wydzielonego miejsca na dane, aby aplikacja mogła nadal uzyskiwać dostęp do plików w starszej lokalizacji na urządzeniach z Androidem 10.
Jeśli aplikacja jest kierowana na Androida 10
Zrezygnuj z ograniczonego dostępu do miejsca na dane, aby łatwiej zachować działanie aplikacji na różnych wersjach Androida.
Migracja danych aplikacji
Gdy aplikacja będzie gotowa do migracji, wykonaj te czynności:
- być kierowane na Androida 10 lub starszego;
- Zrezygnuj z ograniczonego dostępu do miejsca na dane, aby aplikacja miała dostęp do plików, które chcesz przenieść.
-
Wdróż kod, który używa interfejsu API
Filedo przenoszenia plików z ich bieżącej lokalizacji w/sdcard/do lokalizacji dostępnej w ramach ograniczonego dostępu do miejsca na dane:- Przenieś wszystkie prywatne pliki aplikacji do katalogu zwracanego przez metodę
getExternalFilesDir(). - Przenieś wszystkie udostępnione pliki inne niż multimedia do podkatalogu katalogu
Downloads/przeznaczonego dla aplikacji.
- Przenieś wszystkie prywatne pliki aplikacji do katalogu zwracanego przez metodę
- Usuń starsze katalogi pamięci aplikacji z katalogu
/sdcard/.
Po zainstalowaniu nowej wersji aplikacji użytkownicy kończą proces migracji danych na swoich urządzeniach. Możesz monitorować proces migracji wśród użytkowników, tworząc zdarzenie Analytics.
Gdy użytkownicy przeniosą swoje dane, opublikuj kolejną aktualizację aplikacji, w której kierujesz na Androida 11.
Udostępnianie treści innym aplikacjom
Aby udostępnić pliki aplikacji innej aplikacji, użyj FileProvider. W przypadku aplikacji, które muszą udostępniać sobie nawzajem pliki, zalecamy użycie mechanizmu dostarczania treści dla każdej aplikacji, a następnie synchronizowanie danych w miarę dodawania aplikacji do kolekcji.
Zapisywanie w pamięci podręcznej plików innych niż multimedialne
Metoda, której należy użyć, zależy od typu plików, które chcesz zapisać w pamięci podręcznej.
- Małe pliki lub pliki zawierające informacje poufne: użyj
Context#getCacheDir(). - Duże pliki lub pliki, które nie zawierają informacji poufnych: użyj
Context#getExternalCacheDir().
Eksportowanie plików niemultimedialnych na urządzenie
Zdefiniuj odpowiednią domyślną lokalizację do przechowywania plików innych niż multimedia. Zezwalaj użytkownikom na eksportowanie plików z katalogów aplikacji do bardziej ogólnie dostępnej lokalizacji. Użyj pobranych plików lub kolekcji dokumentów MediaStore, aby wyeksportować na urządzenie pliki inne niż multimedialne.
Obsługa plików aplikacji
Jeśli aplikacja tworzy pliki, do których inne aplikacje nie potrzebują lub nie powinny mieć dostępu, możesz przechowywać te pliki w miejscach przeznaczonych dla aplikacji.
Katalogi w pamięci wewnętrznej
System uniemożliwia innym aplikacjom dostęp do tych lokalizacji, a na Androidzie 10 (API na poziomie 29) i nowszych wersjach te lokalizacje są szyfrowane. Te lokalizacje są dobrym miejscem do przechowywania danych poufnych, do których dostęp ma tylko Twoja aplikacja.
Katalogi pamięci zewnętrznej
Jeśli pamięć wewnętrzna nie zapewnia wystarczającej ilości miejsca na pliki aplikacji, rozważ użycie pamięci zewnętrznej. Inna aplikacja może uzyskać dostęp do tych katalogów, jeśli ma odpowiednie uprawnienia, ale pliki przechowywane w tych katalogach są przeznaczone do użytku tylko przez Twoją aplikację.
Na Androidzie 4.4 (interfejs API na poziomie 19) lub nowszym aplikacja nie musi prosić o żadne uprawnienia związane z pamięcią, aby uzyskać dostęp do katalogów aplikacji w pamięci zewnętrznej.
Gdy użytkownik odinstaluje aplikację, pliki zapisane w pamięci aplikacji zostaną usunięte, dlatego nie należy używać tej pamięci do zapisywania niczego, co użytkownik chciałby zachować niezależnie od aplikacji.
Tymczasowa rezygnacja z ograniczonego dostępu do miejsca na dane
Zanim aplikacja będzie w pełni zgodna z ograniczonym dostępem do miejsca na dane, możesz tymczasowo zrezygnować z tej funkcji zarówno w testach, jak i w aplikacji produkcyjnej.
Rezygnacja z testów
Na Androidzie 10 (API na poziomie 29) i nowszych testy aplikacji są domyślnie uruchamiane w piaskownicy pamięci masowej. To środowisko uniemożliwia aplikacji dostęp do plików spoza katalogu aplikacji i katalogów udostępnianych publicznie.
Jeśli test generuje pliki dla hosta, takie jak zrzuty ekranu, dane debugowania, dane o pokryciu lub wskaźniki skuteczności, możesz zapisać te pliki w katalogach globalnych. Aby to zrobić, dodaj do odpowiedniego środowiska, które wywołuje am instrument, tę flagę:
-e no-isolated-storage 1
Ta flaga wpływa na wszystkie zachowania elementu testowania z instrumentacją i na cały wywołany kod testowy. Dlatego gdy używasz tej flagi, nie możesz sprawdzić zgodności aplikacji z ograniczonym dostępem do miejsca na dane. W przypadku danych wyjściowych testu lepiej jest zapisywać je w pamięci masowej o ograniczonym dostępie do miejsca na dane, która jest możliwa do odczytu przez powłokę. Następnie możesz pobrać ten katalog na poziomie aplikacji. Aby określić, z którego katalogu chcesz pobrać dane, wywołaj getExternalMediaDirs().
Rezygnacja w aplikacji produkcyjnej
Jeśli Twoja aplikacja jest kierowana na Androida 10 (poziom interfejsu API 29) lub starszego, możesz tymczasowo zrezygnować z ograniczonego dostępu do miejsca na dane w aplikacji produkcyjnej. Jeśli jednak kierujesz aplikację na Androida 10, musisz ustawić wartość requestLegacyExternalStorage na true w pliku manifestu aplikacji:
<manifest ... > <!-- This attribute is "false" by default on apps targeting Android 10. --> <application android:requestLegacyExternalStorage="true" ... > ... </application> </manifest>
Aby sprawdzić, jak aplikacja kierowana na Androida 10 lub starszego zachowuje się podczas korzystania z ograniczonego dostępu do miejsca na dane, możesz wyrazić zgodę na to zachowanie, ustawiając wartość requestLegacyExternalStorage na false. Jeśli testujesz aplikację na urządzeniu z Androidem 11, możesz też użyć flag zgodności aplikacji, aby sprawdzić jej działanie z ograniczonym dostępem do miejsca na dane i bez niego.
Dodatkowe materiały
Więcej informacji o miejscu na dane na urządzeniach z Androidem znajdziesz w tych materiałach: