Aby zapewnić użytkownikom większą kontrolę nad plikami i ograniczyć ich nadmiar, w Androidzie 10 wprowadziliśmy nowy model przechowywania danych w aplikacjach o nazwie zakresowy dostęp do pamięci. Zmiany w zakresie pamięci masowej wpływają na 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 do obsługi pamięci o ograniczonym zakresie, postępuj zgodnie ze sprawdzonymi metodami w przypadku typowych zastosowań pamięci, które zostały opisane w tym przewodniku. 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ą mieć dostępu lub nie powinny go mieć. System udostępnia miejsca na dane przypisane do aplikacji, w których można zarządzać takimi plikami.
Więcej informacji o przechowywaniu plików na Androidzie i uzyskiwaniu do nich dostępu znajdziesz w przewodnikach szkoleniowych 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 (wideo, obrazów i audio) oraz wyjaśniamy ogólne podejście, które może zastosować Twoja aplikacja. W tabeli poniżej znajdziesz podsumowanie każdego z tych przypadków użycia oraz linki do sekcji zawierających więcej szczegółów.
Przypadek użycia | Podsumowanie |
---|---|
Wyświetlanie wszystkich plików z obrazami lub filmami | Stosuj to samo podejście w przypadku wszystkich wersji Androida. |
Wyświetlanie zdjęć lub filmów z określonego folderu | Stosuj to samo podejście w przypadku wszystkich wersji Androida. |
Dostęp do informacji o lokalizacji ze zdjęć | Jeśli aplikacja korzysta z ograniczonego dostępu do miejsca na dane, zastosuj jedno z tych podejść. Jeśli Twoja aplikacja nie korzysta z ograniczonego dostępu do miejsca na dane, zastosuj inne podejście. |
Określanie lokalizacji przechowywania nowych pobranych plików | Jeśli aplikacja korzysta z ograniczonego dostępu do miejsca na dane, zastosuj jedno z tych podejść. Jeśli Twoja aplikacja nie korzysta z ograniczonego dostępu do miejsca na dane, zastosuj inne podejście. |
Eksportowanie plików multimedialnych użytkownika na urządzenie | Stosuj to samo podejście w przypadku 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 pamięci o ograniczonym zakresie i zastosuj podejście dla Androida 9 i starszych wersji. |
Importowanie pojedynczego obrazu, który już istnieje | Stosuj to samo podejście w przypadku wszystkich wersji Androida. |
Zrobienie pojedynczego zdjęcia | Stosuj to samo podejście w przypadku wszystkich wersji Androida. |
Udostępnianie plików multimedialnych w innych aplikacjach | Stosuj to samo podejście w przypadku wszystkich wersji Androida. |
Udostępnianie plików multimedialnych określonej aplikacji | Stosuj to samo podejście w przypadku 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 pamięci o ograniczonym zakresie i zastosuj podejście dla Androida 9 i starszych wersji. |
Wyświetlanie plików z obrazami lub filmami z wielu folderów
Wysyłanie zapytań dotyczących kolekcji multimediów za pomocą interfejsu query()
API. Aby filtrować lub sortować pliki multimedialne, dostosuj parametry projection
, selection
, selectionArgs
i sortOrder
.
Wyświetlanie zdjęć lub filmów z określonego folderu
Zastosuj to podejście:
- Postępuj zgodnie ze sprawdzonymi metodami opisanymi w artykule Żądanie uprawnień aplikacji i poproś o uprawnienie
READ_EXTERNAL_STORAGE
. - Pobieranie plików multimedialnych na podstawie wartości parametru
MediaColumns.DATA
, który zawiera bezwzględną ścieżkę do pliku multimedialnego na dysku.
Uwaga: gdy uzyskujesz dostęp do istniejącego pliku multimedialnego, możesz użyć wartości z kolumny DATA
w logice. 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ę 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 pamięci o ograniczonym zakresie, wykonaj czynności opisane w sekcji Informacje o lokalizacji na zdjęciach w przewodniku po pamięci multimediów.
Określanie lokalizacji zapisu nowych pobranych plików
Jeśli Twoja aplikacja korzysta z pamięci o ograniczonym zakresie, pamiętaj o lokalizacji, 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.
W Androidzie 11 i nowszych pliki w zewnętrznym katalogu specyficznym dla aplikacji nie są dostępne dla innych aplikacji, nawet jeśli używasz DownloadManager
do pobierania tych plików.
Eksportowanie plików multimedialnych użytkownika na urządzenie
Określ odpowiednią domyślną lokalizację do przechowywania plików multimedialnych użytkownika:
- Umożliwia użytkownikom wybór, czy pliki multimedialne mają być odczytywane przez inne aplikacje, za pomocą miejsca na dane specyficznego dla aplikacji lub pamięci współdzielonej.
- Zezwalaj użytkownikom na eksportowanie plików z katalogów specyficznych dla 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
Zastosuj logikę opartą na wersjach Androida, na których działa Twoja aplikacja.
Android 11
Zastosuj to podejście:
- Utwórz oczekujący zamiar dla żądania zapisu lub usunięcia w aplikacji, używając
MediaStore.createWriteRequest()
lubMediaStore.createTrashRequest()
, a następnie poproś użytkownika o zezwolenie na edytowanie zestawu plików, wywołując ten zamiar. Oceń odpowiedź użytkownika:
- Jeśli uprawnienia zostały przyznane, kontynuuj operację modyfikowania lub usuwania.
- Jeśli uprawnienie nie zostało przyznane, wyjaśnij użytkownikowi, dlaczego funkcja w aplikacji wymaga tego uprawnienia.
Dowiedz się więcej o zarządzaniu grupami plików multimedialnych za pomocą tych metod dostępnych na urządzeniach z Androidem 11 i nowszym.
działa w systemie Android 10,
Jeśli Twoja aplikacja jest kierowana na Androida 10 (poziom API 29), zrezygnuj z zakresu pamięci i nadal używaj podejścia stosowanego w przypadku Androida 9 i starszych wersji, aby wykonać tę operację.
Android 9 lub starszy
Zastosuj to podejście:
- Postępuj zgodnie ze sprawdzonymi metodami opisanymi w artykule Żądanie uprawnień aplikacji i poproś o uprawnienie
WRITE_EXTERNAL_STORAGE
. - Do modyfikowania lub usuwania plików multimedialnych 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 do tej operacji lub selektora systemowego.
Wyświetlanie własnego interfejsu
Zastosuj to podejście:
- Postępuj zgodnie ze sprawdzonymi metodami opisanymi w artykule Żądanie uprawnień aplikacji i poproś o uprawnienie
READ_EXTERNAL_STORAGE
. - Użyj interfejsu
query()
API, aby wysłać zapytanie do kolekcji multimediów. - Wyświetl wyniki w interfejsie niestandardowym aplikacji.
Użyj selektora systemowego
Użyj intencji ACTION_GET_CONTENT
, która prosi użytkownika o wybranie obrazu do zaimportowania.
Jeśli chcesz odfiltrować typy obrazów, które selektor systemowy wyświetla użytkownikowi do wyboru, możesz użyć setType()
lub EXTRA_MIME_TYPES
.
Zrobienie pojedynczego zdjęcia
Jeśli chcesz zrobić jedno zdjęcie do wykorzystania w aplikacji (np. jako zdjęcie profilowe użytkownika), użyj intencji ACTION_IMAGE_CAPTURE
, aby poprosić użytkownika o zrobienie zdjęcia za pomocą aparatu urządzenia. System zapisuje zrobione zdjęcie w tabeli MediaStore.Images
.
Udostępnianie plików multimedialnych w innych aplikacjach
Użyj metody
insert()
, aby dodać rekordy bezpośrednio do MediaStore. Więcej informacji znajdziesz w sekcji Dodawanie elementu w przewodniku po przechowywaniu multimediów.
Udostępnianie plików multimedialnych w określonej aplikacji
Użyj komponentu Androida FileProvider
zgodnie z opisem w przewodniku Konfigurowanie udostępniania plików.
Dostęp do plików z kodu lub bibliotek, które używają bezpośrednich ścieżek do plików
Zastosuj logikę opartą na wersjach Androida, na których działa Twoja aplikacja.
Android 11
Zastosuj to podejście:
- Postępuj zgodnie ze sprawdzonymi metodami opisanymi w artykule Żądanie uprawnień aplikacji i poproś o uprawnienie
READ_EXTERNAL_STORAGE
. - Uzyskaj dostęp do plików za pomocą bezpośrednich ścieżek do plików.
Więcej informacji znajdziesz w sekcji dotyczącej otwierania plików multimedialnych za pomocą bezpośrednich ścieżek do plików.
działa w systemie Android 10,
Jeśli Twoja aplikacja jest kierowana na Androida 10 (poziom API 29), zrezygnuj z zakresu pamięci i nadal używaj podejścia stosowanego w przypadku Androida 9 i starszych wersji, aby wykonać tę operację.
Android 9 lub starszy
Zastosuj to podejście:
- Postępuj zgodnie ze sprawdzonymi metodami opisanymi w artykule Żądanie uprawnień aplikacji i poproś o uprawnienie
WRITE_EXTERNAL_STORAGE
. - Uzyskaj dostęp do plików za pomocą bezpośrednich ścieżek do plików.
Obsługa plików innych niż multimedia
W tej sekcji opisujemy niektóre typowe przypadki użycia związane z obsługą plików innych niż multimedia i wyjaśniamy ogólne podejście, które może zastosować Twoja aplikacja. W tabeli poniżej znajdziesz podsumowanie każdego z tych przypadków użycia oraz linki do sekcji zawierających więcej szczegółów.
Przypadek użycia | Podsumowanie |
---|---|
Otwieranie pliku dokumentu | Stosuj to samo podejście w przypadku wszystkich wersji Androida. |
Zapisywanie plików na dodatkowych woluminach pamięci | W przypadku Androida 11 użyj jednego podejścia. W przypadku starszych wersji Androida zastosuj inne podejście. |
Przenoszenie istniejących plików z starszej lokalizacji pamięci | W miarę możliwości przenieś pliki do pamięci o ograniczonym zakresie. W razie potrzeby zrezygnuj z pamięci o ograniczonym zakresie na urządzeniach z Androidem 10. |
Udostępnianie treści w innych aplikacjach | Stosuj to samo podejście w przypadku wszystkich wersji Androida. |
Buforowanie plików multimedialnych | Stosuj to samo podejście w przypadku wszystkich wersji Androida. |
Eksportowanie plików innych niż multimedia na urządzenie | Jeśli aplikacja korzysta z ograniczonego dostępu do miejsca na dane, zastosuj jedno z tych podejść. Jeśli Twoja aplikacja nie korzysta z ograniczonego dostępu do miejsca na dane, zastosuj inne podejście. |
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 wyświetlać 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 woluminach pamięci dodatkowej
Woluminy pamięci dodatkowej obejmują karty SD. Dostęp do informacji o danym woluminie pamięci masowej można uzyskać za pomocą klasy StorageVolume
.
Zastosuj logikę opartą na wersji Androida, na której działa Twoja aplikacja.
Android 11
Zastosuj to podejście:
- Używaj modelu pamięci o ograniczonym zakresie.
- kierować aplikację na Androida 10 (interfejs API na poziomie 29) lub starszego;
- Zadeklaruj uprawnienie
WRITE_EXTERNAL_STORAGE
. - Wykonaj jedną z tych czynności:
- Dostęp do pliku za pomocą interfejsu API
MediaStore
. - Bezpośredni dostęp do ścieżki pliku za pomocą interfejsów API, takich jak
File
lubfopen()
.
- Dostęp do pliku za pomocą interfejsu API
Działanie na starszych wersjach
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 zapisywać plik.
Przenoszenie istniejących plików z starszej lokalizacji pamięci
Katalog jest uważany za starszą lokalizację pamięci, jeśli nie jest katalogiem specyficznym dla aplikacji ani publicznym katalogiem udostępnionym. Jeśli Twoja aplikacja tworzy lub wykorzystuje pliki w starszej lokalizacji pamięci, zalecamy przeniesienie plików aplikacji do lokalizacji dostępnych w pamięci o ograniczonym zakresie i wprowadzenie niezbędnych zmian w aplikacji, aby działała z plikami w pamięci o ograniczonym zakresie.
Zachowaj dostęp do starszej lokalizacji pamięci na potrzeby migracji danych
Aplikacja musi mieć dostęp do starszej lokalizacji pamięci, aby przenieść pliki aplikacji do lokalizacji dostępnych w ramach pamięci o ograniczonym zakresie. Podejście, którego należy użyć, zależy od docelowego poziomu interfejsu API aplikacji.
Jeśli Twoja aplikacja jest kierowana na Androida 11
Ustaw flagę
preserveLegacyExternalStorage
natrue
, aby zachować starszy model przechowywania danych. Dzięki temu aplikacja będzie mogła przenieść dane użytkownika, gdy przejdzie on na nową wersję aplikacji kierowaną na Androida 11.Zrezygnuj z pamięci o ograniczonym zakresie, aby aplikacja mogła nadal uzyskiwać dostęp do plików w starszej lokalizacji pamięci na urządzeniach z Androidem 10.
Jeśli Twoja aplikacja jest kierowana na Androida 10
Zrezygnuj z pamięci o ograniczonym zakresie, aby łatwiej było zachować spójne działanie aplikacji w różnych wersjach Androida.
Przenoszenie danych aplikacji
Gdy aplikacja będzie gotowa do migracji, wykonaj te czynności:
- kierować aplikację na Androida 10 lub starszego;
- Zrezygnuj z pamięci o ograniczonym zakresie, aby aplikacja miała dostęp do plików, które chcesz przenieść.
-
Wdróż kod, który korzysta z interfejsu
File
API, aby przenieść pliki z bieżącej lokalizacji w/sdcard/
do lokalizacji dostępnej w ramach pamięci o ograniczonym zakresie:- Przenieś wszystkie pliki aplikacji prywatnej do katalogu zwróconego przez metodę
getExternalFilesDir()
. - Przenoszenie dowolnych udostępnionych plików innych niż multimedia do podkatalogu
Downloads/
dedykowanego aplikacji.
- Przenieś wszystkie pliki aplikacji prywatnej do katalogu zwróconego przez metodę
- Usuń starsze katalogi pamięci aplikacji z katalogu
/sdcard/
.
Po zainstalowaniu nowej wersji aplikacji użytkownicy przechodzą na swoich urządzeniach proces migracji danych. Możesz monitorować proces migracji w przypadku wszystkich użytkowników, tworząc zdarzenie analityczne.
Po przeniesieniu danych przez użytkowników opublikuj kolejną aktualizację aplikacji, w której kierujesz ją na Androida 11.
Udostępnianie treści w innych aplikacjach
Aby udostępnić pliki aplikacji jednej innej aplikacji, użyjFileProvider
. W przypadku aplikacji, które muszą udostępniać sobie pliki, zalecamy używanie dostawcy treści w każdej z nich, a następnie synchronizowanie danych w miarę dodawania aplikacji do kolekcji.
Buforowanie plików innych niż multimedia
Podejście, którego należy użyć, zależy od typu plików, które chcesz buforować.
- 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
Określ odpowiednią domyślną lokalizację do przechowywania plików innych niż multimedialne. Zezwalaj użytkownikom na eksportowanie plików z katalogów specyficznych dla aplikacji do bardziej ogólnie dostępnej lokalizacji. Użyj pobrań lub kolekcji dokumentów w MediaStore, aby wyeksportować na urządzenie pliki inne niż multimedia.
Obsługa plików specyficznych dla aplikacji
Jeśli aplikacja tworzy pliki, do których inne aplikacje nie muszą mieć dostępu lub nie powinny go mieć, możesz je przechowywać w lokalizacjach pamięci specyficznych dla aplikacji.
Katalogi pamięci wewnętrznej
System uniemożliwia innym aplikacjom dostęp do tych lokalizacji, a na Androidzie 10 (API na poziomie 29) i nowszym są one szyfrowane. Te lokalizacje są dobrym miejscem do przechowywania danych wrażliwych, 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. Chociaż inna aplikacja może uzyskać dostęp do tych katalogów, jeśli ma odpowiednie uprawnienia, pliki w nich przechowywane są przeznaczone do użytku tylko przez Twoją aplikację.
Na Androidzie 4.4 (poziom API 19) lub nowszym aplikacja nie musi prosić o żadne uprawnienia związane z pamięcią, aby uzyskać dostęp do katalogów specyficznych dla aplikacji w pamięci zewnętrznej.
Gdy użytkownik odinstaluje aplikację, pliki zapisane w pamięci specyficznej dla aplikacji zostaną usunięte. Dlatego nie należy używać tej pamięci do zapisywania niczego, co użytkownik chce zachować niezależnie od aplikacji.
Tymczasowa rezygnacja z pamięci o ograniczonym zakresie
Zanim Twoja aplikacja stanie się w pełni zgodna z zakresem pamięci, możesz tymczasowo zrezygnować z tej funkcji zarówno w testach, jak i w wersji produkcyjnej aplikacji.
Rezygnacja z udziału w testach
Na Androidzie 10 (API na poziomie 29) i nowszych testy aplikacji są domyślnie przeprowadzane w piaskownicy pamięci. Ta piaskownica uniemożliwia aplikacji dostęp do plików poza katalogiem aplikacji i katalogami udostępnionymi publicznie.
Jeśli test generuje pliki dla hosta, takie jak zrzuty ekranu, dane debugowania, dane o pokryciu lub dane o wydajności, możesz zapisać te pliki w globalnych katalogach. Aby to zrobić, dodaj do odpowiedniego narzędzia, które wywołuje am instrument
, ten flag:
-e no-isolated-storage 1
Ta flaga wpływa na wszystkie działania testu z instrumentacją i na cały wywoływany kod testu. Dlatego, gdy używasz tego flagi, nie możesz sprawdzić zgodności aplikacji z pamięcią o ograniczonym zakresie. W przypadku danych wyjściowych testu lepiej jest zapisywać dane w pamięci o zakresie aplikacji, która jest czytelna dla powłoki. Następnie możesz pobrać ten katalog w zakresie aplikacji. Aby określić, z którego katalogu pobrać dane, wywołaj funkcję
getExternalMediaDirs()
.
Rezygnacja w wersji produkcyjnej aplikacji
Jeśli Twoja aplikacja jest przeznaczona na Androida 10 (poziom interfejsu API 29) lub starszego, możesz tymczasowo zrezygnować z pamięci o ograniczonym zakresie w aplikacji produkcyjnej. Jeśli jednak Twoja aplikacja jest przeznaczona 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 pamięci o ograniczonym zakresie, możesz włączyć 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ć, jak aplikacja działa z zakresem pamięci lub bez niego.
Dodatkowe materiały
Więcej informacji o miejscu na dane na Androidzie znajdziesz w tych materiałach: