Presentation is loading. Please wait.

Presentation is loading. Please wait.

CIS 493/EEC 492 Android Sensor Programming

Similar presentations


Presentation on theme: "CIS 493/EEC 492 Android Sensor Programming"— Presentation transcript:

1 CIS 493/EEC 492 Android Sensor Programming
Lecture 5 Wenbing Zhao Department of Electrical Engineering and Computer Science Cleveland State University 4/22/2019 CIS 470: Mobile App Development

2 CIS 470: Mobile App Development
Outline Services Networking 4/22/2019 CIS 470: Mobile App Development

3 CIS 470: Mobile App Development
Services How to create a service that runs in the background How to perform long-running tasks in a separate thread How to perform repeated tasks in a service How an activity and a service communicate 4/22/2019 CIS 470: Mobile App Development

4 CIS 470: Mobile App Development
What is a Service A facility for the application to tell the system about something it wants to be doing in the background Even when the user is not directly interacting with the application This corresponds to calls to Context.startService(), which ask the system to schedule work for the service, to be run until the service or someone else explicitly stop it A facility for an application to expose some of its functionality to other applications This corresponds to calls to Context.bindService(), which allows a long-standing connection to be made to the service in order to interact with it 4/22/2019 CIS 470: Mobile App Development

5 CIS 470: Mobile App Development
What is a Service A Service is not a separate process. The Service object itself does not imply it is running in its own process; unless otherwise specified, it runs in the same process as the application it is part of A Service is not a thread. It is not a means itself to do work off of the main thread 4/22/2019 CIS 470: Mobile App Development

6 CIS 470: Mobile App Development
Service Lifecycle If someone calls Context.startService() then the system will retrieve the service and then call its onStartCommand(Intent, int, int) method with the arguments supplied by the client The service will at this point continue running until Context.stopService() or stopSelf() is called There are two major modes of operation depending on the value they return from onStartCommand(): START_STICKY is used for services that are explicitly started and stopped as needed START_NOT_STICKY or START_REDELIVER_INTENT are used for services that should only remain running while processing any commands sent to them 4/22/2019 CIS 470: Mobile App Development

7 CIS 470: Mobile App Development
Service Lifecycle Clients can also use Context.bindService() to obtain a persistent connection to a service This creates the service but does not call onStartCommand() The client will receive the IBinder object that the service returns from its onBind(Intent) method, allowing the client to then make calls back to the service The service will remain running as long as the connection is established (whether or not the client retains a reference on the service's IBinder) Usually the IBinder returned is for a complex interface 4/22/2019 CIS 470: Mobile App Development

8 CIS 470: Mobile App Development
Service Permission Global access to a service can be enforced when it is declared in its manifest's <service> tag By doing so, other applications will need to declare a corresponding <uses-permission> element in their own manifest to be able to start, stop, or bind to the service 4/22/2019 CIS 470: Mobile App Development

9 CIS 470: Mobile App Development
Basic Service Basic steps of creating/using a service: Create a separate service java class Add service in the manifest Start/stop the service from the main activity Create a new project and name it Services Modify manifest: <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android= package="com.wenbing.services"> <application android:allowBackup="true" android:supportsRtl="true" <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".MyService" /> </application> </manifest> 4/22/2019 CIS 470: Mobile App Development

10 CIS 470: Mobile App Development
import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.widget.Toast; import java.net.MalformedURLException; import java.net.URL; import android.os.AsyncTask; import android.util.Log; import java.util.Timer; import java.util.TimerTask; Basic Service Add a new Java class: MyService public class MyService extends Service { int counter = 0; static final int UPDATE_INTERVAL = 1000; private Timer timer = new Timer(); @Override public IBinder onBind(Intent arg0) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show(); doSomethingRepeatedly(); try { new DoBackgroundTask().execute( new URL(" new URL(" new URL(" new URL(" } catch (MalformedURLException e) { e.printStackTrace(); } return START_STICKY; } Perform task asynchronously: don’t wait for completion 4/22/2019 CIS 470: Mobile App Development

11 CIS 470: Mobile App Development
@Override public void onDestroy() { super.onDestroy(); if (timer != null){ timer.cancel(); } Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show(); } private void doSomethingRepeatedly() { timer.scheduleAtFixedRate(new TimerTask() { public void run() { Log.d("MyService", String.valueOf(++counter)); } }, 0, UPDATE_INTERVAL); } private class DoBackgroundTask extends AsyncTask<URL, Integer, Long> { protected Long doInBackground(URL... urls) { int count = urls.length; long totalBytesDownloaded = 0; for (int i = 0; i < count; i++) { totalBytesDownloaded += DownloadFile(urls[i]); publishProgress((int) (((i + 1) / (float) count) * 100)); } return totalBytesDownloaded; } Calculate percentage downloaded and report its progress 4/22/2019 CIS 470: Mobile App Development

12 CIS 470: Mobile App Development
onProgressUpdate is invoked when you call publishProgress() protected void onProgressUpdate(Integer... progress) { Log.d("Downloading files", String.valueOf(progress[0]) + "% downloaded"); Toast.makeText(getBaseContext(), String.valueOf(progress[0]) + "% downloaded-"+counter, Toast.LENGTH_LONG).show(); } protected void onPostExecute(Long result) { Toast.makeText(getBaseContext(), "Downloaded " + result + " bytes", Toast.LENGTH_LONG).show(); //stopSelf(); } } private int DownloadFile(URL url) { try { //---simulate taking some time to download a file Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } //---return an arbitrary number representing // the size of the file downloaded return 100; } } The onPostExecute() is invoked in the UI thread and is called when the doInBackground() method has finished execution Call stopSelf() if you want to destroy the service as soon as the long-running task is done 4/22/2019 CIS 470: Mobile App Development

13 CIS 470: Mobile App Development
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android=" xmlns:app=" xmlns:tools=" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.....services.MainActivity"> <Button android:text="Start Service" android:layout_width="90dp" android:layout_height="50dp" android:layout_marginTop="16dp" android:layout_marginBottom="8dp" android:onClick="startService" /> <Button android:text="Stop Service" android:layout_width="88dp" android:layout_height="48dp" android:layout_marginStart="16dp" android:layout_marginEnd="16dp" android:onClick="stopService" /> </android.support.constraint.ConstraintLayout> Basic Service Modify layout: add two buttons to start/stop service 4/22/2019 CIS 470: Mobile App Development

14 CIS 470: Mobile App Development
Basic Service Modify MainActivity.java: start/stop service import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.content.Intent; import android.view.View; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void startService(View view) { startService(new Intent(getBaseContext(), MyService.class)); } public void stopService(View view) { stopService(new Intent(getBaseContext(), MyService.class)); } } 4/22/2019 CIS 470: Mobile App Development

15 Communication between Service and Activity
Create another app and name it MyService2 Add a Java class MyIntentService Add the service in manifest <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android=" package="com.....myservices2"> <application android:allowBackup="true" android:supportsRtl="true" <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".MyIntentService" /> </application> </manifest> 4/22/2019 CIS 470: Mobile App Development

16 Communication between Service and Activity
import android.app.IntentService; import android.content.Intent; import android.util.Log; import java.net.MalformedURLException; import java.net.URL; public class MyIntentService extends IntentService { public MyIntentService() { super("MyIntentServiceName"); } @Override protected void onHandleIntent(Intent intent) { try { int result = DownloadFile(new URL(" Log.d("IntentService", "Downloaded " + result + " bytes"); Intent broadcastIntent = new Intent(); broadcastIntent.setAction("FILE_DOWNLOADED_ACTION"); getBaseContext().sendBroadcast(broadcastIntent); } catch (MalformedURLException e) { e.printStackTrace(); } } private int DownloadFile(URL url) { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } return 100; } } Populate MyIntentService.java //---send a broadcast to inform the activity // that the file has been downloaded--- 4/22/2019 CIS 470: Mobile App Development

17 Communication between Service and Activity
import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.view.View; import android.widget.Toast; public class MainActivity extends AppCompatActivity { IntentFilter intentFilter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public void onResume() { super.onResume(); intentFilter = new IntentFilter(); intentFilter.addAction("FILE_DOWNLOADED_ACTION"); //---register the receiver registerReceiver(intentReceiver, intentFilter); } @Override public void onPause() { super.onPause(); //---unregister the receiver unregisterReceiver(intentReceiver); } Modify MainActivity.java intent to filter for file downloaded intent 4/22/2019 CIS 470: Mobile App Development

18 Communication between Service and Activity
Modify MainActivity.java Modify the layout to add two buttons as before public void startService(View view) { startService(new Intent(getBaseContext(), MyIntentService.class)); } public void stopService(View view) { stopService(new Intent(getBaseContext(), MyIntentService.class)); } private BroadcastReceiver intentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(getBaseContext(), "File downloaded!", Toast.LENGTH_LONG).show(); } }; } 4/22/2019 CIS 470: Mobile App Development

19 CIS 470: Mobile App Development
Homework#14 Modify the ServiceBindingTest app: Use a ProgressBar view instead/in addition to the Toast to display the progress made by the service 4/22/2019 CIS 470: Mobile App Development

20 CIS 470: Mobile App Development
Networking How to connect to the web using HTTP How to consume XML web services How to consume JSON web services 4/22/2019 CIS 470: Mobile App Development

21 Fetch Web Content using HTTP
Create a new app as usual and name it Networking Add the INTERNET permission in manifest Add an ImageView in activity_main.xml <uses-permission android:name="android.permission.INTERNET"/> <android.support.constraint.ConstraintLayout xmlns:android=" xmlns:app=" xmlns:tools=" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.wenbing.networking.MainActivity"> <ImageView android:layout_width="209dp" android:layout_height="272dp" /> </android.support.constraint.ConstraintLayout> 4/22/2019 CIS 470: Mobile App Development

22 Fetch Web Content using HTTP
import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import android.Manifest; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.AsyncTask; import android.widget.ImageView; import android.widget.Toast; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import java.io.InputStreamReader; Modify MainActivity.java. We will first fetch an image, then the text/html public class MainActivity extends AppCompatActivity { ImageView img; final private int REQUEST_INTERNET = 123; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (ContextCompat.checkSelfPermission(this, Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.INTERNET}, REQUEST_INTERNET); } else{ downloadSomething(); } } 4/22/2019 CIS 470: Mobile App Development

23 Fetch Web Content using HTTP
private void downloadSomething() { String texturl = " String imgurl = " new DownloadImageTask().execute(imgurl); new DownloadTextTask().execute(texturl); } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { switch (requestCode) { case REQUEST_INTERNET: if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { downloadSomething(); } else { Toast.makeText(MainActivity.this, "Permission Denied", Toast.LENGTH_SHORT).show(); } break; default: super.onRequestPermissionsResult(requestCode, permissions, grantResults); } } 4/22/2019 CIS 470: Mobile App Development

24 CIS 470: Mobile App Development
private InputStream OpenHttpConnection(String urlString) throws IOException { InputStream in = null; int response = -1; URL url = new URL(urlString); URLConnection conn = url.openConnection(); if (!(conn instanceof HttpURLConnection)) throw new IOException("Not an HTTP connection"); try{ HttpURLConnection httpConn = (HttpURLConnection) conn; httpConn.setAllowUserInteraction(false); httpConn.setInstanceFollowRedirects(true); httpConn.setRequestMethod("GET"); httpConn.connect(); response = httpConn.getResponseCode(); if (response == HttpURLConnection.HTTP_OK) { in = httpConn.getInputStream(); } } catch (Exception ex) { Log.d("Networking", ex.getLocalizedMessage()); throw new IOException("Error connecting"); } return in; } private InputStream download(String URL) { InputStream in = null; try { in = OpenHttpConnection(URL); return in; } catch (IOException e1) { Log.d("NetworkingActivity", e1.getLocalizedMessage()); } return null; } 4/22/2019 CIS 470: Mobile App Development

25 CIS 470: Mobile App Development
private Bitmap DownloadImage(String URL) { Bitmap bitmap = null; InputStream in = download(URL); if(in != null) { bitmap = BitmapFactory.decodeStream(in); try { in.close(); } catch (IOException e1) { Log.d("NetworkingActivity", e1.getLocalizedMessage()); } } return bitmap; } private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> { protected Bitmap doInBackground(String... urls) { return DownloadImage(urls[0]); } protected void onPostExecute(Bitmap result) { ImageView img = (ImageView) findViewById(R.id.imageView); img.setImageBitmap(result); } } The three periods after the final parameter's type indicate that the final argument may be passed as an array or as a sequence of arguments. Varargs can be used only in the final argument position 4/22/2019 CIS 470: Mobile App Development

26 CIS 470: Mobile App Development
private String DownloadText(String URL) { int BUFFER_SIZE = 2000; InputStream in = download(URL); InputStreamReader isr = new InputStreamReader(in); int charRead; String str = ""; char[] inputBuffer = new char[BUFFER_SIZE]; try { while ((charRead = isr.read(inputBuffer))>0) { String readString = String.copyValueOf(inputBuffer, 0, charRead); str += readString; inputBuffer = new char[BUFFER_SIZE]; } in.close(); } catch (IOException e) { Log.d("Networking", e.getLocalizedMessage()); return ""; } return str; } private class DownloadTextTask extends AsyncTask<String, Void, String> { protected String doInBackground(String... urls) { return DownloadText(urls[0]); } @Override protected void onPostExecute(String result) { Toast.makeText(getBaseContext(), result, Toast.LENGTH_LONG).show(); } } } 4/22/2019 CIS 470: Mobile App Development

27 Fetch Web Content using HTTP
4/22/2019 CIS 470: Mobile App Development

28 Accessing Web Services
import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import android.util.Log; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import android.Manifest; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.AsyncTask; import android.widget.ImageView; import android.widget.Toast; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; Create another app and name it WebService Add INTERNET permission in manifest Modify MainActivity.java 4/22/2019 CIS 470: Mobile App Development

29 Accessing Web Services
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (ContextCompat.checkSelfPermission(this, Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.INTERNET}, REQUEST_INTERNET); } else { new AccessWebServiceTask().execute("apple"); } } 4/22/2019 CIS 470: Mobile App Development

30 Accessing Web Services
ImageView img; final private int REQUEST_INTERNET = 123; private InputStream OpenHttpConnection(String urlString) throws IOException { InputStream in = null; int response = -1; URL url = new URL(urlString); URLConnection conn = url.openConnection(); if (!(conn instanceof HttpURLConnection)) throw new IOException("Not an HTTP connection"); try { HttpURLConnection httpConn = (HttpURLConnection) conn; httpConn.setAllowUserInteraction(false); httpConn.setInstanceFollowRedirects(true); httpConn.setRequestMethod("GET"); httpConn.connect(); response = httpConn.getResponseCode(); if (response == HttpURLConnection.HTTP_OK) { in = httpConn.getInputStream(); } } catch (Exception ex) { Log.d("Networking", ex.getLocalizedMessage()); throw new IOException("Error connecting"); } return in; } 4/22/2019 CIS 470: Mobile App Development

31 CIS 470: Mobile App Development
private String WordDefinition(String word) { InputStream in = null; String strDefinition = ""; try { in = OpenHttpConnection( " + "/DictService/DictService.asmx/Define?word=" + word); Document doc = null; DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db; try { db = dbf.newDocumentBuilder(); doc = db.parse(in); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } doc.getDocumentElement().normalize(); NodeList definitionElements = doc.getElementsByTagName("Definition"); for (int i = 0; i < definitionElements.getLength(); i++) { Node itemNode = definitionElements.item(i); if (itemNode.getNodeType() == Node.ELEMENT_NODE) { Element definitionElement = (Element) itemNode; NodeList wordDefinitionElements = (definitionElement).getElementsByTagName("WordDefinition"); strDefinition = ""; for (int j = 0; j < wordDefinitionElements.getLength(); j++) { Node n = wordDefinitionElements.item(j); if (n.getNodeType() == Node.ELEMENT_NODE) { Element wordDefinitionElement = (Element) n; NodeList textNodes = ((Node) wordDefinitionElement).getChildNodes(); strDefinition += ((Node) textNodes.item(0)).getNodeValue() + ". \n"; } } } } } catch (IOException e1) { Log.d("NetworkingActivity", e1.getLocalizedMessage()); } return strDefinition; } 4/22/2019 CIS 470: Mobile App Development

32 CIS 470: Mobile App Development
private class AccessWebServiceTask extends AsyncTask<String, Void, String> { protected String doInBackground(String... urls) { return WordDefinition(urls[0]); } protected void onPostExecute(String result) { Toast.makeText(getBaseContext(), result, Toast.LENGTH_LONG).show(); } } } 4/22/2019 CIS 470: Mobile App Development

33 Consuming JSON Services
[ { "appeId":"1", "survId":"1", "location":"", "surveyDate":" ", "surveyTime":"12:19:47", "inputUserId":"1", "inputTime":" :21:51", "modifyTime":" :00:00” }, "appeId":"2", "survId":"32", "surveyDate":" ", "surveyTime":"22:43:09", "inputUserId":"32", "inputTime":" :43:37", "modifyTime":" :00:00" } ] XML is expensive both for decoding and transmission JSON is a concise representation of XML document Create another app and name it JSON Add INTERNET permission in manifest 4/22/2019 CIS 470: Mobile App Development

34 Consuming JSON Services
import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.os.AsyncTask; import android.util.Log; import android.widget.Toast; import org.json.JSONArray; import org.json.JSONObject; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new ReadJSONFeedTask().execute( " } Modify MainActivity.java 4/22/2019 CIS 470: Mobile App Development

35 Consuming JSON Services
public String readJSONFeed(String address) { URL url = null; try { url = new URL(address); } catch (MalformedURLException e) { e.printStackTrace(); }; StringBuilder stringBuilder = new StringBuilder(); HttpURLConnection urlConnection = null; try { urlConnection = (HttpURLConnection) url.openConnection(); } catch (IOException e) { e.printStackTrace(); } try { InputStream content = new BufferedInputStream( urlConnection.getInputStream()); BufferedReader reader = new BufferedReader( new InputStreamReader(content)); String line; while ((line = reader.readLine()) != null) { stringBuilder.append(line); } } catch (IOException e) { e.printStackTrace(); } finally { urlConnection.disconnect(); } return stringBuilder.toString(); } Modify MainActivity.java 4/22/2019 CIS 470: Mobile App Development

36 Consuming JSON Services
private class ReadJSONFeedTask extends AsyncTask<String, Void, String> { protected String doInBackground(String... urls) { return readJSONFeed(urls[0]); } protected void onPostExecute(String result) { try { JSONArray jsonArray = new JSONArray(result); Log.i("JSON", "Number of surveys in feed: " jsonArray.length()); for (int i = 0; i < jsonArray.length(); i++) { JSONObject jsonObject = jsonArray.getJSONObject(i); Toast.makeText(getBaseContext(), jsonObject.getString("appeId") " - " + jsonObject.getString("inputTime"), Toast.LENGTH_SHORT).show(); } } catch (Exception e) { e.printStackTrace(); } } } } Modify MainActivity.java 4/22/2019 CIS 470: Mobile App Development

37 CIS 470: Mobile App Development
Homework# 15 Modify the Networking app: Load a webpage that has at least two images Analyze the html page received, identify the image urls by parsing the <img> component, and fetch every image referenced by the page Store the fetched images in a Bitmap array Display the thumbnail images in a GridView On touching each thumbnail in the GridView, display the full image 4/22/2019 CIS 470: Mobile App Development


Download ppt "CIS 493/EEC 492 Android Sensor Programming"

Similar presentations


Ads by Google