Skip to content

Commit 175c56a

Browse files
committed
dagger post published and storage added
1 parent 4158260 commit 175c56a

File tree

5 files changed

+185
-0
lines changed

5 files changed

+185
-0
lines changed

_drafts/2019-08-12-storage.md

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
---
2+
layout: post
3+
title: "Storage"
4+
date: 2019-08-12
5+
categories: ["Przechowywanie"]
6+
image: store/storage
7+
github: store/tree/master/storage
8+
description: "Przechowywanie danych"
9+
keywords: "store, data, external, internal, file, files, cache, lru, android, programowanie, programming"
10+
---
11+
12+
## Wstęp
13+
`Android` używa systemu plików opartego o dyski podobnego do rozwiązań znanych z wielu innych platform. Obiekty typu `File` pozwalają na zarządzanie strukturą plików (zapis, odczyt) i mogą być wykorzystywane do operowania i przechowywania dużych jak i niewielkich informacji. Wszystkie urządzenia posiadają dwie przestrzenie pamięci: wewnętrzną (`internal`) i zewnętrzną (`external`). Takie rozróżnienie pochodzi z czasów w których większość urządzeń posiadała pamięć wbudowaną i wymienną (np. karta `micro SD`). Obecnie jednak znaczna część urządzeń dzieli pamięć wbudowaną na `internal` i `external` oraz dostarcza możliwość rozszerzenia pamięci o pamięć przenośną. Z związku z czym lokalizacja pamięci może się różnić w zależności od konfiguracji urządzenia dlatego należy wystrzegać się ścieżek bezwzględnych.
14+
15+
## Internal
16+
`Internal storage` jest zawsze dostępną pamięcią wbudowaną w urządzenie. Przechowuje pliki domyślnie prywatne dostępne tylko dla aplikacji. Kiedy aplikacja zostanie odinstalowana usunięte zostaną również jej pliki. Jest pewnym wyborem w sytuacji kiedy dane mają być widoczne tylko dla aplikacji i są powiązane z jej istnieniem. Warto dodać, że domyślnie aplikacje instalowane są w pamięci `internal`. Przeważnie posiada mniejszy rozmiar niż `external`. Nie wymaga żadnych dodatkowych uprawnień. Dostęp do pamięci aplikacji (katalogu) odbywa się przez `getFilesDir`.
17+
18+
{% highlight kotlin %}
19+
class InternalStorage {
20+
21+
fun readFile() {
22+
//represents file system associated with the app
23+
val dir = getFilesDir() //the name of directory is app package
24+
val file = File(dir, "file.txt")
25+
//do something with the file
26+
}
27+
28+
fun writeFile() {
29+
val content = "some file content"
30+
31+
//open file by constructor or by stream and write to it
32+
//use MODE_PRIVATE to make it private for only this app
33+
openFileOutput("file.txt", Context.MODE_PRIVATE).use {
34+
//write data content
35+
it.write(content.toByteArray())
36+
}
37+
38+
//to make it public use FileProvider instead of MODE_WORLD_READABLE
39+
}
40+
41+
fun deleteFile() {
42+
val file = File(filesDir, "file.txt")
43+
if(file.exists()) {
44+
file.delete()
45+
}
46+
}
47+
48+
fun checkSpaceInStorage() {
49+
val total = filesDir.totalSpace
50+
val free = filesDir.freeSpace
51+
}
52+
53+
fun listFilesInStorage() {
54+
val list = fileList()
55+
//do something with files names
56+
}
57+
58+
//do more things with File class
59+
}
60+
{% endhighlight %}
61+
62+
## External
63+
`External storage` nie jest zawsze dostępną pamięcią ponieważ może być powiązana z pamięcią wymienną, która w danej chwili nie jest zamontowana w urządzeniu. Zapisane dane są widoczne dla innych aplikacji i systemów, a po odinstalowaniu aplikacji pliki mogą, ale nie muszą być usuniętę. Wykorzystywana jest przede wszystkim do przechowywania danych niewrażliwych oraz takich, które mogą być udostępnione dla innych aplikacji lub dostępne dla użytkownika z poziomu eksploratora plików w komputerze. System dostarcza kilka publicznych katalogów dla różnych typów plików dostępnych z poziomu klasy `Environment`. Dostęp do folderu publicznego odbywa się przez `getExternalStoragePublicDirectory` natomiast do prywatnego przy użyciu `getExternalFilesDir`.
64+
65+
{% highlight kotlin %}
66+
class ExternalStorage {
67+
68+
fun doSomethingWithFile() {
69+
if(hasPermissions()) {
70+
//write or read to file depends on needs
71+
if(isWriteable()) {
72+
val file = getPrivateDirectory()
73+
//write to file
74+
}
75+
else if(isReadable()) {
76+
//get file and read it
77+
}
78+
}
79+
}
80+
81+
//stay after uninstall, available for other apps
82+
fun getPublicDirectoryFile() : File? {
83+
//use one of Environment folder or pass null to get the root
84+
val file = File(Environment.getExternalStoragePublicDirectory(null), "public.txt")
85+
if(file.mkdirs()) {
86+
//file has not been created
87+
}
88+
return file
89+
}
90+
91+
//remove after uninstall, not visible for MediaStore
92+
fun getPrivateDirectoryFile() : File? {
93+
//use one of Environment folder or pass null to get the root
94+
val file = File(getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS), "private.txt")
95+
if(file.mkdirs()) {
96+
//file has not been created
97+
}
98+
return file
99+
}
100+
101+
//there can be more than one external storage, check it
102+
fun listExternalDirectories() {
103+
val list = getExternalFilesDirs(null)
104+
if(list[0] != null) {
105+
//primary external storage exists
106+
}
107+
if(list[1] != null) {
108+
//secondary external storage exists (it should be removable storage like micro SD)
109+
}
110+
//in most cases there are no more than two directories
111+
}
112+
113+
//it depends on API level if they are needed or not
114+
fun hasPermissions() : Boolean {
115+
//check if the app has READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE provided
116+
return true
117+
}
118+
119+
//check is storage writable or readable before do something
120+
fun isWritable(): Boolean {
121+
return Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED
122+
}
123+
124+
fun isReadable(): Boolean {
125+
return Environment.getExternalStorageState() in
126+
setOf(Environment.MEDIA_MOUNTED, Environment.MEDIA_MOUNTED_READ_ONLY)
127+
}
128+
}
129+
{% endhighlight %}
130+
131+
## Cache
132+
Pamięć podręczna zlokalizowana jest w pamięci `internal` i ograniczona jest do 1MB dlatego należy mieć na uwadzę regularne manualne czyszczenie nieużywanych już plików. W przypadku przekroczenia rozmiaru system może automatyczmnie usunąć niektóre pliki. Przeznaczona do przechowywania niedużych danych roboczych aplikacji. Może być także zamiennikiem przekazywania informacji między komponentami zamiast `extras` w `Intent` lub `Bundle` (np. zapis kolekcji przy obrocie lub przekazaniu ich do kolejnego ekranu). Dostęp do niej odbywa się przy pomocy metody `getCacheDir` lub `getExternalCacheDir` (dla pamięci zewnętrznej) natomiast tworzenie nowego pliku metodą `createTempFile`.
133+
134+
{% highlight kotlin %}
135+
class Cache {
136+
137+
fun readCacheFile() {
138+
//from getCacheDir
139+
val file = File(getCacheDir(), "cache.txt")
140+
//read cache, but be aware if still exists
141+
}
142+
143+
fun writeCacheFile() {
144+
val file = File.createTempFile("cache", "txt", getCacheDir())
145+
//write cache, but be aware if still exists
146+
//e.g. convert object collection to json
147+
}
148+
}
149+
{% endhighlight %}
150+
151+
## LruCache
152+
Alternatywnym podejściem do implementacji pamięci podręcznej w stosunku do standardowego `cache` opartego o system plików z lokalizacji `getCacheDir` jest wykorzystanie także pamięci operacyjnej urządzenia do której dostęp jest szybszy niż do dysku. Przykładem realizacji może być `LruCache`, który przechowuje obiekty w postaci kolejki `klucz - wartość`. Dba o prawidłową kolejność wpisów (bajtów) w kolejce oraz automatyczne usuwanie obiektów w przypadku przekroczenia maksymalnego rozmiaru. Dodatkowo zastosowanie podobnego mechanizmu dla dyskowej pamięci tymczasowej `DiskLruCache` pozwala na zoptymalizowanie zarządzania pamięcią podręczną.
153+
154+
{% highlight kotlin %}
155+
class LruCacheActivity : AppCompatActivity() {
156+
157+
//set key and value type
158+
private lateinit var memoryCache : LruCache<String, String>
159+
160+
override fun onCreate(savedInstanceState: Bundle?) {
161+
super.onCreate(savedInstanceState)
162+
163+
initMemoryCache()
164+
useMemoryCache() //use some put, get, remove, resize method in memory
165+
}
166+
167+
fun initMemoryCache() {
168+
//calculate max memory to 10% of available memory
169+
val maxMemory = (Runtime.getRuntime().maxMemory() / 1024).toInt()
170+
171+
memoryCache = object: LruCache<String, String>(maxMemory / 10) {
172+
override fun sizeOf(key: String, value: String): Int {
173+
return value.toByteArray().size
174+
}
175+
}
176+
}
177+
178+
fun useMemoryCache() {
179+
memoryCache.put("key", "some content like json")
180+
val value = memoryCache.get("key")
181+
memoryCache.remove("key")
182+
memoryCache.resize(memoryCache.size() * 2)
183+
}
184+
}
185+
{% endhighlight %}
File renamed without changes.

assets/img/posts/store/storage.jpg

436 KB
Loading
18.5 KB
Loading
49.6 KB
Loading

0 commit comments

Comments
 (0)