cosc 4730 Brief return Sockets And HttpClient (and with AsyncTask) DownloadManager Android • Networking is based on standard Java SE methods – And get the BufferedReader/PrintWriter – Most Java SE network code works with almost no modifications. typical Android network code. try { InetAddress serverAddr = InetAddress.getByName(host); //make the connection Socket socket = new Socket(serverAddr, port); String message = "Hello from Client android emulator"; try { //receive a message PrintWriter out = new PrintWriter( new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())), true); out.println(message); //send a message now BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); String str = in.readLine(); } catch(Exception e) { //error! } finally { socket.close(); in.close(); out.close(); } } catch (Exception e) { //unable to connect } Android Client Code • Making a connection, the code is pretty straight forward String hostname = “localhost”; // remote machine Int port = 3012; //remote port number //make the connection InetAddress serverAddr = InetAddress.getByName(hostname); Socket socket = new Socket(serverAddr, port); //now we have a connection to the server Android Server Code • Again pretty straight forward Int port = 3012; //this is the local port number //create the server socket ServerSocket serverSocket = new ServerSocket(port); //wait for a client to connect Socket socket = serverSocket.accept(); //now we have a connection to the client. Reading and writing. • This works for both client and server. • Once we have the socket connection, we need to get the read and write part of the socket. //Write side PrintWriter out = new PrintWriter( new BufferedWriter( new OutputStreamWriter( socket.getOutputStream())),true); – Note the true, turns on autoflush. //Read side. BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter • Networking is normally a text based protocol. – So while there are many function to send int, long, etc. I’m ignoring them. – out.print(String) and out.println(String) • They both do the same thing, send a line of text. println will add an end of line marker. • This is important for the read side. BufferedReader • The read method reads a single character and returns it as a int. – Second version uses a length and char[]. • readLine() returns line of text as a string. It stops at the end of line marker. – Back to the print and println methods for the writer. • There is a ready() methods that return true or false. True if there is a data to be read, false other. Using the read() and ready() allows to prevent blocking reads. – Example: if (in.read()) { read() } else { do something else} Lastly. • Don’t forget to close everything when you are done with the network. in.close(); out.close(); socket.close(); Android example code • There is a TCPclient and TCPServ examples for the android – For the sever code you will need to tell the emulator to accept the port number – In android-sdk-windows\tools directory, run the following dos command • adb forward tcp:3012 tcp:3012 – assuming you are using port 3012 Android notes • You will need to put – <uses-permission android:name= "android.permission.INTERNET" /> – In the AndroidManifest.xml file • At this point you should be able to use it in both the simulator and on the phone. Last Note. • You must connect your phone to UW’s UWyo wireless network to talk to a local cosc machine. – See http://www.uwyo.edu/askit/displaydoc.asp?askit docid=1769&parentid=1 for help. AndroidManifest.xml <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.cosc4730.TCPclient" android:versionCode="1" android:versionName="1.0"> <uses-permission android:name="android.permission.INTERNET" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".TCPclient" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-sdk android:minSdkVersion="10" android:targetSdkVersion="20"/> </manifest> Networking • Android networking is built on standard Java SE – So use the same network code you learned earlier. – See the source code example, Android TCPclient and TCPserv for examples that run on the Android platform. simulator • For server code, you need to tell the simulator to accept the port number • In android-sdk-windows\tools directory, run the following dos command – adb forward tcp:3012 tcp:3012 • assuming you are using port 3012 References • Android dev site of course – http://developer.android.com/intl/zhCN/reference/android/net/packagesummary.html • Socket programming tutorial. http://www.anddev.org/socket_programmingt325-s30.html Main thread and network. • Networking can take some time and should not be done on the main thread – Ie it can lock up the drawing. • As of v11 (honeycomb) – It will force close if you attempt networking on the main thread. • It must be done in a thread – Or a AsyncTask HTTPCLIENT HttpClient • This is a modified version of Apache’s HttpClient – http://hc.apache.org/httpclient-3.x/ – Used a lot with the J2EE space Use • Create an HttpClient • Instantiate a new HTTP method – PostMethod or GetMethod • Set HTTP parameter names/values • Execute the HTTP call using the HttpClient • Process the HTTP response. Example get HttpClient client = new DefaultHttpClient(); HttpGet request = new HttpGet(); request.setURI(new URI("http://www.uwyo.edu/")); HttpResponse response = client.execute(request); • To add parameters to a get HttpGet method = new HttpGet( "http://www.com/do.php?key=valueGoesHere"); HttpResponse response = client.execute(method); Example Post • HttpClient client = new DefaultHttpClient(); • HttpPost request = new HttpPost("http://somewebsite/do.php"); • List<NameValuePair> postParameters = new ArrayList<NameValuePair>(); • postParameters.add(new BasicNameValuePair("one", "valueGoesHere")); • UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(postParameters); • request.setEntity(formEntity); • HttpResponse response = client.execute(request); A second look. ASYNCTASK AsyncTask • Networking can’t be used on the main thread, so an AsyncTask can be ideal for short networking tasks, say file downloads or other things. – otherwise you should use threads and handlers. AsyncTask download Example private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> { protected Long doInBackground(URL... urls) { int count = urls.length; long totalSize = 0; URL is pamaters to for (int i = 0; i < count; i++) { doInBackground totalSize += Downloader.downloadFile(urls[i]); publishProgress((int) ((i / (float) count) * 100)); // Escape early if cancel() is called Integer is the value for if (isCancelled()) break; } publishProgress and return totalSize; onProgressUpdate } //background thread protected void onProgressUpdate(Integer... progress) { setProgressPercent(progress[0]); } //UI thread protected void onPostExecute(Long result) { showDialog("Downloaded " + result + " bytes"); } //UI thread } • Once created, a task is executed very simply: new DownloadFilesTask().execute(url1, url2, url3); And Long is the return value and parameter to onPostExecute The call, uses URL to create the “list” used in doInBackground Rest of the examples • See the GitHub page pages for the rest of the source code for the examples. • HttpClientDemo uses threads • HttpClientDemo2 uses AsyncTask DOWNLOADMANGER (API 9+) DownloadManager • The download manager is a system service that handles long-running HTTP downloads. – Clients may request that a URI be downloaded to a particular destination file. • The download manager will conduct the download in the background, taking care of HTTP interactions and retrying downloads after failures or across connectivity changes and system reboots. • Note that the application must have the INTERNET permission to use this class. How it works • Get the service via getSystemService DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE); • Make a request via the request methods DownloadManager.Request request = new DownloadManager.Request(URI) long download_id = downloadManager.enqueue(request); • Setup a broadcastReciever to receive an broadcast when it’s done. – The downloadmanager uses the download_id number, so you need to store it for use in the receiver. • The intent will contain the id number for the file downloaded, so you know which one (when downloading more then one at a time.) DownloadManager.Request(URI) • Request has a lot of parameters you can set – .setAllowedNetworkTypes( DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE) • All networks by default – setDescription( String) – setTitle (CharSequence title) • Sets the title and description for the notification line if enabled – setShowRunningNotification (boolean) • Show notification, true. Deprecated for api 11+ • setNotificationVisibility (int visibility) – VISIBILITY_HIDDEN, VISIBILITY_VISIBLE, VISIBILITY_VISIBLE_NOTIFY_COMPLETED. – If hidden, this requires the permission android.permission.DOWNLOAD_WITHOUT_NOTIFICATION. A note, setShowRunningNotification(false) didn’t work on 4.1.x DownloadManager.Request(URI) (2) • setDestinationInExternalFilesDir (String dirType, String subPath) – dirType is the directory type to pass to getExternalStoragePublicDirectory(String) – subPath is the path within the external directory, including the destination filename – Example: – .setDestinationInExternalPublicDir(Environment.DIRECTOR Y_DOWNLOADS, "nasapic.jpg"); • allowScanningByMediaScanner () – If setting above, add this so the media scanner is called as well. Receiver • Set to receive DownloadManager.ACTION_DOWNLOAD_COMPLETE • Since we don’t allows want to get download notifications, we set this on up dyanamically in onResume/OnPause IntentFilter intentFilter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE); registerReceiver(downloadReceiver, intentFilter); • Where downloadReceiver is our method unregisterReceiver(downloadReceiver); DownloaderManager.Query • In the receiver, we deal with the query methods to find out the status of the download – Successful or failure – Based on the download_id (which we can get from the intent or keep from the enqueue method) – We filter and get a Cursor with the information DownloaderManager.Query (2) DownloadManager.Query query = new DownloadManager.Query(); query.setFilterById(intentdownloadId); Cursor cursor = downloadManager.query(query); • The example code shows you how to get the columns and information out of the cursor, including a file, so you can read the downloaded file. Example code • DownloadDemo – MainActivity has two buttons. One downloads and shows the notification, the second doesn’t – MainActivityORG stores the download_id in preferences, instead of a variable. References (downloadManager) • http://developer.android.com/reference/andr oid/app/DownloadManager.html • http://stackoverflow.com/questions/7239996/ android-downloadmanager-api-opening-fileafter-download • http://blog.vogella.com/2011/06/14/androiddownloadmanager-example/ Q&A