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

Android School 08

Android School 08

Adam Jodłowski

May 26, 2013
Tweet

More Decks by Adam Jodłowski

Other Decks in Programming

Transcript

  1. Android School
    Warsztat 08
    Adam Jodłowski

    View Slide

  2. 2
    Alarmy

    usługa systemowa AlarmManager pozwala na ustawianie alarmów rozgłaszanych w
    określonym czasie w przyszłości, alarmy nie są kasowane na skutek uśpienia
    urządzenia, ale znikają po jego wyłączeniu

    mogą być jednorazowe, powtarzalne, dokładne lub niedokładne oraz budzić
    urządzenie z uśpienia

    w przykładzie, najpierw rejestrujemy BroadcastReceivera – odbiorcę alarmu

    dalej, rejestrujemy alarm w usłudze systemowej
    AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    Intent intent = new Intent(ctx, AlarmBroadcastReceiver.class);
    PendingIntent pi = PendingIntent.getBroadcast(ctx, 666, intent, 0);
    Calendar cal = Calendar.getInstance();
    cal.add(Calendar.SECOND, 10);
    am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pi);

    alarm powtarzany zlecamy poprzez metodę setRepeating(), będzie zgłaszany co
    określony czas, do momentu wywołania cancel()

    za pomocą setInexactRepeating() możemy uzyskać mniej dokładne, ale tańsze
    alarmy, których faktyczny czas zgłoszeń będzie różnił się od założonego

    View Slide

  3. 3
    Stwórz alarm, który uruchomi aktywność, usługę lub
    broadcast receivera.

    View Slide

  4. 4
    Widżety

    widoczne na ekranie głównym elementy interfejsu aplikacji, ich rozmiar ogranicza bounding box
    (płótno do naszej dyspozycji) a składają się z tradycyjnego układu kontrolek graficznych

    widżet to w najprostszym ujęciu, specjalny broadcast receiver sterujący widokami hostowanymi na
    pulpicie, które nie są częścią procesu naszej aplikacji

    ekran główny jest podzielony na komórki, które może zajmować widżet – z uwagi na orientację
    pionową i poziomą, definiujemy minimalne wymiary ze wzoru (74*liczba_komórek)-2 [dp]

    konfiguracja widżetu dokonujemy za pomocą pliku, np. /res/xml/widget_info.xml

    android:minWidth="294dp"
    android:minHeight="72dp"
    android:updatePeriodMillis="1800000"
    android:initialLayout="@layout/widget">


    Android 3.1 wprowadził możliwość dowolnej zmiany rozmiaru widżetów, wystarczy dodać do
    konfiguracji android:resizeMode="horizontal|vertical"

    layout widżetu określamy podobnie jak dotychczas, z drobnymi ograniczeniami (nie wszystkie
    widoki i layouty są dostępne*) w pliku XML w /res/layout

    View Slide

  5. 5
    WidgetProvider
    ● WidgetProvider zarządza wszystkimi widżetami naszej aplikacji za pomocą metod zwrotnych onEnabled(),
    onDisabled(), onUpdate(), onDeleted(), onReceive()
    public class WidgetProvider extends AppWidgetProvider {
    @Override
    public void onReceive(Context context, Intent intent) {
    super.onReceive(context, intent);
    if (intent.getAction().equals("MY.ACTION")) {
    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
    ComponentName thisAppWidget = new ComponentName(context.getPackageName(),
    WidgetProvider.class.getName());
    int[] appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidget);
    onUpdate(context, appWidgetManager, appWidgetIds);
    }
    }
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    // wczytujemy zdalny układ widoków
    RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);
    // aktualizujemy zawartość komponentu
    remoteViews.setTextViewText(R.id.widget_text, "onUpdate " + System.currentTimeMillis()/1000);
    Intent intent = new Intent(context, WidgetProvider.class);
    intent.setAction("MY.ACTION");
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent,
    PendingIntent.FLAG_UPDATE_CURRENT);
    // ustawienie OnClickListenera
    remoteViews.setOnClickPendingIntent(R.id.widget_image, pendingIntent);
    // aktualizacja zdalnego widoku
    appWidgetManager.updateAppWidget(appWidgetIds[0], remoteViews);
    }
    }

    View Slide

  6. 6
    Wpis w manifeście, aktualizacje spoza widżetu

    konieczny jest odpowiedni wpis w manifeście
    android:label="@string/widget_desc"
    android:icon="@drawable/ic_launcher">



    android:resource="@xml/widget_info" />


    określamy powyżej klasę broadcast receivera, nazwę i ikonkę na liście widżetów, filtr
    domyślnych intencji oraz plik konfiguracyjny

    możemy wysyłać własne broadcasty zlecające aktualizacje widżetów, wystarczy dodać w
    manifeście filtr intencji z naszą akcją




    i rozesłać broadcast, który zostanie odebrany w onReceive()
    Intent intent = new Intent("MY.ACTION");
    context.sendBroadcast(intent);

    View Slide

  7. 7
    Stwórz widżet i zainstaluj go na ekranie głównym.

    View Slide

  8. 8
    Content Provider

    stanowi RESTfulowy interfejs do danych, które muszą być
    współdzielone pomiędzy aplikacjami, uzyskujemy dzięki niemu
    abstrakcję od fizycznej postaci danych (SQLite, API usługi
    sieciowej, plik w pamięci)

    najpopularniejsze wbudowane komponenty udostępniające dane
    to MediaStore, CallLog, Browser, ContactsContract, Settings,
    CalendarContract

    URI o postaci :////
    identyfikuje dane, np. content://as.books/dictionaries/1 –
    jest to pierwszy argument wywołań metod modułu
    ContentResolver, prowadzącego interakcję z dostawcami

    dostęp do konkretnych danych wymaga znajomości typów
    kolumn oraz identyfikatora _ID rekordu w bazie danych

    View Slide

  9. 9
    Przykład odczytania logu połączeń*

    odczytanie ostatnich połączeń telefonicznych
    String[] columns = { CallLog.Calls.NUMBER,
    CallLog.Calls.DURATION, CallLog.Calls.TYPE };
    Cursor calls =
    managedQuery(CallLog.Calls.CONTENT_URI, columns,
    null, null, null);
    calls.moveToFirst();
    while (!calls.isAfterLast()) {
    Log.d("AS", calls.getString(0) + ": " +
    calls.getInt(1) + "s [" + calls.getInt(2) +
    "]");
    calls.moveToNext();
    }
    // nie wywolujemy calls.close()

    View Slide

  10. 10
    Przykład odczytywania multimediów

    możemy wypisać wszystkie multimedia przechowywane w pamięci zewnętrznej
    String[] columns = { MediaStore.Audio.Media.TITLE,
    MediaStore.Audio.Media.DURATION, MediaStore.Audio.Media.DATA };
    Cursor cursor =
    managedQuery(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, columns,
    null, null, null);
    cursor.moveToFirst();
    while (!cursor.isAfterLast()) {
    Log.d("AS", "Tytul: " + cursor.getString(0));
    Log.d("AS", "Czas trwania: " + cursor.getInt(1) / 1000 + "s");
    Log.d("AS", "URI: " + cursor.getString(2));
    cursor.moveToNext();
    }

    analogicznie postępujemy z MediaStore.Video.Media, .Images.Media,
    .Images.ThumbNails, .Audio.Albums, .Audio.Artists, .Audio.Genres,
    .Audio.Playlists i innymi

    View Slide

  11. 11
    Przykład odczytywania kontaktów

    możemy wypisać wszystkie, nawet niewidoczne normalnie kontakty
    ContentResolver cr = getContentResolver();
    String[] columns = new String[] { ContactsContract.Contacts._ID,
    ContactsContract.Contacts.DISPLAY_NAME };
    Cursor contacts = managedQuery(ContactsContract.Contacts.CONTENT_URI,
    columns, null, null, null);
    contacts.moveToFirst();
    while (!contacts.isAfterLast()) {
    Cursor phone =
    cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, new String[]
    { ContactsContract.CommonDataKinds.Phone.NUMBER },
    ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", new String[]
    { String.valueOf(contacts.getLong(0)) }, null);
    if (phone.moveToFirst()) {
    Log.d("AS", contacts.getString(1) + ": " + phone.getString(0));
    }
    phone.close();
    contacts.moveToNext();
    }

    View Slide

  12. 12
    Przetestuj możliwości odczytywania danych
    składowanych w dostawcach treści.

    View Slide

  13. 13
    Dźwięki

    przykład nagrywania i odtwarzania dźwięków
    MediaRecorder recorder = null;
    MediaPlayer player = null;
    String fileName = Environment.getExternalStorageDirectory().getAbsolutePath() + "/android.3gp";
    // nagrywanie
    recorder = new MediaRecorder();
    recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
    recorder.setOutputFile(fileName);
    recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
    recorder.prepare();
    recorder.start();
    ...
    recorder.stop();
    recorder.release();
    recorder = null;
    // odtwarzanie
    player = new MediaPlayer();
    player.setDataSource(fileName);
    player.prepare();
    player.start();
    ...
    // player.stop(), player.pause()
    player.release();
    player = null;

    rejestracja na zakończenie odtwarzania
    player.setOnCompletionListener()

    View Slide

  14. 14
    Zdjęcia

    warto dodać do manifestu zapis wymagający możliwości robienia zdjęć przez
    dane urządzenie


    najłatwiej jest skorzystać z wbudowanej aplikacji kamery
    // odpalamy intencje niejawna
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    Uri photoUri =
    getContentResolver().insert(android.provider.MediaStore.Images.Media
    .EXTERNAL_CONTENT_URI, new ContentValues());
    intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
    startActivityForResult(intent, INTENT_RESULT_CODE);
    // korzystamy z dostepu do zdjecia w pamieci po odebraniu rezultatu
    InputStream stream = getContentResolver().openInputStream(photoUri);
    Bitmap bmp = BitmapFactory.decodeStream(stream);
    imageView.setImageBitmap(bmp);

    View Slide

  15. 15
    Wideo

    do nagrania wideo również możemy posłużyć się aplikacją kamery
    Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
    startActivityForResult(takeVideoIntent, INTENT_RESULT_CODE);
    // w onActivityResult() dostaniemy URI wideoklipu
    Uri videoUri = data.getData();

    odtwarzanie wideo odbywa się analogicznie do dźwięku
    VideoView myVideoView = (VideoView) ((Activity)
    ctx).findViewById(R.id.video);
    myVideoView.setVideoURI(videoUri);
    // myVideoView.setMediaController(new MediaController(this));
    myVideoView.requestFocus();
    myVideoView.start();
    // myVideoView.setVideoURI(Uri.parse("rtsp://..."));
    // myVideoView.setVideoPath(SD_CARD_PATH + "/as.3gp");

    View Slide

  16. 16
    Przetestuj możliwości multimedialne.

    View Slide

  17. 17
    Publikowanie aplikacji

    gruntowne przetestowanie aplikacji

    przygotowanie opisów i grafik promocyjnych

    rejestracja konta w Google Play ($25)

    podpisanie cyfrowo paczki

    wprowadzenie aplikacji do sklepu

    śledzenie sprzedaży w konsoli wydawcy (developer console)

    zgodność z regulaminem i zasadami

    15-minutowe okno czasowe refundacji

    nieograniczona liczba reinstalacji

    sprzedawanie aplikacji, in-app billing

    konkurencyjne sklepy to np. Amazon Appstore, GetJar, Samsung Apps

    View Slide

  18. 18

    View Slide