16
Dozenten: Patrick Förster, Michael Hasseler Programmieren für mobile Endgeräte SS 2013/2014

Programmieren für mobile Endgeräte€¦ · Dozenten: Patrick Förster, Michael Hasseler Programmieren für mobile Endgeräte SS 2013/2014

  • Upload
    others

  • View
    3

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Programmieren für mobile Endgeräte€¦ · Dozenten: Patrick Förster, Michael Hasseler Programmieren für mobile Endgeräte SS 2013/2014

Dozenten: Patrick Förster, Michael Hasseler

Programmieren für mobile Endgeräte SS 2013/2014

Page 2: Programmieren für mobile Endgeräte€¦ · Dozenten: Patrick Förster, Michael Hasseler Programmieren für mobile Endgeräte SS 2013/2014

Dozenten: Patrick Förster, Michael Hasseler

Wiederholung (Datenverarbeitung)

• Bisher:

• Activity: Steuereinheit zwischen View und Model

• BroadcastReceiver: „Zuhörer“, der auf bestimmte Intents wartet

• Beide verarbeiten Daten

• Nutzereingaben

• Intent-Argumente

• Beide blockieren dabei die Applikation

• Daher strenges Zeitlimit für die „akzeptierte“ Verarbeitungszeit

• Activity: Maximal fünf Sekunden

• BroadcastReceiver: Maximal zehn Sekunden

Programmieren für mobile Endgeräte 2

Page 3: Programmieren für mobile Endgeräte€¦ · Dozenten: Patrick Förster, Michael Hasseler Programmieren für mobile Endgeräte SS 2013/2014

Dozenten: Patrick Förster, Michael Hasseler

Services

• Dritte Möglichkeit zur Datenverarbietung

• Werden von Activies, Receivern oder anderen Services gestartet

• General ohne grafisches Interface

• Keine Zeiteinschränkung

• Höher priorisiert als inaktive oder gestoppte Activities

• „Foreground Services“: Services mit hoher Priorität, die nur in Extremfällen vom System gestoppt werden dürfen

• Achtung: Laufen per se im Haupt-Thread, d.h. auch Services blockieren die Applikation

Programmieren für mobile Endgeräte 3

Page 4: Programmieren für mobile Endgeräte€¦ · Dozenten: Patrick Förster, Michael Hasseler Programmieren für mobile Endgeräte SS 2013/2014

Dozenten: Patrick Förster, Michael Hasseler

Services (Lebenszyklus)

• Es gibt Varianten eines Services mit unterschiedlichen Lebenszyklen:

• „Started“:

• Der Service lebt solange bis er gestoppt wird/sich selbst stoppt

• „Bound“:

• Andere Komponenten (bspw. Activities) können sich an einen Services „Binden“

• Der Service lebt solange wie eine andere Komponente eine Verbindung aufrecht erhält

Programmieren für mobile Endgeräte 4

create start stop destroy

create bind unbind destroy

Page 5: Programmieren für mobile Endgeräte€¦ · Dozenten: Patrick Förster, Michael Hasseler Programmieren für mobile Endgeräte SS 2013/2014

Dozenten: Patrick Förster, Michael Hasseler

Services („Started“)

• Ein Service wird durch erben von android.app.Service definiert

• Die Methode onBind ist abstract und muss implementiert werden

• Callback-Methoden zu allen Lebenszyklus-Stati (bis auf „stop“)

• Services im Manifest registrieren:

• Service starten/stoppen (explizit/implizit)

Programmieren für mobile Endgeräte 5

Intent intent = new Intent(this, MyService.class); startService(intent); stopService(intent)

public class MyService extends Service { public static final String ACTION_SERVICE = "de.wuu.ziv.aufgabenapp.ACTION_SERVICE"; @Override public IBinder onBind(Intent intent) { return null; } }

<service android:name=".MyService" android:enabled="true"> <intent-filter> <action android:name="de.wuu.ziv.aufgabenapp.ACTION_SERVICE" /> </intent-filter> </service>

Intent intent = new Intent(MyService.ACTION_SERVICE); startService(intent); stopService(intent)

Page 6: Programmieren für mobile Endgeräte€¦ · Dozenten: Patrick Förster, Michael Hasseler Programmieren für mobile Endgeräte SS 2013/2014

Dozenten: Patrick Förster, Michael Hasseler

Services („Bound“)

• Wenn bspw. eine Activity direkt mit einem Service kommunizieren soll, benötigt es einen „bounded“ Service:

• Implementierung von onBind

• IBinder werden zur Umsetzung von Remote-Aufrufen benötigt

• Im Beispiel ist der Service „lokal“ zur aufrufenden Activity

• Mit android.os.Binder existiert bereits eine vollständige

Implementierung der IBinder-Schnittstelle für diesen Fall

Programmieren für mobile Endgeräte 6

public class MyService extends Service { public class Binder extends android.os.Binder { public MyService getService() { return MyService.this; } } private final Binder binder = new Binder(); public IBinder onBind(Intent intent) { return binder; } }

Page 7: Programmieren für mobile Endgeräte€¦ · Dozenten: Patrick Förster, Michael Hasseler Programmieren für mobile Endgeräte SS 2013/2014

Dozenten: Patrick Förster, Michael Hasseler

Services („Bound“ II)

• Auf aufrufender Seite benötigt es eine ServiceConnection:

• Callback für das Binding

• Zugriff auf den Service

• BIND_AUTO_CREATE: Service automatisch erstellen, solange das

Binding besteht

Programmieren für mobile Endgeräte 7

public class MainActivity extends Activity { … private MyService service; private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { service = ((MyService.Binder)service).getService(); } @Override public void onServiceDisconnected(ComponentName name) { service = null; } }; … }

Intent intent = new Intent(this, MyService.class); bindService(intent, connection, Context.BIND_AUTO_CREATE); unbindService(intent)

Page 8: Programmieren für mobile Endgeräte€¦ · Dozenten: Patrick Förster, Michael Hasseler Programmieren für mobile Endgeräte SS 2013/2014

Dozenten: Patrick Förster, Michael Hasseler

Services (Restart)

• Falls ein Service vom System gestoppt wurde, wird er per default erneut gestartet, sobald genügen Ressourcen zur Verfügung stehen

• Bei jedem Start wird der Callback onStartCommand aufgerufen

• Sein Rückgabewert definiert das „Restart“-Verhalten

• START_STICKY: Service wird solange neugestartet, bis er per stopService explizit angehalten wird

• START_NOT_STICKY: Service wird nur neugestartet, wenn während seiner Auszeit ein startService erfolgte

• START_REDELIVER_INTENT: Service wird neugestartet, falls ein startService erfolgte oder der Service abgebrochen wurde, bevor er sich per stopSelf selbst stoppen konnte; in diesem Fall wird der initiale Intent erneut mitgeliefert (ansonsten null)

Programmieren für mobile Endgeräte 8

public int onStartCommand(Intent intent, int flags, int startId) { ... // arbeit starten return Service.START_NOT_STICKY; }

Page 9: Programmieren für mobile Endgeräte€¦ · Dozenten: Patrick Förster, Michael Hasseler Programmieren für mobile Endgeräte SS 2013/2014

Dozenten: Patrick Förster, Michael Hasseler

Services (Beispiel)

• Service, der eine Internetverbindung herstellt und eine URL einliest

Programmieren für mobile Endgeräte 9

public int onStartCommand(Intent intent, int flags, int startId) { try { read(new URL(intent.getStringExtra("URL"))); } catch (java.lang.Exception e) {… } return Service.START_NOT_STICKY; } private String read(URL url) { try { URLConnection connection = url.openConnection(); int responseCode = ((HttpURLConnection)connection).getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { String inputLine; StringBuilder sb = new StringBuilder(""); BufferedReader inBuff = new BufferedReader(new InputStreamReader(connection.getInputStream())); while ((inputLine = inBuff.readLine()) != null) { sb.append(inputLine).append("\n"); } inBuff.close(); return sb.toString(); } } catch (java.lang.Exception e) {… } return null; }

Page 10: Programmieren für mobile Endgeräte€¦ · Dozenten: Patrick Förster, Michael Hasseler Programmieren für mobile Endgeräte SS 2013/2014

Dozenten: Patrick Förster, Michael Hasseler

Services (Beispiel II)

• Idee gut, aber:

• „Network on main thread exception“

• Der Service könnte die Applikation zu lange blockieren

• Lösung: Das Einlesen muss ausgelagert werden

• Klasse android.os.Async übernimmt das Thread-Management

Programmieren für mobile Endgeräte 10

private class ScanTask extends AsyncTask<URL, String, List<String>> { @Override protected List<String> doInBackground(URL... params) { List<String> contents = new ArrayList<String>(); String content; for (URL url : params) { content = read(url); if (content != null) { contents.add(content); publishProgress(content); } } return contents; } private String read(URL url) {…} }

public int onStartCommand(Intent intent, int flags, int startId) { try { task = new ScanTask(); task.execute(new URL(intent.getStringExtra("URL")); } catch (java.lang.Exception e) {… } return Service.START_NOT_STICKY; }

Page 11: Programmieren für mobile Endgeräte€¦ · Dozenten: Patrick Förster, Michael Hasseler Programmieren für mobile Endgeräte SS 2013/2014

Dozenten: Patrick Förster, Michael Hasseler

Services (Threads + UI)

• Achtung: Aus einem anderen als den Main-Thread heraus, kann die UI nicht geändert werden!

• Insbesondere also nicht aus AsyncTask.doInBackground

• Folgende AsyncTask-Methoden werden im Main-Thread ausgeführt

• doProgressUpdate: Wird aufgerufen nachdem per publishProgress ein Fortschritt signalisiert wurde

• onPostExecute: Wird aufgerufen sobald doInBackground

durchgelaufen ist

Programmieren für mobile Endgeräte 11

Page 12: Programmieren für mobile Endgeräte€¦ · Dozenten: Patrick Förster, Michael Hasseler Programmieren für mobile Endgeräte SS 2013/2014

Dozenten: Patrick Förster, Michael Hasseler

Services (Timer)

• Der Service soll statt einmal periodisch laufen

• Statt AsyncTask verwendet man TimerTask

• Im Gegensatz zu AsyncTask gibt es keine mit dem Main-Thread

synchronisierten Methoden!

• Mögliche Lösungen:

• Eigenständiges Thread-Handling implementieren

• Aus der run-Methode einen AsyncTask erstellen und aufrufen

• Handler benutzten um Code in anderen Thread auszuführen

Programmieren für mobile Endgeräte 12

private class RefreshTask extends TimerTask { private List<URL> url; public RefreshTask(URL urls) { this.url = url; } @Override public void run() { read(url); } }

public int onStartCommand(Intent intent, int flags, int startId) { try { URL url = new URL(intent.getStringExtra("URL„); Timer timer = new Timer(); timer.scheduleAtFixedRate(new RefreshTask(urls), 0, refreshRate); } catch (java.lang.Exception e) {… } return Service.START_NOT_STICKY; }

Page 13: Programmieren für mobile Endgeräte€¦ · Dozenten: Patrick Förster, Michael Hasseler Programmieren für mobile Endgeräte SS 2013/2014

Dozenten: Patrick Förster, Michael Hasseler

Services (Handler)

• Handler bieten die Möglichkeit java.lang.Runnable Objekte zur

Ausführung an einen bestimmten Thread zu überreichen

• Der Thread ist dabei immer der, in das Handler-Objekt erzeugt wurde

• Der RefreshTask wird aus dem Main-Thread heraus erzeugt

Per post wird veranlasst, dass UpdateContentRunnable im

Main-Thread ausgeführt werden soll

Programmieren für mobile Endgeräte 13

private class RefreshTask extends TimerTask { private List<URL> url; private Handler handler = new Handler(); private View view; Public RefreshTask(URL url, View view) { this.url = url; this.view = view; } @Override public void run() { String content = read(url); handler.post(new UpdateContentRunnable(view, content)); } }

private class UpdateContentRunnable implements Runnable { private String message; private View view; UpdateContentRunnable(View view, String message) { this.message = message; this.view = view; } public void run() { TextView messageView = (TextView) view.findViewById(R.id.text_scan_message); messageView.setText(message); } }

Page 14: Programmieren für mobile Endgeräte€¦ · Dozenten: Patrick Förster, Michael Hasseler Programmieren für mobile Endgeräte SS 2013/2014

Dozenten: Patrick Förster, Michael Hasseler

Services (Alarm)

• Timer laufen im Scope der Applikation

• Wird die Applikation beendet, so auch der Timer

• Soll ein Service eine Applikation überleben, sind Timer ungeeignet

• Ein Alarm überlebt eine Applikation

• Alarm wird über den AlarmManager ausgelöst

• Es wird ein Broadcast mit dem angegebenen Intent gesendet

• Über den PendingIntent kann der Alarm wieder abgebrochen werden

Programmieren für mobile Endgeräte 14

public class MyActivity extends Activity { private AlarmManager alarmManager; private PendingIntent pending; @Override public void onCreate() { super.onCreate(); alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); pending= PendingIntent.getBroadcast(this, 0, new Intent(…), 0); .. }

Page 15: Programmieren für mobile Endgeräte€¦ · Dozenten: Patrick Förster, Michael Hasseler Programmieren für mobile Endgeräte SS 2013/2014

Dozenten: Patrick Förster, Michael Hasseler

Services (Alarm)

• Auslösen des Alarms:

• ELAPSED_REALTIME: Alarm starten nach der angegebenen Zeit, seit

Starten des Gerätes

• setInexactRepeating wird genutzt, wenn es nicht wichtig, das der

Alarm nach eine exakten Zeit ausgelöst wird

Programmieren für mobile Endgeräte 15

public class MyActivity extends Acitivty { … @Override public void onCreate() { … // einfach alarmManager.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime(), scanIntent); alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime(), 5000, pending); // oder: alarmManager.setInexactRepeating( AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime(), AlarmManager.INTERVAL_FIFTEEN_MINUTES, pending ); }

Page 16: Programmieren für mobile Endgeräte€¦ · Dozenten: Patrick Förster, Michael Hasseler Programmieren für mobile Endgeräte SS 2013/2014

Dozenten: Patrick Förster, Michael Hasseler

Services (Alarm)

• Der Alarm löst einen Broadcast aus

• Eigenen BroadcastReceiver anmelden

• Der Receiver wiederum startet den Service:

Programmieren für mobile Endgeräte 16

public class MyReceiver extends BroadcastReceiver { public static final String ACTION_SCAN = "de.wwu.ziv.aufgabenapp.ACTION_SCAN"; @Override public void onReceive(Context context, Intent intent) { Intent scanIntent = new Intent(context, AufgabenScanner.class); context.startService(scanIntent); } }

public class MyActivity extends Acitivty { @Override protected void onResume() { super.onResume(); receiver.setListener(this); registerReceiver(receiver, new IntentFilter(MyReceiver .ACTION_SCAN)); } }