$30 off During Our Annual Pro Sale. View Details »

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.

Adam Jodłowski

April 07, 2013
Tweet

More Decks by Adam Jodłowski

Other Decks in Programming

Transcript

  1. Android School
    Warsztat 04
    Adam Jodłowski

    View Slide

  2. 2
    Domyślny katalog aplikacji

    aplikacja może manipulować swoimi plikami z katalogu
    /data/data//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);
    ...

    View Slide

  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

    View Slide

  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();
    }
    }
    }
    }

    View Slide

  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();
    }

    View Slide

  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ę?

    View Slide

  7. 7
    Wypróbuj mechanizmy zapisu i odczytu danych z
    domyślnego katalogu, karty pamięci i zasobów
    statycznych.

    View Slide

  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

    View Slide

  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();

    View Slide

  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();

    View Slide

  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"});

    View Slide

  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.

    View Slide

  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ść

    View Slide

  14. 14
    ArrayAdapter

    przykładowa klasa adaptera
    class OrderAdapter extends ArrayAdapter {
    private ArrayList items;
    private Context ctx;
    LayoutInflater inflater = null;
    public OrderAdapter(Context context, int textViewResourceId, ArrayList 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;
    }
    }

    View Slide

  15. 15
    Lista z adapterem i optymalizacja

    podpięcie adaptera do listy
    ListView lv = (ListView) findViewById(R.id.listView);
    ArrayList orders = new ArrayList();
    // 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;

    View Slide

  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.

    View Slide

  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().

    View Slide