ukryj menu
SPEC
aktualizacja: 2022-03-11 11:14:23
Tematyka:
- System plików urządzenia, dostęp do katalogów i plików
- ListView i ArrayAdapter - tworzenie list przewijanych
- Dialogs - okienka
1. Scenariusz aplikacji na dziś
przy starcie aplikacji powinien się utworzyć folder główny WaszeImieNazwisko w folderze PICTURES
oraz trzy przykładowe podfoldery na albumy zdjęć:
--- miejsca
--- ludzie
--- rzeczy
przy kolejnym starcie aplikacja sprawdza czy taki folder już istnieje, jeśli tak, to go nie tworzy
kolejne foldery będzie dodawał już użytkownik w dalszej części projektu
2. Ekrany (Activities) na dziś
w których odbywają się jakieś działania
MainActivity - uprawnienia, system plików
AlbumsActivity - ListView, ArrayAdapter
3. ListView i ArrayAdapter - ekran prezentujący albumy w postaci listy
a) utwórz w folderze Layout (New / Layout Resource File) plik xml odpowiedzialny za wygląd jednego wiersza w ListView:
prawy klawisz na katalog res / layout
potem
New / Layout Resource File / root element / LinearLayout
proponowana struktura wewnątrz tego pliku
- LinearLayout (horizontal)
--- ImageView
--- TextView
b) w pliku xml AlbumsActivity, dodaj statycznie ListView, dodaj id
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
/>kopiuj
android:layout_width="match_parent"
android:layout_height="match_parent"
/>kopiuj
c) w kodzie Activity tego ekranu:
odwołaj się do ListView (findview)
dla testów utwórz prostą tablicę stringów:
String[] array = new String[]{"wynik 1","wynik 2","wynik 3"};kopiuj
utwórz obiekt ArrayAdapter:
ArrayAdapter<String> adapter = new ArrayAdapter<>(
MainActivity.this, // tzw Context
R.layout.row_layout, // nazwa pliku xml naszego wiersza na liście
R.id.tv1, // id pola txt w wierszu
array ); // tablica przechowująca testowe danekopiuj
MainActivity.this, // tzw Context
R.layout.row_layout, // nazwa pliku xml naszego wiersza na liście
R.id.tv1, // id pola txt w wierszu
array ); // tablica przechowująca testowe danekopiuj
przypisz adapter do ListView:
listView.setAdapter(adapter);kopiuj
w tym momencie już powinna się wyświetlać lista z trzema testowymi wierszami
których wygląd ustalamy w pliku xml (pkt a)
d) dodaj obsługę kliknięcia w wiersz ListView (nie wklejaj, napisz setonitem, new OnItem...)
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Log.d("TAG","numer klikanego wiersza w ListView = " + i);
}
});
kopiuj
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Log.d("TAG","numer klikanego wiersza w ListView = " + i);
}
});
kopiuj
e) długie przytrzymanie elementu listy
listView1.setOnItemLongClickListener...kopiuj
4. AndroidManifest.xml - umożliwienie ingerencji w system plików
W pliku AndroidManifest.xml dodaj uprawnienia uses-permission :
napisz <uses-permission
a z listy wybierz dwa razy:
WRITE_EXTERNAL_STORAGE kopiuj
READ_EXTERNAL_STORAGE kopiuj
UWAGA: w wersjach Androida >= 6 należy jeszcze manualnie ustawić uprawnienia dla danej aplikacji w telefonie/tablecie
lub wywołać okno dialoga, które umożliwi udzielenie uprawnień przez użytkownika
5. Uprawnienia - dialog
<application
...
android:requestLegacyExternalStorage="true"
...
>kopiuj
kolejny krok to wywołanie funkcji która pokaże oko dialogowe
public void checkPermission(String permission, int requestCode) {
// jeśli nie jest przyznane to zażądaj
if (ContextCompat.checkSelfPermission(MainActivity.this, permission) == PackageManager.PERMISSION_DENIED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{permission}, requestCode);
} else {
Toast.makeText(MainActivity.this, "Permission already granted", Toast.LENGTH_SHORT).show();
}
}kopiuj
wywołanie w onCreate()
dla androida od wersji 9 potrzebne jest zezwolenie w pliku manifest na jakiekolwiek ingerencje
w system plików poza aplikacją
<application
...
android:requestLegacyExternalStorage="true"
...
>kopiuj
kolejny krok to wywołanie funkcji która pokaże oko dialogowe
public void checkPermission(String permission, int requestCode) {
// jeśli nie jest przyznane to zażądaj
if (ContextCompat.checkSelfPermission(MainActivity.this, permission) == PackageManager.PERMISSION_DENIED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{permission}, requestCode);
} else {
Toast.makeText(MainActivity.this, "Permission already granted", Toast.LENGTH_SHORT).show();
}
}kopiuj
wywołanie w onCreate()
checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, 100);kopiuj
reakcja na rezultat czyli przyznanie lub nie, permission
reakcja na rezultat czyli przyznanie lub nie, permission
funkcję piszemy w klasie, poza onCreate
najlepiej napisać onreqper... i poczekać na podpowiedź
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
//
switch (requestCode) {
case 100:
if (grantResults.length > 0 &&
grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//tak
} else {
//nie
}
break;
case 101 :
break;
}
}kopiuj
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
//
switch (requestCode) {
case 100:
if (grantResults.length > 0 &&
grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//tak
} else {
//nie
}
break;
case 101 :
break;
}
}kopiuj
6. System plików Androida
proponuję tworzyć folder na pliki aplikacji w folderze DIRECTORY_PICTURES:
File pic = Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES );kopiuj
utworzenie katalogu
File dir = new File(pic, "moje_nazwisko");kopiuj
dir.mkdir()kopiuj
przykład zwracający tablicę plików w katalogu
File[] files = pic.listFiles() // tablica plikówkopiuj
files.length // ilość plikówkopiuj
Arrays.sort(files) // sortowanie plików wg nazwykopiuj
pętla czytająca dane z plików w katalogu
for (File file : pic.listFiles()){
//
}kopiuj
//
}kopiuj
potrzebne operacje na systemie plików
pic.getPath() // pełna ścieżka
pic.getName() // nazwa
pic.getParent() // nazwa nadrzędnego
pic.exists() // czy istnieje
pic.isDirectory() // czy jest katalogiem
pic.isFile() // czy jest plikiem
pic.isHidden() // czy ukrytykopiuj
pic.getName() // nazwa
pic.getParent() // nazwa nadrzędnego
pic.exists() // czy istnieje
pic.isDirectory() // czy jest katalogiem
pic.isFile() // czy jest plikiem
pic.isHidden() // czy ukrytykopiuj
usunięcie pliku / katalogu
file.delete();kopiuj
usunięcie katalogu (uwaga - przed usunięciem katalogu należy usunąć wszystkie pliki, najlepiej
pętlą foreach, jak w przykładzie poniżej)
for (File file : anyDir.listFiles()){
//usuwaj pliki
}kopiuj
//usuwaj pliki
}kopiuj
a potem usunąć katalog
dir.delete();kopiuj
dokumentacja:
https://developer.android.com/reference/java/io/File.html
pozbycie się paska tytułu u góry layoutu
7. Dialogi
posłużą m.in. jako zabezpieczenie przed przypadkowym usunięciem albumu czy zdjęcia,
do wprowadzania danych do aplikacji
a) dialog z jednym butonem
AlertDialog.Builder alert = new AlertDialog.Builder(context);
alert.setTitle("Uwaga!");
alert.setCancelable(false); //nie zamyka się po kliknięciu poza nim
alert.setMessage("TEST");
alert.setNeutralButton("OK", null).show(); // null to pusty clickkopiuj
b) dialog z ikoną i kliknięciem butona
AlertDialog.Builder alert = new AlertDialog.Builder(context);
alert.setTitle("Uwaga");
alert.setMessage("komunikat");
alert.setIcon(R.drawable.anyicon);
alert.setNeutralButton("OK", new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
//komunikat
}
});
alert.show();kopiuj
c) dialog z dwoma butonami, TAK, NIE
AlertDialog.Builder alert = new AlertDialog.Builder(context);
alert.setTitle("Uwaga!");
alert.setMessage("komunikat");
//ok
alert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
//wyświetl zmienną which
}
});
//no
alert.setNegativeButton("NO", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
//wyświetl which
}
});
//
alert.show();kopiuj
d) dialog z listą możliwych opcji
AlertDialog.Builder alert = new AlertDialog.Builder(context);
alert.setTitle("Uwaga!");
//nie może mieć setMessage!!!
String[] opcje = {"tanie","średnie","drogie"};
alert.setItems(opcje, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// wyswietl opcje[which]);
}
});
//
alert.show();kopiuj
e) dialog z inputem
AlertDialog.Builder alert = new AlertDialog.Builder(context);
alert.setTitle("Uwaga!");
alert.setMessage("login lub hasło jest puste!!!");
//tutaj input
EditText input = new EditText(this);
input.setText("podaj login");
alert.setView(input);
//teraz butony jak poprzednio i
alert.show();kopiuj
a) dialog z jednym butonem
AlertDialog.Builder alert = new AlertDialog.Builder(context);
alert.setTitle("Uwaga!");
alert.setCancelable(false); //nie zamyka się po kliknięciu poza nim
alert.setMessage("TEST");
alert.setNeutralButton("OK", null).show(); // null to pusty clickkopiuj
b) dialog z ikoną i kliknięciem butona
AlertDialog.Builder alert = new AlertDialog.Builder(context);
alert.setTitle("Uwaga");
alert.setMessage("komunikat");
alert.setIcon(R.drawable.anyicon);
alert.setNeutralButton("OK", new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
//komunikat
}
});
alert.show();kopiuj
c) dialog z dwoma butonami, TAK, NIE
AlertDialog.Builder alert = new AlertDialog.Builder(context);
alert.setTitle("Uwaga!");
alert.setMessage("komunikat");
//ok
alert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
//wyświetl zmienną which
}
});
//no
alert.setNegativeButton("NO", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
//wyświetl which
}
});
//
alert.show();kopiuj
d) dialog z listą możliwych opcji
AlertDialog.Builder alert = new AlertDialog.Builder(context);
alert.setTitle("Uwaga!");
//nie może mieć setMessage!!!
String[] opcje = {"tanie","średnie","drogie"};
alert.setItems(opcje, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// wyswietl opcje[which]);
}
});
//
alert.show();kopiuj
e) dialog z inputem
AlertDialog.Builder alert = new AlertDialog.Builder(context);
alert.setTitle("Uwaga!");
alert.setMessage("login lub hasło jest puste!!!");
//tutaj input
EditText input = new EditText(this);
input.setText("podaj login");
alert.setView(input);
//teraz butony jak poprzednio i
alert.show();kopiuj