Asynctask

advertisement
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
Download