Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Android School 08

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

Android School 08

Avatar for Adam Jodłowski

Adam Jodłowski

May 26, 2013
Tweet

More Decks by Adam Jodłowski

Other Decks in Programming

Transcript

  1. 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
  2. 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
  3. 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); } }
  4. 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);
  5. 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
  6. 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()
  7. 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
  8. 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(); }
  9. 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()
  10. 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);
  11. 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");
  12. 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
  13. 18