Android School 04

Android School 04

Praca z wewnętrznym systemem plików, pamięcią zewnętrzną (kartą SD) i dodatkowymi zasobami (assets i raw resources). Obsługa bazy danych SQLite i kompleksowe omówienie podstaw SQL. Wydajne listy (ListView) z wieloma typami elementów i własnymi widokami, adaptery list.

572884b36b9538ad273ef7dd7e23b228?s=128

Adam Jodłowski

April 07, 2013
Tweet

Transcript

  1. Android School Warsztat 04 Adam Jodłowski

  2. 2 Domyślny katalog aplikacji • aplikacja może manipulować swoimi plikami

    z katalogu /data/data/<nazwa.pakietu>/files za pomocą metod kontekstu getFilesDir(); getCacheDir(); openFileInput(); openFileOutput(); deleteFile(); fileList(); • przykłady zapisu, dopisywania i odczytu FileOutputStream fos; String strFileContents = "Początek."; fos = openFileOutput("tekst.txt", MODE_PRIVATE); fos.write(strFileContents.getBytes()); fos.close(); strFileContents = "Koniec."; fos = openFileOutput("tekst.txt", MODE_APPEND); fos.write(strFileContents.getBytes()); fos.close(); String strFileName = "tekst.txt"; FileInputStream fis = openFileInput(strFileName); ...
  3. 3 Pamięć zewnętrzna • używamy jej do składowania dużych plików,

    niekluczowych składników aplikacji • Android pozwala na dostęp do zawartości karty SD jeśli urządzenie ją posiada, system plików to przeważnie FAT i nie mają w nim zastosowania uprawnienia linuksowe • karta SD może zostać w każdej chwili odmontowana – nasza aplikacja musi być na to gotowa • binarne zasoby statyczne możemy też przechowywać w katalogach /assets i /res/raw
  4. 4 Praca z pamięcią zewnętrzną • utworzenie nowego katalogu i

    zapisanie w nim pliku File sdDirectory = Environment.getExternalStorageDirectory(); if (sdDirectory.exists() && sdDirectory.canWrite()) { File myDirectory = new File(sdDirectory.getAbsolutePath() + "/school"); myDirectory.mkdir(); if (myDirectory.exists() && myDirectory.canWrite()) { File file = new File(myDirectory.getAbsolutePath() + "/" + "as.txt"); file.createNewFile(); if (file.exists() && file.canWrite()) { FileOutputStream fos = new FileOutputStream(file); fos.write("Lubie placki".getBytes()); if (fos != null) { fos.flush(); fos.close(); } } } }
  5. 5 Praca z pamięcią zewnętrzną • odczytanie pliku z pamięci

    zewnętrznej File readFile = new File(Environment.getExternalStorageDirectory() + "/school/" + "as.txt"); if (readFile.exists() && readFile.canRead()) { FileInputStream fis = new FileInputStream(readFile); byte[] reader = new byte[fis.available()]; while (fis.read(reader) != -1) {} String fileContent = new String(reader); if (fis != null) fis.close(); }
  6. 6 Praca z zasobami statycznymi • zasoby z /res/raw Resources

    resources = getResources(); InputStream is = resources.openRawResource(R.raw.plik); byte[] reader = new byte[is.available()]; while (is.read(reader) != -1) {} String data = new String(reader)); is.close(); • zasoby z /assets AssetManager am = getAssets(); InputStream is = am.open("pliki/plik.txt"); ... is.close(); • czy dostrzegasz różnicę?
  7. 7 Wypróbuj mechanizmy zapisu i odczytu danych z domyślnego katalogu,

    karty pamięci i zasobów statycznych.
  8. 8 Baza danych • SQLite to silnik bazodanowy wbudowany w

    system • cechuje go słaba współbieżność, ograniczenia integralnościowe nie są zawsze wymuszane, brak zaawansowanych możliwości znanych z pełnoprawnych baz relacyjnych • każda aplikacja może mieć wiele prywatnych baz w postaci pojedynczych plików • do bezpośredniego zarządzania bazą danych możemy użyć odpowiednich metod kontekstu, ale lepiej jest wykorzystać klasę pomocniczą SQLiteOpenHelper
  9. 9 SQLiteOpenHelper • klasa pomocnika class MyDatabaseHelper extends SQLiteOpenHelper {

    MyDatabaseHelper(Context context) { super(context, "my_database.db", null, 1); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL("CREATE TABLE " + "EMPLOYEES" + " (_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, surname TEXT NOT NULL, age INTEGER);"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("DROP TABLE IF EXISTS " + "EMPLOYEES"); onCreate(db); } } • korzystanie z pomocnika MyDatabaseHelper dh = new MyDatabaseHelper(ctx); SQLiteDatabase db = dh.getWritableDatabase(); // SQLiteDatabase db = dh.getReadableDatabase(); // wykonanie operacji na bazie dh.close();
  10. 10 Podstawowe zapytania • INSERT i SELECT String INSERT =

    "INSERT INTO " + "EMPLOYEES" + " (name, surname, age) VALUES (?, ?, ?)"; SQLiteStatement insertStatement = db.compileStatement(INSERT); insertStatement.bindString(1, "scott"); insertStatement.bindString(2, "tiger"); insertStatement.bindLong(3, 666); insertStatement.executeInsert(); Cursor cursor = db.query("EMPLOYEES", new String[] {"name", "surname", "age"}, "name = ?", new String[] {"scott"}, null, null, "age"); if (cursor.moveToFirst()) { do { Log.d("AS", cursor.getString(0) + " " + cursor.getString(1) + ", " + cursor.getLong(2)); } while (cursor.moveToNext()); } if (cursor != null && !cursor.isClosed()) cursor.close();
  11. 11 Podstawowe zapytania • SELECT, DELETE i UPDATE db.rawQuery("SELECT *

    FROM EMPLOYEES WHERE name = ?", new String[] {"scott"}); db.delete("EMPLOYEES", "name = ?", new String[] {"scott"}); ContentValues values = new ContentValues(); values.put("age", 333); db.update("EMPLOYEES", values, "name = ?", new String[] {"scott"});
  12. 12 Przetestuj mechanizm działania SQLiteOpenHelper, stwórz własną tabelę, dodaj do

    niej dane i wypisz je wykonując odpowiednie zapytania. Zapoznaj się z programem SQLite Database Browser.
  13. 13 ListView • obok GridView i GalleryView stanowi kontrolkę typu

    AdapterView i zawiera elementy View • łączy je ze źródłem danych dzięki ListAdapter, np. BaseAdapter, ArrayAdapter, CursorAdapter, które stanowi model i manipuluje widokami • wydajność operacji adapterów jest kluczowa • poznamy podejście trzymające listę danych w pamięci, często używamy też kursorów i tzw. Loaderów poprawiających ich wydajność
  14. 14 ArrayAdapter • przykładowa klasa adaptera class OrderAdapter extends ArrayAdapter<Order>

    { private ArrayList<Order> items; private Context ctx; LayoutInflater inflater = null; public OrderAdapter(Context context, int textViewResourceId, ArrayList<Order> items) { super(context, textViewResourceId, items); this.items = items; ctx = context; inflater = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override public View getView(int position, View convertView, ViewGroup parent) { View v = convertView; if (v == null) { // optymalizacja v = inflater.inflate(R.layout.row, null); } Order o = items.get(position); if (o != null) { // odswiezamy tresc wiersza TextView tt = (TextView) v.findViewById(R.id.toptext); tt.setText("Name: " + o.getOrderName()); TextView bt = (TextView) v.findViewById(R.id.bottomtext); bt.setText("Status: " + o.getOrderStatus()); } return v; } }
  15. 15 Lista z adapterem i optymalizacja • podpięcie adaptera do

    listy ListView lv = (ListView) findViewById(R.id.listView); ArrayList<Order> orders = new ArrayList<Orders>(); // wypelniamy liste "orders"... OrderAdapter adapter = new OrderAdapter(ctx, R.layout.row, orders); lv.setAdapter(adapter); // lv.setOnItemClickListener(...); • dodatkowa optymalizacja adaptera list poprzez ViewHolder pattern static class ViewHolder { public ImageView imageView; public TextView textView; } // cialo metody getView() ViewHolder holder; View rowView = convertView; if (rowView == null) { rowView = inflater.inflate(R.layout.rowlayout, null, true); holder = new ViewHolder(); holder.textView = (TextView) rowView.findViewById(R.id.label); holder.imageView = (ImageView) rowView.findViewById(R.id.icon); rowView.setTag(holder); } else { holder = (ViewHolder) rowView.getTag(); } // odswiezamy tresc wiersza holder.textView.setText(names[position]); holder.imageView.setImageResource(R.drawable.icon); return rowView;
  16. 16 Metoda adaptera notifyDataSetChanged() powoduje przeładowanie modeli widoków. Stwórz ArrayAdapter

    i wypełnij za jego pomocą własną listę obiektów, obsłuż kliknięcie na dany element.
  17. 17 Zadanie domowe: Stwórz aplikację do robienia notatek tekstowych używając

    ListView oraz bazy danych lub systemu plików. Dla chętnych: stwórz listę z nagłówkami sekcji, korzystając z przesłaniania metod getViewTypeCount(), getItemViewType() i getCount().