Android School 08

Android School 08

572884b36b9538ad273ef7dd7e23b228?s=128

Adam Jodłowski

May 26, 2013
Tweet

Transcript

  1. Android School Warsztat 08 Adam Jodłowski

  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
  3. 3 Stwórz alarm, który uruchomi aktywność, usługę lub broadcast receivera.

  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 <?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minWidth="294dp" android:minHeight="72dp" android:updatePeriodMillis="1800000" android:initialLayout="@layout/widget"> </appwidget-provider> • 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
  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); } }
  6. 6 Wpis w manifeście, aktualizacje spoza widżetu • konieczny jest

    odpowiedni wpis w manifeście <receiver android:name=".WidgetProvider" android:label="@string/widget_desc" android:icon="@drawable/ic_launcher"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/widget_info" /> </receiver> • 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ą <intent-filter> <action android:name="MY.ACTION"/> </intent-filter> • i rozesłać broadcast, który zostanie odebrany w onReceive() Intent intent = new Intent("MY.ACTION"); context.sendBroadcast(intent);
  7. 7 Stwórz widżet i zainstaluj go na ekranie głównym.

  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 <prefix>://<authority>/<data>/<id> 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
  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()
  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
  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(); }
  12. 12 Przetestuj możliwości odczytywania danych składowanych w dostawcach treści.

  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()
  14. 14 Zdjęcia • warto dodać do manifestu zapis wymagający możliwości

    robienia zdjęć przez dane urządzenie <uses-feature android:name="android.hardware.camera" /> • 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);
  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");
  16. 16 Przetestuj możliwości multimedialne.

  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
  18. 18